目录
🍨注意下面写的函数基本上都是定义放在game.c而声明放在game.h中。
读者最好具有一定的C语言基础,本文分享一波用C语言简单地做个三子棋小游戏,希望对你有所帮助,由于笔者水平有限,难免会有纰漏,读者各取所需即可。
分三个文件,game.c放入主要的实现游戏逻辑的函数,game.h放入头文件包含、函数声明、宏常量,而test.c作为主文件。
我们一点一点来实现。
首先,进入游戏不都会有菜单界面嘛,虽然我们现在用的还是“黑框框”,但是好歹也是在写游戏嘛,那就写个菜单函数吧。
目前也就游玩和退出两个选项。
- void menu()
- {
- printf("*********** 三子棋 **********\n");
- 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();
- break;
- case 0:
- printf("退出游戏!\n");
- break;
- default :
- printf("选择有误,请重新选择!\n");
- break;
- }
-
- } while (input);
-
- return 0;
- }
使用do…while结构,input接收用户的选择,switch实现分支。
然后具体的游戏逻辑的实现交由函数game实现,实际上是将逻辑细分后封装成若干个函数后再在game函数中组织。
我们既然要下棋,那需要把每一步棋都存起来,这里考虑用一个二维字符数组chess存储棋盘上棋的信息,需要注意的是,我们最好使用常量宏来定义数组大小,一来能保证数组大小不易写错,二来方便更改,比如实现三子棋后想要实现五子棋,就不需要到处改,只需要在宏处修改即可。
所以定义宏ROW和COL分别对应行和列大小(放在头文件game.h中)。
- #define ROW 3
- #define COL 3
char chess[ROW][COL];//存储棋盘中棋的信息
棋盘一开始是空的嘛,也就是说初始时chess中的元素要全为空格咯,这样的话就写一个初始化函数InitChess。
- void InitChess(char chess[ROW][COL], int row, int col)
- {
- int i = 0;
- int j = 0;
-
- for (i = 0; i < row; i++)
- {
- for (j = 0; j < col; j++)
- {
- chess[i][j] = ' ';
- }
- }
- }
好了,那棋盘呢?棋盘不需要用数组存吗?不了,我们这里直接把棋盘的打印封装成函数DisplayBoard,打印当前棋盘和棋的信息。
当然,对于棋盘的设计可以有多种思路,这里笔者使用的是这种类型的棋盘:

代码:
- void DisplayBoard(char chess[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 ", chess[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");
- }
-
- }
这样设计即使是五子棋甚至N子棋都能适应,只需要修改宏ROW和COL即可,比如:

接下来就要实现下棋的逻辑了,分别是玩家下棋和电脑下棋。
注意一下,我们这里使用以下这种坐标表示法:

封装一个PlayerMove函数,所谓下棋不就是把chess数组中对应下标的值修改成“棋”嘛,我们这里用*表示玩家下的棋,要注意的是数组下标是从0开始的,而玩家一般都是从(1,1)开始下棋的,如图:

