目录
1.游戏规则
2.游戏实现
3.游戏测试
4.代码链接
---------------------------------------------------------------------------------------------------------------------------------
1.游戏规则
三子棋又称井字棋,一般来说是在一个3×3的棋盘中,双方执不同的棋按先后顺序依次落子,率先将棋连成连续3个(同一种棋连成一行或者一列,或者斜对角)的一方获胜,如下图所示,红方为先行方,红方率先将棋连成3子一线。
2.游戏实现
首先我们将项目分为游戏和测试两个模块,分别创建game.h game.c和test.c三个文件,game文件用于游戏的声明和实现,test模块用于游戏的测试。
游戏的大致逻辑如下所示:
以上转换为代码:
//游戏测试模块
void test() {
int input = 0;
do {
//打印菜单
menu();
//获取用户输入
printf("请选择:>");
scanf("%d", &input);
//判断用户输入
switch (input) {
case 1:
//进入游戏
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("非法输入,请重新输入\n");
break;
}
} while (input);
}
//实现一个三子棋的游戏
int main() {
test();
return 0;
}
2.1打印菜单
打印游戏菜单menu(),提示用户输入,1代表开始游戏,0表示推出游戏
menu() {
printf("************************\n");
printf("***** 1. play *****\n");
printf("***** 0. exit *****\n");
printf("************************\n");
}
2.2获取用户输入
获取用户输入,根据输入判断是否执行游戏模块。
2.3执行游戏程序
当用户输入1时,进入游戏模块game()。游戏执行后,应该先打印一张空的棋盘,用户输入坐标后,重新打印已经落子后的棋盘,接着电脑下棋,再打印棋盘,依次类推。同时,在一方落子后,需要判断棋面是哪一方赢,或者平局,或者棋还未下完,根据棋面状态决定继续下棋还是结束下棋。游戏的执行逻辑如下:
2.3.1打印棋盘
为了能够打印棋盘,首先创建棋盘并进行初始化,为了能够更灵活的复用代码,在game.h头文件中定义两个符号ROW和COL来分别代表棋盘数组的行和列,后续要改变棋盘的大小,只需要改变这两个量的值。
#define ROW 3
#define COL 3
//创建棋盘
char board[ROW][COL] = { 0 };
//初始化棋盘
init_board(board, ROW, COL);
//打印棋盘
print_board(board, ROW, COL);
为了能在终端上看的出来棋盘,首先将数组初始化为空格,即' ',并在相应的行和列打印横竖边界,打印的形式如下图所示:
对应的代码:
//初始化棋盘
void init_board(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 print_board(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");
}
}
终端打印效果:
2.3.2玩家下棋
能够顺利打印棋盘后,接下来是玩家进行下棋,首先获取玩家输入的坐标信息,得到输入坐标后需要判断坐标值是否有效,例如是否取值在设定的棋盘坐标大小之内,坐标判定有效后,仍需判定坐标所表示的地方是否已经下过棋,若下过棋,需要提示用户重新输入坐标,若没有,则将对应位置的内容改为玩家所下的棋,这里用字符 * 表示玩家下棋,字符 # 表示电脑下棋, 因为数组的下标从0开始,而玩家默认坐标是从1开始的,所以应该将输入的横纵坐标都减1后,才是需要更改的棋盘坐标。玩家下棋逻辑如下:
代码:
void player_turn(char board[ROW][COL], int row, int col) {
int x = 0;
int y = 0;
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");
}
}
}
2.3.3 电脑下棋
电脑下棋同理,通过获取0~棋盘大小的随机值,例如x=rand()%row,y=rand()%col,若row为3,即x的取值范围为0~2(注意,调用rand()函数我们需要给其指定sand(),即随机值起点,我们可以指定从当前时间开始,即srand((unsigned int)time(NULL));同样判断坐标值是否已经不是空格,若不是,修改对应位置值为字符 #。
2.3.4判断输赢
双方各自下完棋后,需要打印更改后的棋盘,然后判断输赢。这里用字符 * 表示玩家赢,字符 # 表示电脑赢,字符 Q 表示平局,字符 C 表示棋未要玩,继续下棋,根据判断的结果返回相应的字符。
一方赢的条件为3行或3列或斜对角连成3个相同形状的符号,例如可以先遍历棋盘数组,获取一行中的元素个数,将一行中的元素个数存放在一个arr[]数组中,数组的大小就是棋盘数组一行元素的个数,即棋盘数组的列数,存放入arr[]后再判断其中元素是否相等,若相等,再判断是字符 * 还是字符 #,若不相等,同理再获取每一列与对角元素,并进行比较。
若以上判断没有结果,再判断棋盘是否已经被下满,即棋盘数组元素已经没有空格字符了,若被下满,则表示平局,返回字符 Q,若没有,则继续下棋。
//判断数组内元素是否相等
int is_equal(char arr[], int sz) {
char ret = arr[0];
for (int i = 1; i < sz; i++) {
if (ret != arr[i]) {
return 0;
}
}
return 1;
}
//判断输赢
char is_win(char board[ROW][COL], int row, int col) {
//获取每一行数据,判断是否相等
for (int i = 0; i < row; i++) {
char arr1[COL] = { 0 };
for (int j = 0; j < col; j++) {
arr1[j] = board[i][j];
}
if (1 == is_equal(arr1, col)) {
if (arr1[0] == '*') {
return '*';
}
else if (arr1[0] == '#') {
return '#';
}
}
}
//获取每一列数据,判断是否相等
for (int i = 0; i < row; i++) {
char arr1[ROW] = { 0 };
for (int j = 0; j < col; j++) {
arr1[j] = board[j][i];
}
if (1 == is_equal(arr1, row)) {
if (arr1[0] == '*') {
return '*';
}
else if (arr1[0] == '#') {
return '#';
}
}
}
//获取斜对角数据,判断是否相等,行和列需相等
if (row == col) {
char arr2[ROW] = { 0 };
for (int i = 0; i < row; i++) {
for (int j = 0; j < row; j++) {
if (i == j) {
arr2[i] = board[i][j];
}
}
}
if (1 == is_equal(arr2, row)) {
if (arr2[0] == '*') {
return '*';
}
else if (arr2[0] == '#') {
return '#';
}
}
char arr3[ROW] = { 0 };
for (int i = 0; i < row; i++) {
for (int j = 0; j < row; j++) {
if (i + j == row - 1) {
arr3[i] = board[i][j];
}
}
}
if (1 == is_equal(arr3, row)) {
if (arr3[0] == '*') {
return '*';
}
else if (arr3[0] == '#') {
return '#';
}
}
}
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
if (board[i][j] == ' ') {
return 'C';
}
}
}
return 'Q';
}
最后根据返回的字符,打印相应的结果。
3.游戏测试
首先我们测试3×3的棋盘,编译并运行程序:
如果需要改变棋盘的大小,只需要改变符号ROW和COL的大小,例如改为4×4的棋盘:
#define ROW 4
#define COL 4
4.代码链接
https://gitee.com/hkjz/for-c/tree/master/tic_tac_toe/tic_tac_toe
标签:int,三子,C语言,++,board,子棋,棋盘,col,row From: https://blog.csdn.net/weixin_58888381/article/details/142261351