目录
三子棋的游戏逻辑
实现的大致思路
主菜单的思路
game函数的实现建议及其实现思路和代码
game函数的实现建议
game函数的实现思路
game函数代码框架
初始化二维数组boardInint实现
打印棋盘displayBoard实现
玩家落子(player_move)和电脑落子(computer_move)的实现
判断输赢函数(is_win)的思路和实现
运行结果
小结
三子棋的游戏逻辑
三子棋游戏也叫井字棋
游戏的逻辑比较简单,三个一样的符号连成一行或者一列或者对角线即可胜出。
当然基于两人对战的情况下大多数都是平局。
实现的大致思路
和玩游戏一样,点开程序(程序运行)--->选择(游玩或者退出)--->游玩--->游戏结束--->选择--->再来一把或者退出。基于这个思路就可以很好实现这个代码了
主菜单的思路
和一般的游戏主菜单一样,通常使用do while 循环。
do while 循环的好处是先循环在判断,可以多循环一次,一般来说游戏的界面都是用这个框架来实现。
用menu函数对玩家的进行一个可供选则的一个提示。
如让玩家输入数字,用swtich语句对输入的数字进行一个选择 。例如输入1进行游戏,输入0退出。
那有的人输入错了,输入0或者1之外的其他数字。c语言中0为假,此外都是真,则会让玩家一直进行选择的一个循环
int main()
{
int input = 0;
do
{
menu();//提示玩家因该输入什么数字
scanf("%d", &input);//玩家输入数字
switch (input)//对玩家输入的数字进行选择
{
case 1:
game();//进行游戏
break;
case 0:
printf("游戏结束n");//游戏结束退出
break;
default:
printf("选择错误n");//除0或者1之外的数字就会再打印一次菜单进行选择
break;
}
} while (input);
return 0;
}
menu的实现
这个函数的实现较为简单
void menu()
{
printf("*********************************n");
printf("********* 三子棋游戏 ********n");
printf("********* 1.play ********n");
printf("********* 0.exit ********n");
printf("*********************************n");
printf("请输入数字--------------------->:");
}
game函数的实现建议及其实现思路和代码
game函数的实现建议
这里建议先简单打印一下“玩游戏”,检查一下之前写的代码有无错误,写一步运行一下。即使发现错误,也能及时修改;
等到最后代码写完了最后检查会比较费时费力;
例如printf(“玩游戏”)运行。
实现game函数比较复杂,需要用多个函数实现;
因此建议创建一个game.h的头文件用来声明game使用的函数;
用game.c的源文件来实现game.h声明的函数;
用test.c的源文件来对game.c来测试;当然,test.c和game.c最开头都要先声明一下
例如#include“game.h”
如果不用多个文件实现的话,代码都堆在一个文件会造成冗余,不够清晰,缺乏观赏性。
game函数的实现思路
三子棋游戏的棋盘像3×3的二维数组,下棋相当于在二维数组里面放字符。
基于这个思路我们先初始化一下这个二位数组;
然后打印棋盘,打印棋盘,玩家落子,打印棋盘,判断胜负,电脑落子,打印棋盘,判断胜负。
如果胜负未定,则一直循环玩家落子和电脑落子的过程;
当判断一方胜负或者棋盘下满为和棋之时就跳出这个循环游戏结束。
game函数代码框架
void game()
{
char board[ROW][COL] = {0};
boardInint(board,ROW,COL);//棋盘初始化
displayBoard(board,ROW,COL);//打印棋盘
char tmp = 0;
while (1)
{
player_move(board, ROW, COL);//玩家下棋
displayBoard(board, ROW, COL);//打印棋盘
tmp = is_win(board, ROW, COL);//判断输赢
if (tmp != 'c')//游戏是否继续
{
break;
}
computer_move(board, ROW, COL);//电脑下棋
displayBoard(board, ROW, COL);//打印棋盘
tmp= is_win(board, ROW, COL);//判断输赢
if (tmp != 'c')//游戏是否继续
{
break;
}
}
if (tmp == '*')
{
printf("恭喜你赢得游戏!n");
}
if (tmp == '#')
{
printf("很遗憾,你输了n");
}
if (tmp == 'p')
{
printf("平局n");
}
}
用到的函数在头文件声明
初始化二维数组boardInint实现
初始化棋盘只要在二位数组里面放上空格就行
void boardInint(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] =' ';
}
}
}
打印棋盘displayBoard实现
打印棋盘就是打印二维数组里面的字符内容及其分隔符号;
分隔符号的打印可以打印一个空格一个字符再加一个空格,然后打印“|”,
在下一排打印“---|---|---”;
注意在边界是不需要打印“|”和“---|---|---”的。
具体代码如下
void displayBoard(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++)
{
printf(" %c ", board[i][j]);
if (j < col - 1)
printf("|");
}
printf("n");
if (i < row - 1)
{
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
printf("|");
}
}
printf("n");
}
}
玩家落子(player_move)和电脑落子(computer_move)的实现
玩家落子和电脑落逻辑基本相同;
需要注意的是玩家落子和数组的起始数字;
玩家的起始数字的1,数组却是0;
玩家落子代码如下
void player_move(char board[ROW][COL], int row, int col)//玩家下棋
{
printf("玩家下棋n");
int x = 0;
int y = 0;
while (1)
{
printf("请输入坐标");
scanf("%d %d", &x, &y);
if (board[x - 1][y - 1] == ' ' && x >= 0 && x <= row && y >= 0 && y <= col)//玩家落子的范围必须在0-3和0-3之间并且此处没有字符,否则非法,循环继续落子
{
board[x - 1][y - 1] = '*';
break;
}
else
printf("坐标非法!");
}
}
电脑落子需要用到两个函数
rand() 和srand()这两个函数
用rand随机生成一个数字的时候,需要用一个随机数来定义srand的标准;需要随机数又要用随机数来生成随机数,有点矛盾,但使用时间戳能解决这个问题,因为时间是不断在变化,时间戳会把时间转换成数字;
具体用法如下
srand((unsigned int)time(NULL)); int x = rand() ;
注意需要用#include
srand((unsigned int)time(NULL));这句代码放在主函数开头就可以了,标准只需要设置一次就好
同样需要注意的是玩家落子和数组的起始数字;
玩家的起始数字的1,数组却是0;
电脑落子具体代码如下
void computer_move(char board[ROW][COL], int row, int col)//电脑下棋
{
printf("电脑下棋n");
while (1)
{
int x = rand() % 3 + 1;// 用随机数模上一个数字会生成0到(x-1)之间的数字,加一就会随机生成0到x之间的数字
int y = rand() % 3 + 1;
if (board[x - 1][y - 1] == ' ' && x >= 0 && x <= row && y >= 0 && y <= col)
{
board[x - 1][y - 1] = '#';
break;
}
}
}
判断输赢函数(is_win)的思路和实现
用函数来判断输赢最好用一个返回字符来判断游戏是否继续和胜出;
例如玩家赢就返回玩家的落子字符,电脑赢就返回电脑落子的字符;
没有胜负就返回一个’c‘来使函数继续执行玩家落子和电脑落子;
此外非’c‘都可以市循环继续;
平局就返回”p“使循环结束;
平局需要再用一个函数(is_full)判断(is_full函数只需检查数组里面是不是没有空字符即可)
(is_win)具体代码如下
char is_win(char board[ROW][COL], int row, int col)//判断输赢,有四种情况,玩家赢,电脑赢,平局还有继续下棋,因此用返回的字符来判断是哪一种情况
{
if (board[0][0] == board[1][1]&& board[1][1] == board[2][2]&&board[1][1]!=' ')//两条对角线相同
return board[0][0];
if (board[0][2] == board[1][1]&& board[1][1] == board[2][0] && board[1][1] != ' ')
return board[0][2];
for (int i = 0; i < row; i++)
{
if (board[i][0] == board[i][1]&& board[i][1] == board[i][2] && board[i][0] != ' ')//一行三个相同
return board[i][0];
}
for (int i = 0; i < row; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')//一列三个相同
return board[i][0];
}
//平局只能是棋盘都下满了
if (is_full(board, row, col) == 1)
return 'p';
//继续下棋
return 'c';
}
(is_full)具体代码如下
int is_full(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
if (board[i][j] == ' ')//还有空格,表示棋盘没满
return 0;
}
}
return 1;//循环结束都不是空格表示期盼满了
}
运行结果
小结
该代码只能写出傻瓜电脑,如果需要电脑更加聪明,则需要在电脑落子的算法上进行优化。
还可以在每次落子之时用system('cls');这行代码清理一下屏幕,使其游戏体验更佳。



