在学完分支循环语句和函数、数组等概念后,就可以将他们串联起来,做一个三子棋的小游戏。
先是写一个menu函数,将菜单打印给玩家,让玩家选择游玩或是退出
void menu()
{
printf(" ---------------- n");
printf("| 1.play |n");
printf("| 0.exit |n");
printf(" ---------------- n");
}
当然玩家在游玩结束后不能直接结束程序,要再次打印菜单询问玩家是否需要再玩一把,这样就可以使用一个do...while循环去实现,这就是我们的主函数
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请选择");
scanf("%d", &input);
switch (input)
{
case 1:
printf("开始游戏n");
game();
break;
case 0:
printf("退出游戏n");
break;
default:
printf("输入错误,请重新输入n");
break;
}
} while (input);
}
用switch对玩家的input进行判断,input为1时会进行游戏,输入0或1之外的数字会要求重新输入
接下来要完善case 1中的game函数,也就是游戏的主体部分
三子棋游戏可以分为两部分,一是玩家和电脑下棋的过程,这其中需要打印一个棋盘,也需要将落子的地方存储起来,二是对局结束的条件,也就是行列或是对角三子连线或是棋盘被填满
首先先来实现下棋的过程,我们要用一个二维字符数组board来存放落子的位置,宏定义行列,然后用InitBoard来初始化数组,用for循环的嵌套让数组的每个元素都是空格
#define ROW 3
#define COL 3
void InitBoard(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}
}
当然把落子存入字符数组还不够,需要将棋盘打印出来给玩家看
void DisplayBoard(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
printf(" %c ", board[i][j]);
if (j < col - 1)
printf("|");
}
printf("n");
if (i < row - 1)
{
for (int j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
printf("|");
}
}
printf("n");
}
}
打印出来的效果如图所示
接下来就是下棋的部分,玩家和电脑轮流下棋,每次落子后再次打印棋盘,写一个while的死循环,玩家键盘输入下棋的行列,若玩家输入的坐标在棋盘内,则判断玩家输入坐标处的字符,如果此处为空格,则改为‘*’并跳出循环,若此处有人下过棋,打印此处有人下过棋,让玩家重新输入横纵坐标。若坐标非法则打印坐标非法并重新输入
void player_move(char board[ROW][COL], int row, int col)
{
printf("玩家下棋:");
int x, y;
while (1)
{
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] = '*';
break;
}
else
{
printf("此处已被占用,请重新输入!n");
}
}
else
{
printf("坐标非法n");
}
}
}
电脑的下棋则相对简单,因为我们只是初学阶段,只能让电脑随机落在一个空的地方,对此我们需要导入time.h的头文件,在主函数中写下一行srand((unsigned int)time(NULL)); 他的具体含义这里就不赘述了,他会为我们提供两个随机的无符号整数,将两个随机数和行列进行取余我们就能得到一个坐标,它肯定会在我们的棋盘里面,接下来我们去判断这个坐标是否为空格,是则把空格改成’#‘并跳出循环
void computer_move(char board[ROW][COL], int row, int col)
{
int x, y;
printf("电脑下棋n");
while (1)
{
x = rand() % ROW;
y = rand() % COL;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
接下来就是判断获胜的条件了,获胜无非就三种,行相等,列相等,对角线相等,我们对行列进行遍历,三个相等且不是空格则返回相等的字符,若是‘*’则是玩家胜利,反之则是电脑胜利。当然还有平局和对局还没结束两种情况,我们遍历二维数组中的每一个,如果有空格就返回字符‘c’作为游戏继续,如果什么都没返回,那就是没人赢也不能继续了,就是平局,返回字符‘p’
char is_win(char board[ROW][COL], int row, int col)
{
for (int 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 (int 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];
}
}
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];
}
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
if (board[i][j] == ' ')
return 'c';
}
}
return 'p';
}
接下来就是把所有的函数放到我们的game函数里了,初始化棋盘并展示后,把玩家电脑双方下棋放入一个死循环中,知道is_win函数返回的不再是count后跳出循环。
void game()
{
char board[ROW][COL] = { 0 };
InitBoard(board, ROW, COL);
DisplayBoard(board, ROW, COL);
char ret = 0;
while (1)
{
player_move(board, ROW, COL);
DisplayBoard(board, ROW, COL);
ret = is_win(board, ROW, COL);
if (ret != 'c')
break;
computer_move(board, ROW, COL);
DisplayBoard(board, ROW, COL);
ret = is_win(board, ROW, COL);
if (ret != 'c')
break;
}
if (ret == '*')
printf("玩家胜利n");
else if (ret == '#')
printf("电脑胜利n");
else
printf("平局n");
}
这样简单的三子棋就做好了