同时还要记得判断一下输入坐标的有效性,包括是否越界以及当前位置是否已经下过棋(判断空格),输入的坐标有误的话重新输入。
- void PlayerMove(char chess[ROW][COL], int row, int col)
- {
- int x = 0;
- int y = 0;
-
- while (1)
- {
- printf("请输入要下棋的坐标位置:>");
- scanf("%d %d", &x, &y);
-
- if (x >= 1 && y >= 1 && x <= COL && y <= ROW && chess[y-1][x-1] == ' ')
- {
- chess[y-1][x-1] = '*';
- break;
- }
- else
- {
- printf("坐标无效,请重新输入!\n");
- }
- }
-
- }
封装一个ComputerMove函数,这里暂时让电脑“笨”一点,使用伪随机数,模拟随机找个空位下棋。
srand()设置种子在主函数main中设置一次即可。随机生成的坐标位置上不一定是空的,加个循环确保能把棋下进去。
- void ComputerMove(char chess[ROW][COL], int row, int col)
- {
-
- while (1)
- {
- int x = rand() % (col - 1);
- int y = rand() % (row - 1);
- if (chess[y][x] == ' ')
- {
- chess[y][x] = '#';
- break;
- }
- }
-
- }
到目前为止,game函数里的逻辑如下:
- void game()
- {
- char chess[ROW][COL];//存储棋盘中棋的信息
- InitChess(chess, ROW, COL);//初始化棋的信息
- DisplayBoard(chess, ROW, COL);//打印棋盘和棋的信息
-
- while (1)
- {
- PlayerMove(chess, ROW, COL);//玩家下棋
- DisplayBoard(chess, ROW, COL);//打印棋盘和棋的信息
- ComputerMove(chess, ROW, COL);//电脑下棋
- DisplayBoard(chess, ROW, COL);//打印棋盘和棋的信息
- }
-
-
- }
现在我们已经实现了下棋,接着我们就要来实现状态更新了。
我们用一个函数来判断当前游戏情况,并根据情况返回不同的值来表示。
游戏状态主要有这几种:
玩家赢 *
电脑赢 #
平局 Q
继续游戏 C
分别用这几个字符来代表当前游戏状态,每次下完棋后都判断一次。
只要不是返回'C'就说明游戏结束,跳出循环,进一步再来判断是什么具体情况。
- void game()
- {
- char ret = 0;
- char chess[ROW][COL];//存储棋盘中棋的信息
-
- InitChess(chess, ROW, COL);//初始化棋的信息
- DisplayBoard(chess, ROW, COL);//打印棋盘和棋的信息
-
- while (1)
- {
- PlayerMove(chess, ROW, COL);//玩家下棋
- if ((ret = JudState(chess, ROW, COL)) != 'C')
- break;
- DisplayBoard(chess, ROW, COL);//打印棋盘和棋的信息
-
- ComputerMove(chess, ROW, COL);//电脑下棋
- if ((ret = JudState(chess, ROW, COL)) != 'C')
- break;
- DisplayBoard(chess, ROW, COL);//打印棋盘和棋的信息
- }
-
- if ('*' == ret)
- {
- printf("玩家赢!\n");
- }
- else if ('#' == ret)
- {
- printf("电脑赢!\n");
- }
- else
- {
- printf("平局了!\n");
- }
-
- DisplayBoard(chess, ROW, COL);
- }
先判断是否有人胜出,分为行、列和正反对角线的的判断,只要三个连着相同并且不是空格就说明有人取胜了,为了省事,直接就返回数组元素,免得用if判断。正好前面设计的*代表玩家赢和#代表电脑赢就对应上了。
要是没人赢的话就判断一下是否平局了,很简单,写一个函数IsFilled判断一下棋盘满了没有,满了还没人取胜就是平局了,而如果没满的话说明游戏还要继续。
- int IsFilled(char chess[ROW][COL], int row, int col)
- {
- int i = 0;
- int j = 0;
- int flag = 1;
-
- for (i = 0; i < row; i++)
- {
- for (j = 0; j < col; j++)
- {
- if (chess[i][j] == ' ')
- flag = 0;
- }
- }
-
- return flag;
- }
-
- char JudState(char chess[ROW][COL], int row, int col)
- {
- int i = 0;
- int j = 0;
- //是否有人胜出
- //行判断
- for (i = 0; i < row; i++)
- {
- if (chess[i][0] == chess[i][1] && chess[i][1] == chess[i][2] && chess[i][0] != ' ')
- {
- return chess[i][0];
- }
- }
- //列判断
- for (j = 0; j < col; j++)
- {
- if (chess[0][j] == chess[1][j] && chess[1][j] == chess[2][j] && chess[0][j] != ' ')
- {
- return chess[0][j];
- }
- }
- //对角线判断
- if (chess[0][0] == chess[1][1] && chess[1][1] == chess[2][2] && chess[1][1] != ' ' )
- {
- return chess[1][1];
- }
- if(chess[0][2] == chess[1][1] && chess[2][0] == chess[1][1] && chess[1][1] != ' ')
- {
- return chess[1][1];
- }
-
- //是平局还是继续
- if (IsFilled(chess, ROW, COL))
- {
- return 'Q';
- }
- else
- {
- return 'C';
- }
- }
- #include<stdio.h>
- #include<stdlib.h>
- #include<time.h>
-
- #define ROW 3
- #define COL 3
-
- void InitChess(char chess[ROW][COL], int row, int col);
-
- void DisplayBoard(char chess[ROW][COL], int row, int col);
-
- void PlayerMove(char chess[ROW][COL], int row, int col);
-
- void ComputerMove(char chess[ROW][COL], int row, int col);
-
- char JudState(char chess[ROW][COL], int row, int col);
- #include"game.h"
-
- void InitChess(char chess[ROW][COL], int row, int col)
- {
- int i = 0;
- int j = 0;
-
- for (i = 0; i < row; i++)
- {
- for (j = 0; j < col; j++)
- {
- chess[i][j] = ' ';
- }
- }
- }
-
- void DisplayBoard(char chess[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 ", chess[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 PlayerMove(char chess[ROW][COL], int row, int col)
- {
- int x = 0;
- int y = 0;
-
- while (1)
- {
- printf("请输入要下棋的坐标位置:>");
- scanf("%d %d", &x, &y);
-
- if (x >= 1 && y >= 1 && x <= COL && y <= ROW && chess[y-1][x-1] == ' ')
- {
- chess[y-1][x-1] = '*';
- break;
- }
- else
- {
- printf("坐标无效,请重新输入!\n");
- }
-
- }
-
- }
-
- void ComputerMove(char chess[ROW][COL], int row, int col)
- {
-
- while (1)
- {
- int x = rand() % (col - 1);
- int y = rand() % (row - 1);
- if (chess[y][x] == ' ')
- {
- chess[y][x] = '#';
- break;
- }
- }
-
- }
-
- int IsFilled(char chess[ROW][COL], int row, int col)
- {
- int i = 0;
- int j = 0;
- int flag = 1;
-
- for (i = 0; i < row; i++)
- {
- for (j = 0; j < col; j++)
- {
- if (chess[i][j] == ' ')
- flag = 0;
- }
- }
-
- return flag;
- }
-
- char JudState(char chess[ROW][COL], int row, int col)
- {
- int i = 0;
- int j = 0;
- //是否有人胜出
- //行判断
- for (i = 0; i < row; i++)
- {
- if (chess[i][0] == chess[i][1] && chess[i][1] == chess[i][2] && chess[i][0] != ' ')
- {
- return chess[i][0];
- }
- }
- //列判断
- for (j = 0; j < col; j++)
- {
- if (chess[0][j] == chess[1][j] && chess[1][j] == chess[2][j] && chess[0][j] != ' ')
- {
- return chess[0][j];
- }
- }
- //对角线判断
- if (chess[0][0] == chess[1][1] && chess[1][1] == chess[2][2] && chess[1][1] != ' ' )
- {
- return chess[1][1];
- }
- if(chess[0][2] == chess[1][1] && chess[2][0] == chess[1][1] && chess[1][1] != ' ')
- {
- return chess[1][1];
- }
-
- //是平局还是继续
- if (IsFilled(chess, ROW, COL))
- {
- return 'Q';
- }
- else
- {
- return 'C';
- }
- }
- #include"game.h"
-
- void menu()
- {
- printf("*********** 三子棋 ***********\n");
- printf("******************************\n");
- printf("********** 1. play ***********\n");
- printf("********** 0. exit ***********\n");
- printf("******************************\n");
-
- }
-
- void game()
- {
- char ret = 0;
- char chess[ROW][COL];//存储棋盘中棋的信息
-
- InitChess(chess, ROW, COL);//初始化棋的信息
- DisplayBoard(chess, ROW, COL);//打印棋盘和棋的信息
-
- while (1)
- {
- PlayerMove(chess, ROW, COL);//玩家下棋
- if ((ret = JudState(chess, ROW, COL)) != 'C')
- break;
- DisplayBoard(chess, ROW, COL);//打印棋盘和棋的信息
-
- ComputerMove(chess, ROW, COL);//电脑下棋
- if ((ret = JudState(chess, ROW, COL)) != 'C')
- break;
- DisplayBoard(chess, ROW, COL);//打印棋盘和棋的信息
- }
-
- if ('*' == ret)
- {
- printf("玩家赢!\n");
- }
- else if ('#' == ret)
- {
- printf("电脑赢!\n");
- }
- else
- {
- printf("平局了!\n");
- }
-
- DisplayBoard(chess, ROW, COL);
- }
-
- 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;
- }
感谢观看,阁下何不成人之美,关注收藏点赞走一波~
