SharedCourses/docs/undergraduate/软件工程学院/面向对象程序设计实践(基于C++)/2025-2026-1_历次作业_鲍钰.mdx

1535 lines
37 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: oopcpp实践2025-2026-1全作业
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
## 作业
### 1. ClassDraw
#### 题目
![作业1](./images/25-26-1-hw1.png)
#### 参考答案
<Tabs>
<TabItem value="Draw.h" label="Draw.h">
```cpp title="Draw.h"
#pragma once
/*
* @Description: 绘制类
*/
class Draw
{
public:
Draw(char what, int down, int across);
void DrawWall();
void DrawBox();
void DrawTriangle();
private:
char what;
int down;
int across;
};
```
</TabItem>
<TabItem value="Draw.cpp" label="Draw.cpp">
```cpp title="Draw.cpp"
#include "Draw.h"
#include <iostream>
#include <cassert>
/*
* @Description: 绘制类的构造函数
* @param {char} what 绘制的字符
* @param {int} down 绘制的行数
* @param {int} across 绘制的列数
*/
Draw::Draw(char what, int down, int across) {
assert(down >= 0 && across >= 0 && "down or across should >= 0 !"); // 断言,确保 down 和 across 大于等于 0
this->what = what;
this->down = down;
this->across = across;
}
/*
* @Description: 绘制墙
*/
void Draw::DrawWall() {
for (int i = 0; i < this->down; i++) {
for (int j = 0; j < this->across; j++) {
std::cout << this->what;
}
std::cout << std::endl;
}
}
/*
* @Description: 绘制盒子
*/
void Draw::DrawBox() {
for (int i = 0; i < this->down; i++) {
for (int j = 0; j < this->across; j++) {
if (i != 0 && i != down - 1 && j != 0 && j != across - 1) {
std::cout << " ";
}
else {
std::cout << this->what;
}
}
std::cout << std::endl;
}
}
/*
* @Description: 绘制三角形
*/
void Draw::DrawTriangle() {
int h = down > across ? down : across;
for (int i = 0; i < h; i++) {
for (int j = 0; j < i+1; j++) {
std::cout << this->what;
}
std::cout << std::endl;
}
}
```
</TabItem>
<TabItem value="main.cpp" label="main.cpp">
```cpp title="main.cpp"
// file encode: UTF-8
#include "Draw.h"
#include <iostream>
#include <set>
const std::set<int> TYPES = { -1,1,2,3 }; // 合法的绘制类型
/*
* @Description: 主函数
*/
int main()
{
char what = ' ';
int across = 0, down = 0, type = 0;
while (true) {
std::cout << "Please input the shape you want to draw: 1-wall, 2-box, 3-triangle, -1 for end" << std::endl;
std::cin >> type;
if (TYPES.count(type)) {
if (type == -1) {
return 0;
}
else {
std::cout << "input the letter to fill the shape" << std::endl;
std::cin >> what;
std::cout << "height" << std::endl;
std::cin >> down;
std::cout << "width" << std::endl;
std::cin >> across;
if (down < 0 || across < 0) {
std::cout << "height and width should bigger than 0" << std::endl;
continue;
}
Draw draw(what, down, across);
switch (type) {
case 1:
draw.DrawWall();
break;
case 2:
draw.DrawBox();
break;
case 3:
draw.DrawTriangle();
break;
}
}
}
else {
std::cout << "illegal input, please input again!" << std::endl;
}
}
return 0;
}
```
</TabItem>
</Tabs>
### 2. ClassDecrypt
#### 题目
![作业2-1](./images/25-26-1-hw2-1.png)
![作业2-2](./images/25-26-1-hw2-2.png)
#### 参考答案
```cpp title="main.cpp"
#include<iostream>
#include<string>
class Decrypt {
std::string s;
int key;
public:
Decrypt();
Decrypt(std::string s,int key);
int GetKey();
void PrintKey();
void GetString();
void Print();
void PrintAnswer();
};
Decrypt::Decrypt() { // 默认初始化
this->s="hello,world!";
this->key=1;
}
Decrypt::Decrypt(std::string s,int key) { // 按照给定的s与key初始化
this->s=s;
this->key=key;
}
int Decrypt::GetKey() { // 获取key值
std::cout << "请输入key值整数【110】之间\n";
std::string num; // 采用string读入提高代码健壮性
getline(std::cin,num); // 使用getline避免本行输入中出现空格污染后续输入
if(num == "10") { // 特殊判断输入为10的情况
this -> key = 10;
return this -> key;
}
else if(num.size() == 1 && num[0]>='1' && num[0] <= '9') { // 如果输入合法改变key值
this->key = num[0] - '0';
return this->key;
}
else { // 输入非法,输出提示
std::cout << "输入的数值不对key没有改变。\n";
return 0;
}
}
void Decrypt::PrintKey() { // 输出当前key值
std::cout << "key值是" << this -> key << '\n';
if(this -> key == 10) { // 如果key在上一步被更改为10终止程序
exit(0);
}
return;
}
void Decrypt::GetString() { // 获取明文字符串
std::cout << "请输入明文字符串:\n";
std::string str;
getline(std::cin,str); // 采用getline防止无法读入明文字符串中潜在的空格
this->s=str;
return ;
}
void Decrypt::Print() { // 输出明文字符串
std::cout << "明文字符串是:";
std::cout << this->s << '\n';
return ;
}
void Decrypt::PrintAnswer() { // 加密字符串
for(int i = 0; i < this->s.size(); i++) { // 加密并修改字符串
if(this->s[i] >= 'a' && this->s[i] <= 'z') {
this->s[i] -= key;
}
else if(this->s[i] >= 'A' && this->s[i] <= 'Z') {
this->s[i] -= key;
}
}
std::cout << "加密后的密文字符串是:" << this -> s << '\n'; // 在此处输出加密字符串
return ;
}
int main() {
Decrypt test;
while(true) { // 循环在PrintKey()函数中key==10的情况下终止
test.GetKey();
test.PrintKey();
test.GetString();
test.Print();
test.PrintAnswer();
}
return 0;
}
```
> 教师批语:
>
> 程序的退出逻辑被放在了 PrintKey函数中很怪。
> 一个更合理的做法是在 main函数的循环中检查 GetKey的返回值并决定是否退出。
### 3. ClassRandom
#### 题目
![作业3-1](./images/25-26-1-hw3-1.png)
![作业3-2](./images/25-26-1-hw3-2.png)
#### 参考答案
```cpp title="main.cpp"
#include <iostream>
#include <algorithm>
#include <cmath>
#include <time.h>
#include <string>
#include <vector>
class Random
{
public:
int type,left, right, adv; //从左至右分别为 操作类型、最小值、最大值、均值
Random(bool pseudo);
int reseed();
double random_real();
int poisson(double mean);
int input_positive_int();
double input_positive_double();
std::vector<int> rand6();
private:
int seed, multiplier, add_on;
};
Random::Random(bool pseudo) // 构造函数
{
if (pseudo)
seed = 1;
else
seed = time(NULL) % INT_MAX;
multiplier = 2743;
add_on = 5923;
type = 0;
}
int Random::reseed() // 种子生长函数
{
seed = seed * multiplier + add_on;
return seed;
}
double Random::random_real()
{
double max = INT_MAX + 1.0; // INT_MAX = (2)31 -1
double temp = reseed();
if (temp < 0)
temp = temp + max;
return temp / max;
}
int Random::poisson(double mean)
{
double limit = exp(-mean);
double product = random_real();
int count = 0;
while (product > limit)
{
count++;
product *= random_real();
}
return count;
}
int Random::input_positive_int() // 以字符串形式读入一个正整数
{
std::string str;
std::cin >> str;
int res = 0;
for (int i = 0; i < str.size(); i++)
{
if (str[i] >= '0' && str[i] <= '9')
{
res *= 10;
res += str[i] - '0';
}
else
{
return -1;
}
}
if(res <= 0) res = -1;
return res;
}
double Random::input_positive_double() // 以字符串形式读入一个小数
{
std::string str;
std::cin >> str;
double res = 0, now = 1;
bool dot = false;
for (int i = 0; i < str.size(); i++)
{
if (str[i] == '.') // 判断小数点是否出现过
{
if (dot)
{
return -1;
}
else
{
dot = true;
}
}
else if (str[i] >= '0' && str[i] <= '9')
{
if(dot) // 处理小数部分
{
now /= 10;
res += (str[i] - '0') * now;
}
else // 处理整数部分
{
res *= 10;
res += str[i] - '0';
}
}
else
{
return -1;
}
}
if(res <= 0) res = -1;
return res;
}
std::vector<int> Random::rand6() // 生成六个范围内的随机数
{
std::vector<int> res(6);
for (int i = 0; i < 6; i++)
{
res[i] = random_real() * (right - left) + left;
}
return res;
}
int main()
{
Random r(false);
std::cout << "=====================================\n";
std::cout << " 泊松分布随机数生成器应用 \n";
std::cout << "=====================================\n";
while (r.type != 3)
{
std::cout << "\n";
std::cout << "请选择操作:\n";
std::cout << "1. 生成范围内6个随机数\n";
std::cout << "2. 生成均值多个随机数\n";
std::cout << "3. 退出\n";
std::cout << "请输入选项1-3";
r.type = r.input_positive_int();
while (r.type < 1 || r.type > 3) // 确保输入类型符合预期
{ // 我承认这么写看起来很丑
std::cout << "请您输入选项1-3为正整数请重新来\n"; // 但我一时想不到相对更好的写法
r.type = r.input_positive_int();
}
if (r.type == 1) // 生成区间内六个随机数
{
std::cout << "请输入最小值(正整数):";
r.left = r.input_positive_int();
while (r.left < 1)
{
std::cout << "请输入最小值(正整数),为正整数,请重新来!\n";
r.left = r.input_positive_int();
}
std::cout << "请输入最大值(正整数):";
r.right = r.input_positive_int();
while (r.right < 1 || r.right < r.left)
{
if (r.right < 1)
std::cout << "请输入最大值(正整数),为正整数,请重新来!\n";
else if (r.right < r.left)
std::cout << "错误:最小值不能大于最大值!请重新输入最大值(正整数)\n";
r.right = r.input_positive_int();
}
std::vector<int> res = r.rand6();
std::cout << "生成[" << r.left << "" << r.right << "]的6个随机数如下";
for (int i = 0; i < 6; i++)
{
std::cout << res[i] << (i < 5 ? ", " : "\n");
}
}
else if (r.type == 2) // 生成给定均值的泊松分布随机数
{
std::cout << "请输入概率均值(正实数)\n";
r.adv = r.input_positive_double();
while (r.adv <= 0)
{
std::cout << "请您概率均值(正实数),为正实数,请重新来!\n"; // 此处拼写错误系给定示例程序原文,故原文保留
r.adv = r.input_positive_double();
}
int num;
std::cout << "请输入产生随机整数的个数(正整数):\n";
num = r.input_positive_int();
while (num < 1) {
std::cout << "请您请输入产生随机整数的个数(正整数),为正整数,请重新来!\n";
num = r.input_positive_int();
}
long long sum = 0; // 计算随机整数之和
std::cout << "产生随机整数序列:\n";
for(int i = 0; i < num; i++)
{
int res = r.poisson(r.adv);
sum += res;
std::cout << res << ' ';
}
// 示例程序计算均值似乎有误,已修复此问题
std::cout << "\n随机整数序列的平均值是" << (double)sum/num << '\n';
}
}
std::cout << "感谢使用泊松分布随机数生成器应用!\n";
return 0;
}
```
> 教师批语:
>
> rand6 函数中,
> 生成随机数的公式为 random_real() * (right - left) + left
> 这样生成的随机数范围实际上是 [left, right),永远无法生成最大值 right
### 4. ClassTime
#### 题目
![作业4-1](./images/25-26-1-hw4-1.png)
![作业4-2](./images/25-26-1-hw4-2.png)
#### 参考答案
```cpp title="main.cpp"
#include <iostream>
#include <iomanip>
#include <string>
class TimeType
{
public:
void Set(int hours, int minutes, int seconds);
void Increment();
void Write() const;
bool Equal(TimeType otherTime) const;
bool Lessthan(TimeType otherTime) const;
TimeType(int initHrs, int initMins, int initSecs);
TimeType();
bool Overlap();
private:
int hrs;
int mins;
int secs;
};
void TimeType::Set(int hours, int minutes, int seconds) // 将函数参数赋给类中的变量
{
this->hrs = hours;
this->mins = minutes;
this->secs = seconds;
return;
}
void TimeType::Increment() // 让类增加一秒
{
this->secs++;
if (this->secs == 60) // 处理 60 秒 -> 1 分钟进位
{
this->secs = 0;
this->mins++;
}
if (this->mins == 60) // 处理 60 分钟 -> 1 小时进位
{
this->mins = 0;
this->hrs++;
}
if (this->hrs == 24) // 处理 24 小时 -> 1 天进位
{
this->hrs = 0;
}
return;
}
void TimeType::Write() const
{
if (this->hrs == 12 || this->hrs == 0) // 特殊处理 0 点和 12 点
printf("12");
else //输出当前小时
printf("%02d", this->hrs%12);
printf(":%02d:%02d\n", this->mins, this->secs); // 以保留两位有效数字形式输出当前分钟与秒
return;
}
bool TimeType::Equal(TimeType otherTime) const // 当且仅当小时,分钟,秒三个变量均相等的时候返回 True
{
return this->hrs == otherTime.hrs &&
this->mins == otherTime.mins &&
this->secs == otherTime.secs;
}
bool TimeType::Lessthan(TimeType otherTime) const // 将类中时间转换为自00:00:00过去了多少秒然后比较大小只能比较同一天内的时间
{
return (this->hrs * 3600 + this->mins * 60 + this->secs) < (otherTime.hrs * 3600 + otherTime.mins * 60 + otherTime.secs);
}
TimeType::TimeType(int initHrs, int initMins, int initSecs) // 构造函数
{
this->hrs = initHrs;
this->mins = initMins;
this->secs = initSecs;
}
TimeType::TimeType() // 构造函数
{
this->hrs = 0;
this->mins = 0;
this->secs = 0;
}
bool TimeType::Overlap() // 判断三个指针是否重合
{
return this->mins == this->secs && this->mins / 12 + this->hrs % 12 * 5 == this->mins;
}
int main()
{
TimeType beg(9, 23, 23), end(21, 23, 23);
int num = 0;
for (TimeType i = beg; !i.Equal(end); i.Increment()) // 考虑到可能需要更换参数处理跨天的情况,故采用了 !!i.Equal(end) 而非 i.Increment() 作为循环条件
{
if (i.Overlap())
{
std::string s; // 作为吞掉输入的临时变量,无实际意义
num++; // 计算当前是第多少次重合
std::cout << "-------------------------------------\n"; //参考示例程序,输出上分割线
std::cout << "第" << num << "次重合,重合时间:";
i.Write();
std::cout << "-------------------------------------\n";
std::getline(std::cin, s); // 根据实际测试示例程序应该是采用的getchar()但是出于美观性的考虑本处采用了getline()
}
}
return 0;
}
```
### 5. CBrowser
#### 题目
![作业5-1](./images/25-26-1-hw5-1.png)
![作业5-2](./images/25-26-1-hw5-2.png)
#### 参考答案
<Tabs>
<TabItem value="brouser.h" label="brouser.h">
```cpp title="brouser.h"
template <class Node_entry>
struct Node
{
// data members
Node_entry entry;
Node<Node_entry> *next;
Node<Node_entry> *back;
// constructors
Node();
Node(Node_entry item, Node<Node_entry> *link_back = 0, Node<Node_entry> *link_next = 0);
~Node();
};
template <class Node_entry>
class CBrowser
{
private:
// data members
Node<Node_entry> *current; // 当前游标指针
public:
// constructors
bool CanForward(); // 可以继续往前
bool Forward(); // 前进一个节点
bool CanBack(); // 可以继续后退
bool Back(); // 后退一个节点
void NewSite(Node_entry site); // 将新的site插入到current当前位置的后面
Node<Node_entry> *GetCurrent(); // 获得当前游标指针current
CBrowser(); // 缺省构造,空链表
~CBrowser(); // 析构,释放所有节点内存
};
template <class Node_entry>
Node<Node_entry>::Node()
{
this->entry = "";
this->back = nullptr;
this->next = nullptr;
}
template <class Node_entry>
Node<Node_entry>::Node(Node_entry item, Node<Node_entry> *link_back, Node<Node_entry> *link_next)
{
this->entry = item;
this->back = link_back;
this->next = link_next;
}
template <class Node_entry> // 递归删除此节点及其所有后继节点
Node<Node_entry>::~Node()
{
if (this->next != nullptr)
{
delete this->next;
}
}
template <class Node_entry> // 检测当前节点的next指针是否为空以判断是否存在后继节点
bool CBrowser<Node_entry>::CanForward()
{
return (this->current->next != nullptr);
}
template <class Node_entry>
bool CBrowser<Node_entry>::Forward()
{
if (this->CanForward())
{
this->current = this->current->next;
return true;
}
else
{
return false;
}
}
template <class Node_entry> // 采用了含头节点的双向链表
bool CBrowser<Node_entry>::CanBack() // 故检测当前节点的back指针的back指针是否为空检测该节点前驱节点是否为头节点
{ // 等价于检测该节点是否存在前驱节点
return (this->current->back->back != nullptr);
}
template <class Node_entry>
bool CBrowser<Node_entry>::Back()
{
if (this->CanBack())
{
this->current = this->current->back;
return true;
}
else
{
return false;
}
}
template <class Node_entry>
void CBrowser<Node_entry>::NewSite(Node_entry site)
{
delete this->current->next; // 先删除当前节点的所有后继节点
Node<Node_entry> *newSite = new Node<Node_entry>(site, this->current, nullptr);
newSite->entry = site; // 然后使当前节点的后继节点为新节点
this->current->next = newSite; // 设定指针
this->current = newSite; // 将当前节点转移至后继节点
}
template <class Node_entry>
Node<Node_entry> *CBrowser<Node_entry>::GetCurrent()
{
return this->current;
}
template <class Node_entry>
CBrowser<Node_entry>::CBrowser()
{
current = new Node<Node_entry>;
}
template <class Node_entry>
CBrowser<Node_entry>::~CBrowser()
{
delete this->current;
}
```
</TabItem>
<TabItem value="main.cpp" label="main.cpp">
```cpp title="main.cpp"
#include <iostream>
#include <string>
#include "brouser.h"
int main()
{
std::cout << "请输入浏览器命令V(访问新网站)F(前进)B(后退)X(退出)\n";
CBrowser<std::string> log; // 创建浏览器历史记录链表
char command = 0; // 存储当前指令
while (command != 'X')
{
std::string input;
getline(std::cin, input); // 使用getline()读取字符串作为指令
command = input.front(); // 取字符串首字符做指令模糊匹配
if (command >= 'a' && command <= 'z') // 处理大小写敏感
{
command -= 'a';
command += 'A';
}
std::string website;
switch (command)
{
case 'V':
std::cout << "请输入新的网址:";
getline(std::cin, website); // 使用getline()读入新网址
log.NewSite(website);
std::cout << "当前网址是:" << log.GetCurrent()->entry << '\n';
break;
case 'F':
if (log.Forward())
{
std::cout << "当前网址是:" << log.GetCurrent()->entry << '\n';
}
else
{
std::cout << "无法前进!\n";
}
break;
case 'B':
if (log.Back())
{
std::cout << "当前网址是:" << log.GetCurrent()->entry << '\n';
}
else
{
std::cout << "无法后退!\n";
}
break;
case 'X':
break;
default:
std::cout << "请输入合法的浏览器命令V(访问新网站)F(前进)B(后退)X(退出)\n"; // 处理读入非法命令的情况
break;
}
}
return 0;
}
```
</TabItem>
</Tabs>
### 6. CTypes
#### 题目
![作业6-1](./images/25-26-1-hw6-1.png)
![作业6-2](./images/25-26-1-hw6-2.png)
#### 参考答案
```cpp title="main.cpp"
#include <bits/stdc++.h>
using namespace std;
long long input_int(string str) // 以字符串形式读入一个正整数,从之前写的随机数类作业中拿过来的
{
long long res = 0;
long long i = 0;
bool negative = false;
if (str.front() == '-') // 处理负号
{
negative = true;
i++;
}
for (; i < str.size(); i++)
{
if (str[i] >= '0' && str[i] <= '9')
{
res *= 10;
res += str[i] - '0';
}
else //非法值一律返回0在函数内再进行判断
{
return 0;
}
}
return negative ? -res : res;
}
class CTypes
{
public:
CTypes(); // 缺省构造函数所有成员初始化为0
CTypes(int n, unsigned int i, char c, unsigned char u, bool b); // 构造函数,所有成员初始化为形参
void setValue(); // 设置内部成员数据数值
void printValue(); // 输出内部成员数据数值
void printDeep(); // 输出所有内部成员数据底层补码的存放信息
private:
void printBinary(void *var, size_t size); // 打印指针var指向任意变量字节数为size的底层二进制表示
// size_t 是一个无符号整数类型,32位系统unsigned int4字节64位系统unsigned long8字节
// void * 是一种特殊的指针类型,称为 "无类型指针" 或 "泛型指针",在解引用,或者+-操作之前,必须将其转换为具体的指针类型。
// 内部成员:
int n;
unsigned int i;
char c;
unsigned char u;
bool b;
};
CTypes::CTypes() //缺省构造
{
this->n = 0;
this->i = 0;
this->c = '\0';
this->u = '\0';
this->b = false;
}
CTypes::CTypes(int n, unsigned int i, char c, unsigned char u, bool b) //给定值构造
{
this->n = n;
this->i = i;
this->c = c;
this->u = u;
this->b = b;
}
void CTypes::setValue()
{
string str;
long long temp;
cout << "请输入整数n:\n";
while (1)
{
getline(cin, str);
temp = input_int(str);
if (temp == 0 && str != "0") //此处判断返回值为0是读入了非法值还是读入了0
{
cout << "请您输入整数,请重新来!\n";
}
else
{
this->n = temp;
break;
}
}
cout << "请输入非负整数i:\n";
while (1)
{
getline(cin, str);
temp = input_int(str);
if (temp == 0 && str != "0")
{
cout << "请您输入非负整数,请重新来!\n";
}
else if (temp < 0) //返回负数的时候同样作为非法值处理
{
cout << "请您输入非负整数,请重新来!\n";
}
else
{
this->i = temp;
break;
}
}
cout << "请输入字符c:\n"; // 按照样例程序,此处输入字符串时保留第一个字符
getline(cin, str);
this->c = str.front();
cout << "请输入【0,255】闭区间的整数for unsigned char u:\n";
while (1)
{
getline(cin, str);
temp = input_int(str);
if (temp == 0 && str != "0")
{
cout << "请您输入【0,255】闭区间的整数请重新来\n";
}
else if (temp < 0 || temp > 255) //处理返回范围外的非法值
{
cout << "请您输入【0,255】闭区间的整数请重新来\n";
}
else
{
this->u = temp;
break;
}
}
cout << "请输入布尔类型数值b只能为0或1:\n";
while (1) //因为布尔类型情形简单,只需要判断两种情况,便不调用字符串转整数函数了
{
getline(cin, str);
if (str == "0")
{
this->b = false;
break;
}
else if (str == "1")
{
this->b = true;
break;
}
else
{
cout << "请您输入布尔类型数值b只能为0或1请重新来\n";
}
}
return;
}
void CTypes::printValue() //打印变量
{
cout << "内部成员数值为:" << endl;
cout << "整数n数值为" << this -> n << endl;
cout << "无符号整数i数值为" << this -> i << endl;
cout << "字符c数值为" << this -> c << endl;
cout << "无符号字符u数值为" << (int)(this -> u) << endl; //以数值形式打印无符号整数
cout << "布尔类型b数值为" << this -> b << endl;
return;
}
void CTypes::printDeep()
{
cout << "内部成员底层补码0和1信息为" << endl;
cout << "整数" << this->n << "底层补码0和1信息为";
this->printBinary(&(this->n), sizeof(this->n));
cout << endl;
cout << "无符号" << this->i << "底层补码0和1信息为";
this->printBinary(&(this->i), sizeof(this->i));
cout << endl;
cout << "字符" << this->c << "底层补码0和1信息为";
this->printBinary(&(this->c), sizeof(this->c));
cout << endl;
cout << "无符号字符" << (int)(this->u) << "底层补码0和1信息为"; //这里同样以数值形式打印无符号整数
this->printBinary(&(this->u), sizeof(this->u));
cout << endl;
cout << "布尔类型" << this->b << "底层补码0和1信息为";
this->printBinary(&(this->b), sizeof(this->b));
cout << endl;
return;
}
void CTypes::printBinary(void *var, size_t size)
{
unsigned long long now = (1LL << (size*8-1)); // 将 now 设为最高位为 1 其余位为0的形式
unsigned long long value;
switch(size) { // 以对应的无符号类型读取 var 指向的值,便于后续位运算处理
case 1:
value = *((unsigned char*)var);
break;
case 2:
value = *((unsigned short*)var);
break;
case 4:
value = *((unsigned long*)var);
break;
case 8:
value = *((unsigned long long*)var);
break;
default:
value = (1LL << 63);
}
int num = 0;
while(now) {
cout << (bool)(now&value);
num ++;
now >>=1; // 通过 now 每次右移自左向右打印底层存储
if(num == 8) // 字节之间以空格隔开
{
cout << ' ';
num = 0;
}
}
return;
}
int main()
{
CTypes t1;
CTypes t2(-10, 10, 'K', 200, 1);
cout << "注意,整数在底层是按照补码存放,正整数的原码 = 反码 = 补码;" << endl;
cout << "负数的反码是原码符号位不变数值位取反补码是反码加1。" << endl;
cout << "下面是缺省构造成员底层内部信息:" << endl;
t1.printDeep();
cout << "下面是t2(-10,10,'K',200,1)构造后,成员底层内部信息:" << endl;
t2.printDeep();
cout << endl;
label1:
string input = "";
cout << "请选择操作:" << endl;
cout << "1. 设置类所有内部成员数值,并回显" << endl;
cout << "2. 打印类所有成员内部底层0和1表示信息" << endl;
cout << "3. 退出" << endl;
cout << "请输入选项 (1-3):";
while (input != "3")
{
getline(cin, input);
if (input == "1")
{
t1.setValue();
cout << endl;
cout << "信息回显:" << endl;
t1.printValue();
cout << endl;
goto label1; // 使用 goto 来重新打印默认信息
}
else if (input == "2")
{
t1.printDeep();
cout << endl;
goto label1;
}
else if (input == "3")
{
break;
}
else
{
cout << "请您输入选项 (1-3),为正整数,请重新来!" << endl;
}
}
return 0;
}
```
### 期末大作业
#### 题目
Move.h
![作业7-1](./images/25-26-1-hw7-1.png)
MyStack.h
![作业7-2](./images/25-26-1-hw7-2.png)
Board.h
![作业7-3](./images/25-26-1-hw7-3.png)
1. 当输入无效棋谱文件名称时,程序要求人自行和电脑对战,运行效果如下图
![作业7-4](./images/25-26-1-hw7-4.png)
2. 当输入初学者棋谱beginer.txt时运行效果如下图
![作业7-5](./images/25-26-1-hw7-5.png)
![作业7-6](./images/25-26-1-hw7-6.png)
3. 当输入高手棋谱master.txt时运行效果如下图
![作业7-7](./images/25-26-1-hw7-7.png)
![作业7-8](./images/25-26-1-hw7-8.png)
<Tabs>
<TabItem value="beginner.txt" label="beginner.txt">
```text title="beginner.txt"
0 0
0 1
0 2
1 0
1 1
1 2
2 0
2 1
2 2
```
</TabItem>
<TabItem value="master.txt" label="master.txt">
```text title="master.txt"
1 1
2 0
1 2
0 1
```
</TabItem>
</Tabs>
#### 参考答案
<Tabs>
<TabItem value="Move.h" label="Move.h">
```cpp title="Move.h"
class Move
{
public:
Move();
Move(int r, int c);
int row;
int col;
};
Move::Move()
{
row = -1;
col = -1;
}
Move::Move(int r, int c)
{
row = r;
col = c;
}
```
</TabItem>
<TabItem value="MyStack.h" label="MyStack.h">
```cpp title="MyStack.h"
enum Error_code
{
underflow,
overflow,
success
};
const int maxstack = 10;
template <class Stack_entry>
class MyStack
{
public:
MyStack();
bool empty() const;
Error_code pop();
Error_code top(Stack_entry &item) const;
Error_code push(const Stack_entry &item);
private:
int count;
Stack_entry entry[maxstack];
};
template <class Stack_entry>
MyStack<Stack_entry>::MyStack()
{
count = 0;
}
template <class Stack_entry>
bool MyStack<Stack_entry>::empty() const
{
return count <= 0;
}
template <class Stack_entry>
Error_code MyStack<Stack_entry>::pop()
{
if(empty())
{
return underflow;
}
count--;
return success;
}
template <class Stack_entry>
Error_code MyStack<Stack_entry>::top(Stack_entry &item) const
{
if(empty())
{
return underflow;
}
item = entry[count - 1];
return success;
}
template <class Stack_entry>
Error_code MyStack<Stack_entry>::push(const Stack_entry &item)
{
if(count >= maxstack)
{
return overflow;
}
entry[count] = item;
count++;
return success;
}
```
</TabItem>
<TabItem value="Board.h" label="Board.h">
```cpp title="Board.h"
#include <iostream>
#include "Move.h"
#include "MyStack.h"
class Board
{
public:
Board();
bool done() const;
void print() const;
void instructions() const;
bool better(int value, int old_value) const;
bool ValidStep(Move try_it) const;
void play(Move try_it);
int worst_case() const;
int evaluate() const;
int legal_moves(MyStack<Move> &moves) const;
int the_winner() const;
private:
int squares[3][3];
int moves_done;
};
Board::Board()
{
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
squares[i][j] = 0;
moves_done = 0;
}
bool Board::done() const
{
return moves_done == 9 || the_winner() > 0;
}
void Board::print() const
{
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
std::cout << " " << squares[i][j];
}
std::cout << '\n';
}
std::cout << '\n';
}
void Board::instructions() const
{
std::cout << "This is a Tic-Tac-Toe game. Wait for computer going...\n";
}
bool Board::ValidStep(Move try_it) const
{
return (squares[try_it.row][try_it.col] == 0);
}
void Board::play(Move try_it)
{
squares[try_it.row][try_it.col] = moves_done % 2 + 1;
moves_done++;
}
int Board::the_winner() const
{
for (int i = 0; i < 3; i++)
{
if (squares[i][1] != 0 &&
squares[i][1] == squares[i][0] &&
squares[i][1] == squares[i][2])
return squares[i][1];
if (squares[1][i] != 0 &&
squares[1][i] == squares[0][i] &&
squares[1][i] == squares[2][i])
return squares[1][i];
}
if (squares[1][1] != 0)
{
if (squares[1][1] == squares[0][0] &&
squares[1][1] == squares[2][2])
return squares[1][1];
if (squares[1][1] == squares[0][2] &&
squares[1][1] == squares[2][0])
return squares[1][1];
}
return 0;
}
int Board::legal_moves(MyStack<Move> &moves) const
{
int count = 0;
while (!moves.empty())
moves.pop();
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
if (squares[i][j] == 0)
{
moves.push(Move(i, j));
count++;
}
return count;
}
int Board::evaluate() const
{
int winner = the_winner();
if(winner == 1) return 10-moves_done;
else if(winner == 2) return moves_done-10;
else return 0;
}
bool Board::better(int value, int old_value) const
{
if(moves_done%2) return value<old_value;
else return value>old_value;
}
int Board::worst_case() const
{
if(moves_done%2) return 10;
else return -10;
}
```
</TabItem>
<TabItem value="main.cpp" label="main.cpp">
```cpp title="main.cpp"
#include "Board.h"
#include <vector>
#include <utility>
#include <string>
#include <sstream>
#include <fstream>
int look_ahead(const Board &game, int depth, Move &recommended)
{
if (game.done() || depth == 0)
return game.evaluate();
else
{
MyStack<Move> moves;
game.legal_moves(moves);
int value, best_value = game.worst_case();
while (!moves.empty())
{
Move try_it, reply;
moves.top(try_it);
Board new_game = game;
new_game.play(try_it);
value = look_ahead(new_game, depth - 1, reply);
if (game.better(value, best_value))
{
best_value = value;
recommended = try_it;
}
moves.pop();
}
return best_value;
}
}
void play(std::vector<std::pair<int, int>> rem)
{
Board game;
Move recommended;
int x, y;
int i = 9;
int now = 0;
game.instructions();
while (!game.done())
{
look_ahead(game, i, recommended);
game.play(recommended);
std::cout << "Computer:\n";
game.print();
if (game.done())
break;
std::cout << "Your turn:\n";
if (now < rem.size())
{
x = rem[now].first;
y = rem[now].second;
}
else
{
std::cout << "X:";
std::cin >> x;
std::cout << "Y:";
std::cin >> y;
}
Move me(x, y);
game.play(me);
game.print();
i--;
}
if (game.the_winner() == 1)
std::cout << "Game over with computer win.\n";
else if (game.the_winner() == 2)
std::cout << "Game over with you win.\n";
else
std::cout << "Game over with a draw.\n";
}
std::vector<std::pair<int, int>> read(std::string file)
{
freopen(file.c_str(),"r",stdin);
std::string line;
std::vector<std::pair<int, int>> rem;
while(std::getline(std::cin,line))
{
if(line.size()==0) break;
std::istringstream record(line);
int x,y;
record >> x >> y;
rem.push_back({x,y});
}
freopen("CON","r",stdin);
return rem;
}
int main()
{
std::string filename;
std::cout << "Please input the chess file name:\n";
std::cin >> filename;
std::ifstream file(filename);
std::vector<std::pair<int, int>> rem;
if(file.good())
{
rem = read(filename);
}
else
{
std::cout << "** Can't open input file **\n";
std::cout << "Please input by youself.";
}
play(rem);
return 0;
}
```
</TabItem>
</Tabs>