我是一个初级程序员,并在c++中做了一个toe程序。我需要一些帮助,我的记忆管理可以任何人审查和帮助我。这是我的密码
// This is a trial for tic tac toe in C++
#include <iostream>
using namespace std;
char *squares = new char[9]{'1', '2', '3', '4', '5', '6', '7', '8', '9'};
void play();
void getBoard();
int checkWin();
int main()
{
char *playAgain = new char;
do
{
play();
cout << "Do you want to play again(y/n): ";
cin >> *playAgain;
} while (tolower(*playAgain) == 'y');
delete squares, playAgain;
cin.get();
return 0;
}
//Play the game
void play()
{
int *i = new int;
int player = 1;
int *choice = new int;
char *mark = new char;
do
{
getBoard();
player = (player%2) ? 1 : 2;
cout << "Enter your choice: ";
cin >> *choice;
*mark = (player == 1) ? 'X' : 'O';
if (squares[0] == '1' && *choice == 1)
{
squares[0] = *mark;
}
else if (squares[1] == '2' && *choice == 2)
{
squares[1] = *mark;
}
else if (squares[2] == '3' && *choice == 3)
{
squares[2] = *mark;
}
else if (squares[3] == '4' && *choice == 4)
{
squares[3] = *mark;
}
else if (squares[4] == '5' && *choice == 5)
{
squares[4] = *mark;
}
else if (squares[5] == '6' && *choice == 6)
{
squares[5] = *mark;
}
else if (squares[6] == '7' && *choice == 7)
{
squares[6] = *mark;
}
else if (squares[7] == '8' && *choice == 8)
{
squares[7] = *mark;
}
else if (squares[8] == '9' && *choice == 9)
{
squares[8] = *mark;
}
else
{
cout << "Invalid move ";
player--;
cin.ignore();
cin.get();
}
*i = checkWin();
player++;
} while (*i == -1);
getBoard();
if (*i == 1)
{
cout << "\aPlayer " << --player << " Wins" << endl;
delete mark, choice, i;
}
else
{
cout << "\aGame Draw" << endl;
delete mark, choice, i;
}
}
// Print the board
void getBoard()
{
cout << "\n\n\tTic Tac Toe\n\n";
cout << "Player 1 (X) - Player 2 (O)" << endl
<< endl;
cout << endl;
cout << " | | " << endl;
cout << " " << squares[0] << " | " << squares[1] << " | " << squares[2] << endl;
cout << "_____|_____|_____" << endl;
cout << " | | " << endl;
cout << " " << squares[3] << " | " << squares[4] << " | " << squares[5] << endl;
cout << "_____|_____|_____" << endl;
cout << " | | " << endl;
cout << " " << squares[6] << " | " << squares[7] << " | " << squares[8] << endl;
cout << " | | " << endl
<< endl;
}
/**********************************************************************************************************
Return 1 if some one wins
Return 0 if draw
Return -1 if the game is not over
***********************************************************************************************************/
int checkWin()
{
if (squares[0] == squares[1] && squares[1] == squares[2])
{
return 1;
}
else if (squares[0] == squares[3] && squares[3] == squares[6])
{
return 1;
}
else if (squares[0] == squares[4] && squares[4] == squares[8])
{
return 1;
}
else if (squares[3] == squares[4] && squares[4] == squares[5])
{
return 1;
}
else if (squares[1] == squares[4] && squares[4] == squares[7])
{
return 1;
}
else if (squares[6] == squares[4] && squares[4] == squares[2])
{
return 1;
}
else if (squares[6] == squares[7] && squares[7] == squares[8])
{
return 1;
}
else if (squares[2] == squares[5] && squares[5] == squares[8])
{
return 1;
}
else if (squares[0] != '1' && squares[1] != '2' && squares[2] != '3' && squares[3] != '4' && squares[4] != '5' && squares[5] != '6' && squares[6] != '7' && squares[7] != '8' && squares[8] != '9')
{
return 0;
}
else
{
return -1;
}
}发布于 2020-12-05 08:21:53
这被认为是一种糟糕的做法。这是因为引入名称空间是为了避免名称冲突,即具有相同名称的多个对象。std命名空间很大,有数百个公共标识符可以干扰您的命名空间。
通过执行using namespace std,您现在不知道哪些函数是std库的一部分,哪些不是。
new的使用
我认为您误解了new运算符在C++中的使用。动态内存分配在这里有什么用?我看不出有什么好的理由不能简单地在堆栈上创建变量。这里的问题是,您不能忘记delete。如果你这样做了,你就把你的程序暴露在内存泄漏中--可怕。
您可以在以下情况下使用new:
delete之前,不希望销毁对象简而言之,这里不需要使用new操作符。这只会带来并发症。
enum/**********************************************************************************************************
Return 1 if some one wins
Return 0 if draw
Return -1 if the game is not over
***********************************************************************************************************/数字1,0,-1被称为幻数幻数,您的评论很有帮助,但是要知道它们的含义,就必须不断地引用。在这里使用enum将清除很多
enum Result { Win , Draw , OnGoing };
return Result::Win;这样您就可以将您的函数声明为
Result checkWin();而不是
return (number which means nothing)你做了
return Result::Win;值0、1和2分别自动分配给Win、Draw和Ongoing。现在我们有了这些数字的名称,我们使用它们而不是原始数字。这意味着
return Result::Win;是相同的
return 0;checkWin()int checkWin()
{
if (squares[0] == squares[1] && squares[1] == squares[2])
{
return 1;
}
else if (squares[0] == squares[3] && squares[3] == squares[6])
{
return 1;
}
else if (squares[0] == squares[4] && squares[4] == squares[8])
{
return 1;
}
else if (squares[3] == squares[4] && squares[4] == squares[5])
{
return 1;
}
else if (squares[1] == squares[4] && squares[4] == squares[7])
{
return 1;
}
else if (squares[6] == squares[4] && squares[4] == squares[2])
{
return 1;
}
else if (squares[6] == squares[7] && squares[7] == squares[8])
{
return 1;
}
else if (squares[2] == squares[5] && squares[5] == squares[8])
{
return 1;
}
}要做到这一点,一个更容易读的方法是将模式存储在数组中,并且每次您想要检查是否有赢家时,您都会遍历该数组并使用它们。
constexpr int winPatterns[8][3]{
{0, 1, 2}, // first row
{3, 4, 5}, // second row
//...
};现在,当你想找一个赢家的时候
for (int i = 0;i < 8;i++){
auto const& line = winPatterns[i];
const int a = squares[line[0]];
const int b = squares[line[1]];
const int c = squares[line[2]];
if ( a == b and b == c ) return a;
}的检查
不要检查每个单元格是否被占用,而是使用最初设置为int的0。每次转弯后继续递增。这样你就能得到这样的结果
bool checkDraw(){
return (checkWin() != Result::Win and counter == 9 );
}这很简单。如果计数器达到9,但还没有人赢,那就是平局,因为所有的单元格都被占据,而没有赢家。
cout << "\n\n\tTic Tac Toe\n\n";
cout << "Player 1 (X) - Player 2 (O)" << endl
<< endl;
cout << endl;
cout << " | | " << endl;
cout << " " << squares[0] << " | " << squares[1] << " | " << squares[2] << endl;
cout << "_____|_____|_____" << endl;
cout << " | | " << endl;
cout << " " << squares[3] << " | " << squares[4] << " | " << squares[5] << endl;
cout << "_____|_____|_____" << endl;
cout << " | | " << endl;
cout << " " << squares[6] << " | " << squares[7] << " | " << squares[8] << endl;
cout << " | | " << endl
<< endl;您可以在这里使用字符串文字。
const char* Heading = R"(
Tic Tac Toe
Player 1 (X) - Player 2 (O)
)";
std::cout << Heading;发布于 2020-12-05 08:35:38
using namespace std我再怎么强调也不为过,现在就避免。您现在可能感觉不到它的效果,但是当代码库的大小增加时,它就会令人头痛。想象一下,您有一个定义方法cout的类,这看起来很琐碎,谁会用cout定义一个方法呢?但是您应该知道,有许多好的、合理的名称已经被标准的libary所采用,您可以为sin、cos或tan找到什么好名称。这样做会使编译器混淆并导致未定义的行为。不仅如此,你还会用不相关的东西污染任何地方。首选
std::cout << "Hello World\n"或
using std::cout
cout << "Hello World\n"在后一种情况下,效果只局限于std::cout。
对于programmer来说,只有一个全局可能是合理的,但它会导致许多微妙的错误,并使代码依赖于这些全局。
char *squares = new char[9]{'1', '2', '3', '4', '5', '6', '7', '8', '9'};可以在main()中定义并作为参数传递给其他函数。
中隐式定义
像整数类型和浮点类型这样的内置程序从不隐式初始化,
int a;上面的代码段是未初始化的,是很难跟踪bug的来源,如果有疑问,请避免显式地初始化变量。这意味着,上面的代码段将变成
int a{}这里,a被初始化为0。
delete mark, choice, i;好的,您想要释放分配给这些变量的内存,但是oops,您做了什么,您成功地删除了mark。choice和i从未被删除过。一个好的编译器应该警告不要,这强调你应该让编译器成为你的朋友,不要让警告隐式传递,照顾它们,否则它们以后可能会伤害你。
delete mark;
delete choice;
delete i;现在,更好的是,我们明确了我们想要做的事情。
getBoard()是一个误导性的名称,变量命名是编程的核心,必须尽可能明确地表达它的意图,乍一看getBoard(),我会期待一个面板数组作为返回值,但它会惊讶地打印一个板到stdout,一个更好的名字将是printBoard或displayBoard,这一点对我这样的读者来说是如此的清楚。isValid()函数来简化事情bool isValid(int loc)
return loc > 0 && loc <= MAX_SIZE;然后打个记号就像说
squares[*choice-1] = *mark;编辑 isValid()检查用户的输入是否在squares的范围内,例如,1是有效的,因为它大于0,小于9(方格的大小)。-1无效,因为它不大于0,尽管它小于9。如果isValid()返回true,我们可以用1来抵消它在squares中的位置,因此1的值意味着squares.中0的索引。
这大大减少了代码大小,您可能需要考虑checkwin()的相同方法。
当您有多个if- you语句时,请考虑重构代码。
https://codereview.stackexchange.com/questions/253068
复制相似问题