目录
1. 概述
2. 代码实现
InitBoard 函数
DisplayBoard 函数
PlayMove 函数
ComputerMove 函数
IsFull 函数
IsWin 函数
game 函数
main 函数
3. 总结
该项目为使用 C 语言编写基于控制台的井字棋游戏。
玩家使用“*”作为棋子,电脑使用“#”作为棋子,两个实体轮流下棋,第一个完成三个棋子连成一线的玩家获胜。若棋盘已满且没有玩家获胜,游戏成平局。
该游戏为基础井字棋游戏,AI 算法为随机下棋。
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
#include
#define ROW 3
#define COL 3
#define PLAYER_PIECE '*'
#define COMPUTER_PIECE '#'
void InitBoard(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}
}
void DisplayBoard(char board[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
printf(" %c ", board[i][j]);
if (j < col - 1)
{
printf("|");
}
}
printf("\n");
if (i < row - 1)
{
int j = 0;
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
{
printf("|");
}
}
printf("\n");
}
}
}
void PlayMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("玩家走:>\n");
while (1)
{
printf("请输入坐标\n");
scanf("%d %d", &x, &y);
//判断坐标合法性
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (board[x - 1][y - 1] == ' ')
{
board[x - 1][y - 1] = PLAYER_PIECE;
break;
}
else
{
printf("坐标被占用,请重新输入!\n");
}
}
else
{
printf("非法坐标,请重新输入!\n");
}
}
}
void ComputerMove(char board[ROW][COL], int row, int col)
{
printf("电脑走:>\n");
while (1)
{
int x = rand() % row;
int y = rand() % col;
//判断占用
if (board[x][y] == ' ')
{
board[x][y] = COMPUTER_PIECE;
break;
}
}
}
int IsFull(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
if (board[i][j] == ' ')
{
return 0;//棋盘没满
}
}
}
return 1;//棋盘满了
}
char IsWin(char board[ROW][COL], int row, int col)
{
int i = 0;
//判断三行
for (i = 0; i < row; i++)
{
if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][1] != ' ')
{
return board[i][1];//
}
}
//判断三列
for (i = 0; i < col; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' ')
{
return board[1][i];
}
}
//判断对角线1
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
{
return board[1][1];
}
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
{
return board[1][1];
}
int ret = IsFull(board, row, col);
if (ret == 1)
{
return 'Q';
}
return 'C';
}
void menu()
{
printf("****************************\n");
printf("****** 输入1开始游戏 ******\n");
printf("****** 输入0结束游戏 ******\n");
printf("****************************\n");
}
void game()
{
//存储数据 二维数组
char board[ROW][COL];
//初始化棋盘,初始化空格
InitBoard(board, ROW, COL);
//打印一下棋盘 本质是打印数组内容
DisplayBoard(board, ROW, COL);
//接受游戏转状态
char ret = 0;
while (1)
{
//玩家走
PlayMove(board, ROW, COL);
//玩家走完打印
DisplayBoard(board, ROW, COL);
printf("\n");
//判断玩家是否赢了游戏
ret = IsWin(board, ROW, COL);
if (ret != 'C')
break;
//电脑走
ComputerMove(board, ROW, COL);
//电脑走完打印
DisplayBoard(board, ROW, COL);
printf("\n");
//判断电脑是否赢了游戏
ret = IsWin(board, ROW, COL);
if (ret != 'C')
break;
}
if (ret == PLAYER_PIECE)
{
printf("玩家胜利!\n\n");
}
else if (ret == COMPUTER_PIECE)
{
printf("电脑胜利!\n\n");
}
else
{
printf("平局!\n\n");
}
DisplayBoard(board, ROW, COL);
printf("\n");
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏!\n");
break;
default:
printf("选择错误,请重新选择!\n");
break;
}
} while (input);
return 0;
}
该井字棋游戏使用 C 语言编写,主要由以下几个函数组成:
- InitBoard:初始化棋盘,并将所有位置设置为空格
- DisplayBoard:打印当前棋盘状态
- PlayMove:玩家下棋
- ComputerMove:随机 AI 下棋
- IsFull:判断棋盘是否已满
- IsWin:判断是否有玩家获胜
- menu:打印游戏菜单
- game:控制游戏的流程,游戏结束后打印胜者,并展示最终的棋盘状态
- main:执行前两个函数,并允许用户选择是否开始游戏或结束游戏
void InitBoard(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}
}
该函数用于初始化棋盘,并将所有位置设置为空格。其中,`board` 为一个二维字符数组,存储了棋盘的状态;`row` 和 `col` 分别表示棋盘的行数和列数。
函数实现过程中,使用了嵌套循环对所有的位置进行遍历,将其设置为空格。
void DisplayBoard(char board[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
printf(" %c ", board[i][j]);
if (j < col - 1)
{
printf("|");
}
}
printf("\n");
if (i < row - 1)
{
int j = 0;
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
{
printf("|");
}
}
printf("\n");
}
}
}
该函数用于打印当前棋盘状态。与 `InitBoard` 函数类似,它也使用了 `board` 二维数组表示棋盘状态,同时也使用了 `row` 和 `col` 表示棋盘的行数和列数。
函数实现过程中,使用了嵌套循环对所有的位置进行遍历,使用 `printf` 函数打印每个棋子,并在其后添加竖线分隔符。在打印完一行后,还会添加水平分隔符。通过判断行和列的位置,函数可以控制是否打印分隔符。
void PlayMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("玩家走:>\n");
while (1)
{
printf("请输入坐标\n");
scanf("%d %d", &x, &y);
//判断坐标合法性
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (board[x - 1][y - 1] == ' ')
{
board[x - 1][y - 1] = PLAYER_PIECE;
break;
}
else
{
printf("坐标被占用,请重新输入!\n");
}
}
else
{
printf("非法坐标,请重新输入!\n");
}
}
}
该函数用于让玩家下棋。同样使用了 `board` 二维数组表示棋盘状态,`row` 和 `col` 表示棋盘的行数和列数。
函数实现过程中,使用 `scanf` 函数获取用户输入的坐标,并判断输入坐标的合法性和位置是否已被占用。如果输入的坐标非法或者该位置已被占用,将提示用户重新输入。如果输入的坐标合法并且该位置未被占用,就将棋子放置在该位置。
void ComputerMove(char board[ROW][COL], int row, int col)
{
printf("电脑走:>\n");
while (1)
{
int x = rand() % row;
int y = rand() % col;
//判断占用
if (board[x][y] == ' ')
{
board[x][y] = COMPUTER_PIECE;
break;
}
}
}
该函数用于让电脑下棋。同样使用了 `board` 二维数组表示棋盘状态,`row` 和 `col` 表示棋盘的行数和列数。
函数实现过程中,使用 `rand` 函数生成随机的坐标,判断该位置是否已被占用。如果该位置未被占用,就将棋子放置在该位置。
int IsFull(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
if (board[i][j] == ' ')
{
return 0;//棋盘没满
}
}
}
return 1;//棋盘满了
}
该函数用于判断棋盘是否已满。同样使用了 `board` 二维数组表示棋盘状态,`row` 和 `col` 表示棋盘的行数和列数。
函数实现过程中,使用了嵌套循环对所有的位置进行遍历,判断是否有空格。如果有空格,说明棋盘未满,返回 0;否则,返回 1,表示棋盘已满。
char IsWin(char board[ROW][COL], int row, int col)
{
int i = 0;
//判断三行
for (i = 0; i < row; i++)
{
if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][1] != ' ')
{
return board[i][1];//
}
}
//判断三列
for (i = 0; i < col; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' ')
{
return board[1][i];
}
}
//判断对角线1
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
{
return board[1][1];
}
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
{
return board[1][1];
}
int ret = IsFull(board, row, col);
if (ret == 1)
{
return 'Q';
}
return 'C';
}
该函数用于判断是否有玩家获胜。同样使用了 `board` 二维数组表示棋盘状态,`row` 和 `col` 表示棋盘的行数和列数。
函数实现过程中,使用了嵌套循环判断各行、各列、对角线是否已有一方下满三个棋子。如果存在一方下满三个棋子并连成一线,就返回该方棋子类型。
如果棋盘已满且没有任何一方获胜,就返回 ‘Q’,表示平局。
void menu()
{
printf("****************************\n");
printf("****** 输入1开始游戏 ******\n");
printf("****** 输入0结束游戏 ******\n");
printf("****************************\n");
}
该函数用于打印游戏菜单,提示用户输入 1 开始游戏或输入 0 结束游戏。
void game()
{
//存储数据 二维数组
char board[ROW][COL];
//初始化棋盘,初始化空格
InitBoard(board, ROW, COL);
//打印一下棋盘 本质是打印数组内容
DisplayBoard(board, ROW, COL);
//接受游戏转状态
char ret = 0;
while (1)
{
//玩家走
PlayMove(board, ROW, COL);
//玩家走完打印
DisplayBoard(board, ROW, COL);
printf("\n");
//判断玩家是否赢了游戏
ret = IsWin(board, ROW, COL);
if (ret != 'C')
break;
//电脑走
ComputerMove(board, ROW, COL);
//电脑走完打印
DisplayBoard(board, ROW, COL);
printf("\n");
//判断电脑是否赢了游戏
ret = IsWin(board, ROW, COL);
if (ret != 'C')
break;
}
if (ret == PLAYER_PIECE)
{
printf("玩家胜利!\n\n");
}
else if (ret == COMPUTER_PIECE)
{
printf("电脑胜利!\n\n");
}
else
{
printf("平局!\n\n");
}
DisplayBoard(board, ROW, COL);
printf("\n");
}
该函数用于控制游戏流程,实现玩家和电脑轮流下棋,直至游戏结束。在每次玩家和电脑下完棋后,都会打印当前的棋盘状态以及提示信息。
如果某一方下满三个棋子连成一线,游戏结束,并打印胜利方。如果棋盘已满且没有任何一方获胜,游戏结束,并打印平局。
最后,该函数还将展示最终的棋盘状态。
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏!\n");
break;
default:
printf("选择错误,请重新选择!\n");
break;
}
} while (input);
return 0;
}
该函数是整个程序的入口,执行该函数会根据用户的选择打印游戏菜单或直接退出游戏。
在函数实现过程中,使用了 `srand` 函数生成一个基于时间的随机数种子。此外,在执行菜单选项时,使用了 `switch` 语句根据用户输入执行相应的代码实现。
整个程序的结构非常清晰,游戏流程没有使用递归,主要是使用循环来控制。
其中,比较有意思的部分是 `DisplayBoard` 函数,它使用了循环嵌套来打印棋盘的状态,通过判断行列数来控制是否打印框线。
另一个有趣的部分是 `ComputerMove` 函数,它使用 `rand()` 函数随机下棋。
该井字棋游戏是一个基础版,但可以通过该参考代码了解到一些基本的 C 语言操作,如循环嵌套、判断语句和数组等。
当然,该游戏也有一些可以改进的地方。比如,可以考虑添加更加智能的 AI,提高游戏难度和趣味性。
总之,该项目对于初学者来说是一个不错的练手项目,希望该项目能够帮助你熟悉 C 语言的操作和基本编程概念。