目录
来介绍一个c语言的小游戏吧——三子棋(井字棋),我们的童年或多或少都体验过这个游戏的乐趣,本子随手一画就是一局游戏的开始,就让我们一起来看看用C语言相关的知识如何开始这一小游戏吧。
一.游戏介绍:
如图所示,我们会在一个“井”字里面进行下棋,有“⭕”,“❌”两种棋子存在,一共九个位置,哪方率先将同样的棋连成一条直线,那一方即为胜利,游戏的规则非常简单,让我们来逐步实现一下该逻辑吧!
在这个小游戏中,我们分为三个模块来进行实现,我们将自定义函数的的声明放置在“game.h”头文件中,函数的定义放在“game.c”文件中,函数的使用放在“test.c”文件中来逐步实现。
二,整体逻辑实现
对于一共游戏而言,避免不了菜单的出现,而在菜单中,就必然需要我们选择是否开始游戏,考虑到玩游戏的次数可能是多次,我们采用do while循环来打印菜单,switch语句来选择游戏选项,随后判断游戏是否进行第二轮,代码如下:
#include<stdio.h>
//菜单打印
void menu()
{
printf("************************\n");
printf("******** 1.play *******\n");
printf("******** 0.exit *******\n");
printf("************************\n");
}
//整体的逻辑实现
int main()
{
int input = 0;
do
{
menu();
printf("请选择:");
scanf("%d", &input);
switch (input)
{
case 1:
game();
printf("开始游戏:\n");
break;
case 0:
printf("退出游戏.");
break;
default :
printf("选择错误,请重新选择\n");
break;
}
} while (input);
return 0;
}
//test.c文件里实现
我们采用1开始游戏,0结束游戏来匹配do while的判断情况,打印效果如上所示,当然我们不能选择1后只有个“开始游戏”在屏幕显示,所以接下来我们介绍游戏逻辑的实现——定义一个game函数。
三. 游戏内部函数逻辑
1.棋盘的实现
我们进行人机游戏实现,将game函数放在case 1后进行,如三子棋的图示可见,我们需要一个3×3的棋盘来让玩家和电脑放置棋子,于是便需要一个Board二维数组来制作棋盘,而当棋盘制作好后需要打印出棋盘以观察落子情况,所以这里我们需要定义和打印棋盘,这里我们将3×3的数字以宏的形式来定义:
#define ROW 3
#define COL 3
将此宏定义放置在game.h头文件中,接下来实现game函数:
void game()
{
//定义棋盘.
char Board[ROW][COL] = { 0 };
//打印棋盘.
display_Board(Board, ROW, COL);
}//在test.c文件中
//打印棋盘
void display_Board(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)
{
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
printf("|");
}
printf("\n");
}
}
}//函数的定义放在game.c文件
当我们按照上述逻辑打印后会有如下结果:棋盘的格式很凌乱,达不到我们想要的效果
这是因为我们定义二维数组的时候进行的初始化是0,而字符0是不会打印的,所以我们会有错行情况出现,所以我们也要进行棋盘的初始化——放置空格来满足。
//初始化棋盘
void InitBoard(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++)
{
board[i][j] = ' ';
}
}
}
至此我们便实现了游戏棋盘
2.玩家自主下棋
在实现完棋盘后,我们进入游戏第二步:玩家下棋
玩家下棋满足的情况:
1.下棋位置合法(不能超出棋范围)
2.下棋的位置没有被占用,代码实现如下:
void player_move(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("玩家下棋: \n");
while (1)
{
printf("请输入坐标:");
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");
}
}
}
在这里,因为数组第一个元素从0开始,但输入坐标时我们从1计算,所以我们要将x,y坐标减一来进行实现。
可以观察到我们只下了一步便退出了玩家下棋的逻辑,这是不合理的,所以我们应该将玩家和电脑下棋的函数都放置在while循环中,直到游戏结束再结束下棋
3.电脑随机下棋
我们在这里不将电脑设置成可以追堵玩家的模式,只需要它在空余位置落子即可,由于电脑落子是随机的,我们需要使用一个rand函数来制造随机数以便电脑下棋
观察rand函数的作用,返回一个从0到最大值的随机数,这个RAND_MAX我们可以在vs观察其数值为:32767,也就是我们可以返回一个0~32767的随机数
但注意第二段,这个随机数是由算法生成的,而该算法需要使用srand函数来调用
而观察srand函数时,可以看到,它建议设置seed种子参数时候使用time函数
因为时间每分每秒都在改变,我们使用srand设置种子时,如果种子的数值不变,那么得到的算法单一,产生的随机数会相同,这不是我们想要的结果,于是我们使用time函数,将参数设置为NULL空指针,它返回的值是时间,只需将time_t的类型强制类型转换即可:
srand((unsigned int)time(NULL));
种子只需要设定一次,所以我们将srand函数放在main函数里面,减少代码计算量,然后进行电脑随机下棋:
void computer_move(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] = '#';
break;
}
}
}
4.游戏结束的判断
在玩家和电脑逐步下棋对战后,便是来到了我们判断游戏是否结束的环节:
我们进行如下设定:
1.玩家获胜——我们返回 “ * ”
2.电脑获胜——我们返回 “ # ”
3.平局——我们返回 “ Q ”
4.游戏继续——返回 “ C ”
按照如上逻辑,我们先设定一个ret变量,来存储上述四种返回值——以此来判断游戏是否继续情况和赢家是谁:
char judge_winner(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][0] != ' ')
{
return board[i][0];
}
}
//判断三列
for (i = 0; i < col; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
{
return board[0][i];
}
}
//判断对角线
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ')
{
return board[0][0];
}
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
{
return board[1][1];
}
//以上情况都不发生时:平局产生——棋盘满了
if (is_full(board,row,col))
{
return 'Q';
}
return 'C';
}
我们进行三行,三列以及对角线的判断,因为我们设定的玩家下“ * ”,电脑下“ # ”,所以只需要直接返回下的该棋子即可判断输赢情况,如果输赢都不满足,那我们只需判断棋盘是否填满,如若不是则继续进行游戏,直到结束。
四.三子棋代码
test.c文件:
#include "game.h"
void menu()
{
printf("************************\n");
printf("******** 1.play *******\n");
printf("******** 0.exit *******\n");
printf("************************\n");
}
void game()
{
char ret = 0;
//定义棋盘.
char Board[ROW][COL] = { 0 };
//初始化棋盘.
InitBoard(Board, ROW, COL);
//打印棋盘
display_Board(Board, ROW, COL);
while (1)
{
//玩家下棋
player_move(Board, ROW, COL);
display_Board(Board, ROW, COL);
ret = judge_winner(Board, ROW, COL);
if (ret != 'C')
break;
//电脑下棋
computer_move(Board, ROW, COL);
display_Board(Board, ROW, COL);
ret = judge_winner(Board, ROW, COL);
if (ret != 'C')
break;
}
if (ret == '*')
{
printf("玩家获胜! \n");
}
else if (ret == '#')
{
printf("电脑获胜! \n");
}
else if (ret == 'Q')
{
printf("平局");
}
display_Board(Board, ROW, COL);
}
int main()
{
srand((unsigned int)time(NULL));
int input = 0;
do
{
menu();
printf("请选择:");
scanf("%d", &input);
switch (input)
{
case 1:
game();
printf("开始游戏:\n");
break;
case 0:
printf("退出游戏.");
break;
default :
printf("选择错误,请重新选择\n");
break;
}
} while (input);
return 0;
}
game.c文件:
//初始化棋盘
void InitBoard(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++)
{
board[i][j] = ' ';
}
}
}
//打印棋盘
void display_Board(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)
{
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
printf("|");
}
printf("\n");
}
}
}
//玩家下棋
void player_move(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("玩家下棋: \n");
while (1)
{
printf("请输入坐标:");
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");
}
}
}
//电脑随机下棋
void computer_move(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] = '#';
break;
}
}
}
//判断棋盘是否满格
int is_full(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++)
{
if (' ' == board[i][j])
{
return 0;
}
}
}
return 1;
}
//判断胜利
//C——游戏继续
//*——玩家获胜
//#——电脑获胜
//Q——平局
char judge_winner(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][0] != ' ')
{
return board[i][0];
}
}
//判断三列
for (i = 0; i < col; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
{
return board[0][i];
}
}
//判断对角线
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ')
{
return board[0][0];
}
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
{
return board[1][1];
}
//以上情况都不发生时:平局产生——棋盘满了
if (is_full(board,row,col))
{
return 'Q';
}
return 'C';
}
game.h文件:
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 3
#define COL 3
//初始化棋盘
void InitBoard(char board[ROW][COL], int row, int col);
//打印棋盘
void display_Board(char board[ROW][COL], int row, int col);
//玩家下棋
void player_move(char board[ROW][COL], int row, int col);
//电脑下棋
void computer_move(char board[ROW][COL], int row, int col);
//判断胜利方
char judge_winner(char board[ROW][COL], int row, int col);
好啦,这便是小编对于三子棋的实现情况,谢谢各位的阅读,我们期待下次更新吧~