序言:
想必三子棋大家都玩过吧,回想起小时候在地上用石头画上线,有的用石子儿,有的用树枝,下三子棋,都能玩一天。现在回想起来都是满满的回忆呀。今天带着大家来用C语言,来实现模拟实现一下三子棋游戏,来帮大家找一找童年的记忆。下面进入正题:
一.整体思路
我们三子棋主要实现的原理是,利用字符打印出一个棋盘,用二维数组存储我们下的棋子。先给大家看看什么样的。
大致就是这个样子。
然后一步一步下棋,每下一步,我们就把棋盘打印一边。
二.加载逻辑
首先每次游戏开始我们都需要一个菜单:
菜单代码:
void menu() { printf("*****************************************\n"); printf("************1.play 0.exit*************\n"); printf("*****************************************\n"); }
游戏的加载逻辑,我们希望可以选择游戏开始或者退出,也不是玩完一局就没有了,而是玩完一局以后还可以继续选择玩或者不玩,只有我们选组退出时,程序才会结束。
代码:
void game() { printf("三子棋\n"); }
int main() { int input = 0; do { menu(); printf("请输入选项:>\n"); scanf("%d", &input); printf("\n"); switch (input) { case 1: game(); break; case 0: printf("退出游戏\n"); break; default: printf("输入错误,请重新输入:>\n"); break; } } while (input); return 0; }
运行效果:
设置好游戏的加载逻辑以后,后面的游戏内容就全部在game()函数里面完成。并且我们为了是程序模块化,我们将主函数放到main.c文件里面,函数声明,头文件,宏等,我们就放在game.h文件里面,函数的具体实现我们统统放在,game.c文件里面。这样我们的整体程序就会非常有序,可读性提高。
三.棋盘布置
我们使用宏常量来,规定棋盘的大小 :
#define _CRT_SECURE_NO_WARNINGS 1 #define ROW 3 #define LIN 3 #include<stdio.h> void menu(); void game();
void game() { //创建二维数组 char chess[ROW][LIN] = { 0 }; //初始化用来装棋子的二维数组 init_board(chess,ROW,LIN); //打印棋盘 print_board(chess,ROW,LIN); }
void init_board(char chess[ROW][LIN], int row, int lin) { for (int i = 0; i < row; i++) { for (int j = 0; j < lin; j++) { //二维数组全部初始化位空格 chess[i][j] = ' '; } } }
void print_board(char chess[ROW][LIN],int row,int lin) { for (int i = 0; i < row; i++) { for (int j = 0; j < lin; j++) { //空格 + 棋子 + 空格 + | ,为一组,一共 //需要 lin 组,但是最后一组不需要 | printf(" %c ",chess[i][j]); //控制最后一个 | 不打印 if (j < row - 1) { printf("|"); } } //换行 printf("\n"); // | | //---|---|--- //为一组,一共需要 row 组,但是最后一组,不需要 ---|---|--- if (i < lin - 1) { for (int j = 0; j < row; j++) { // ---| 为一组,一共 row 组,最后一组不需要打印 | printf("---"); if (j < row - 1) { printf("|"); } } } printf("\n"); } }
运行效果:
四.下棋
下棋的主要逻辑实现就是,封装两个函数player_chess()用来表示玩家下棋和电脑下棋computer_board(),玩家输入坐标,并将玩家代表的棋子存入棋盘的二维数组里面,电脑下棋先给他设置成随机下棋,然后每次下完一颗棋子我们就打印一下整个棋盘。我们需要一直下棋,每下一颗棋子都有可能出现胜利的一方,封装一个函数is_win()用来判断是否又人赢了,所以需要每下一颗棋子就需要判断一下是否又赢得玩家,如果又赢得玩家就直接is_win直接返回胜利者的棋子,如果没有人赢就返回‘C’代表继续,如果棋盘已经满了,就返回‘Q’代表平局。
void game() { char set; //随机数生成器 srand((unsigned int)time(NULL)); //创建二维数组 char chess[ROW][LIN] = { 0 }; //初始化用来装棋子的二维数组 init_board(chess,ROW,LIN); //打印棋盘 print_board(chess,ROW,LIN); while (1)//一直循环,直到结果出现输赢,或者平局 { //玩家下棋 player_chess(chess, ROW, LIN ); //打印棋盘 print_board(chess, ROW, LIN); //判断结果 set=is_win(chess,ROW,LIN); if ('C' != set) { break; } //电脑下棋 computer_board(chess, ROW, LIN); //打印棋盘 print_board(chess, ROW, LIN); //判断结果 set = is_win(chess, ROW, LIN); if ('C' != set) { break; } } //如果返回的是玩家代表的棋子, if (set == '*') { printf("恭喜你,你赢了!!\n"); } //如果返回的是电脑代表的棋子 else if ('#' == set) { printf("电脑赢了!!\n"); } //如果是平局 else if ('Q' == set) { printf("平局\n"); } }
void player_chess(char chess[ROW][LIN], int row, int lin) { //计数玩家棋子数量 count_board++; //坐标 int x = 0; int y = 0; while (1) { printf("请输入棋子坐标:>"); scanf("%d %d", &x, &y); //判断坐标合理性,是否在棋盘内 if (x >= 1 && x <= row && y >= 1 && y <= lin) { //坐标位置是否为空 if (chess[x-1][y-1] == ' ') { chess[x-1][y-1] = '*'; break; } else { printf("该位置已有棋子\n"); } } else { printf("棋子坐标错误,请重新输入\n"); } } }
void computer_board(char chess[ROW][LIN], int row, int lin) { while (1)//直到找好位置循环结束。 { //随机数生成,0~2 int x = rand()%row; int y = rand()%lin; //判断是否该位置为空, if (chess[x][y] == ' ') { chess[x][y] = '#'; break; } } }
判断是否有玩家赢is_win()
//判断棋盘是否满了 int is_full(char chess[ROW][LIN], int row, int lin) { for (int i = 0; i < row; i++) { for (int j = 0; j < lin; j++) { if (chess[i][j] == ' ') { return 0; } } } return 1; } char is_win(char chess[ROW][LIN], int row, int lin) { //横着判断是否有三个一样的 for (int 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 (int i = 0; i < lin; i++) { if (chess[0][i] == chess[1][i] && chess[1][i] == chess[2][i] && chess[0][i] != ' ') { return chess[0][i]; } } //斜着判断是否有三个一样的 if (chess[0][0] == chess[1][1] && chess[1][1] == chess[2][2] && chess[0][0] != ' ') { return chess[0][0]; } //斜着判断是否有三个一样的 if (chess[0][2] == chess[1][1] && chess[1][1] == chess[2][0] && chess[0][2] != ' ') { return chess[0][2]; } //判断棋盘是否满了 int tmp = is_full(chess, ROW, LIN); if (tmp == 1) { return 'Q'; } return 'C'; }
这样我们三子棋的主要逻辑就实现了
五.智能化
但是大家发现这电脑傻了吧唧的,现在我们就给他智能化,但是智能化的程度取决于设计者。分析那些情况优先的,就像当你电脑还差一颗棋子就可以赢了,这就是最先考虑的情况,其次是当对手还差一颗棋子赢了,还有电脑下一颗可以达成两颗棋子的领先情况,等等还有一些情况小编不好分析,就不多介绍了。
void computer_board(char chess[ROW][LIN], int row, int lin) { //差一棋子,优先下(1) for (int i = 0; i < row; i++) { if (chess[i][0] == chess[i][1] && chess[i][0] == '#'&& chess[i][2] == ' ') { chess[i][2] = '#'; return; } if (chess[i][0] == chess[i][2] && chess[i][0] == '#'&& chess[i][1] == ' ') { chess[i][1] = '#'; return; } if (chess[i][1] == chess[i][2] && chess[i][1] == '#'&& chess[i][0] == ' ') { chess[i][0] = '#'; return; } } //差一棋子,优先下(2) for (int i = 0; i < lin; i++) { if (chess[0][i] == chess[1][i] && chess[0][i] == '#'&& chess[2][i]==' ') { chess[2][i] = '#'; return; } if (chess[0][i] == chess[2][i] && chess[0][i] == '#'&&chess[1][i] == ' ') { chess[1][i] = '#'; return; } if (chess[1][i] == chess[2][i] && chess[1][i] == '#'&& chess[0][i] == ' ') { chess[0][i] = '#'; return; } } //差一棋子,优先下(3) if (chess[0][0] == chess[1][1] && chess[0][0] == '#' && chess[2][2] == ' ') { chess[2][2] = '#'; return; } if (chess[0][0] == chess[2][2] && chess[0][0] == '#' && chess[1][1] == ' ') { chess[1][1] = '#'; return; } if (chess[2][2] == chess[1][1] && chess[1][1] == '#' && chess[0][0] == ' ') { chess[0][0] = '#'; return; } //差一棋子,优先下(4) if (chess[0][2] == chess[1][1] && chess[0][2] == '#' && chess[2][0] == ' ') { chess[2][0] = '#'; return; } if (chess[0][2] == chess[2][0] && chess[0][2] == '#' && chess[1][1] == ' ') { chess[1][1] = '#'; return; } if (chess[2][0] == chess[1][1] && chess[1][1] == '#' && chess[0][2] == ' ') { chess[0][2] = '#'; return; } //对方差一棋子胜利,优先下(5) for (int i = 0; i < row; i++) { if (chess[i][0] == chess[i][1] && chess[i][0] == '*' && chess[i][2] == ' ') { chess[i][2] = '#'; return; } if (chess[i][0] == chess[i][2] && chess[i][0] == '*' && chess[i][1] == ' ') { chess[i][1] = '#'; return; } if (chess[i][1] == chess[i][2] && chess[i][1] == '*' && chess[i][0] == ' ') { chess[i][0] = '#'; return; } } //对方差一棋子胜利,优先下(6) for (int i = 0; i < lin; i++) { if (chess[0][i] == chess[1][i] && chess[0][i] == '*' && chess[2][i] == ' ') { chess[2][i] = '#'; return; } if (chess[0][i] == chess[2][i] && chess[0][i] == '*' && chess[1][i] == ' ') { chess[1][i] = '#'; return; } if (chess[1][i] == chess[2][i] && chess[1][i] == '*' && chess[0][i] == ' ') { chess[0][i] = '#'; return; } } //对方差一棋子胜利,优先下(7) if (chess[0][0] == chess[1][1] && chess[0][0] == '*' && chess[2][2] == ' ') { chess[2][2] = '#'; return; } if (chess[0][0] == chess[2][2] && chess[0][0] == '*' && chess[1][1] == ' ') { chess[1][1] = '#'; return; } if (chess[2][2] == chess[1][1] && chess[1][1] == '*' && chess[0][0] == ' ') { chess[0][0] = '#'; return; } //对方差一棋子胜利,优先下(8) if (chess[0][2] == chess[1][1] && chess[0][2] == '*' && chess[2][0] == ' ') { chess[2][0] = '#'; return; } if (chess[0][2] == chess[2][0] && chess[0][2] == '*' && chess[1][1] == ' ') { chess[1][1] = '#'; return; } if (chess[2][0] == chess[1][1] && chess[1][1] == '*' && chess[0][2] == ' ') { chess[0][2] = '#'; return; } //抢占先机,下完这一棋子,差一步胜利;(1) for (int i = 0; i < lin; i++) { if (chess[0][i] == '#' && chess[1][i] == ' ' && chess[2][i] == ' ') { chess[1][i] = '#'; return; } if (chess[1][i] == '#' && chess[0][i] == ' ' && chess[2][i] == ' ') { chess[0][i] = '#'; return; } if (chess[2][i] == '#' && chess[0][i] == ' ' && chess[1][i] == ' ') { chess[0][i] = '#'; return; } } //抢占先机,下完这一棋子,差一步胜利;(2) for (int i = 0; i < row; i++) { if (chess[i][0] == '#' && chess[i][1] == ' ' && chess[i][2] == ' ') { chess[i][1] = '#'; return; } if (chess[i][1] == '#' && chess[i][0] == ' ' && chess[i][2] == ' ') { chess[i][0] = '#'; return; } if (chess[i][2] == '#' && chess[i][0] == ' ' && chess[i][1] == ' ') { chess[i][0] = '#'; return; } } //抢占先机,下完这一棋子,差一步胜利;(3) if (chess[0][0] == '#' && chess[1][1] == ' ' && chess[2][2] == ' ') { chess[1][1] = '#'; return; } if (chess[0][0] == ' ' && chess[1][1] == '#' && chess[2][2] == ' ') { chess[2][2] = '#'; return; } if (chess[0][0] == ' ' && chess[1][1] == ' ' && chess[2][2] == '#') { chess[0][0] = '#'; return; } //抢占先机,下完这一棋子,差一步胜利;(4) if (chess[0][2] == '#' && chess[1][1] == ' ' && chess[2][0] == ' ') { chess[1][1] = '#'; return; } if (chess[0][2] == ' ' && chess[1][1] == '#' && chess[2][0] == ' ') { chess[0][2] = '#'; return; } if (chess[0][2] == ' ' && chess[1][1] == ' ' && chess[2][0] == '#') { chess[0][2] = '#'; return; } //第一步棋子,针对 if (count_board == 1 && chess[0][0] == '*') { chess[2][2] = '#'; return; } if (count_board == 1 && chess[0][2] == '*') { chess[2][0] = '#'; return; } if (count_board == 1 && chess[2][0] == '*') { chess[0][2] = '#'; return; } if (count_board == 1 && chess[2][2] == '*') { chess[0][0] = '#'; return; } while (1) { int x = rand()%row; int y = rand()%lin; if (chess[x][y] == ' ') { chess[x][y] = '#'; break; } } }
最后展示成果:
这里我就已经输了,哈哈哈。
最后:
坚守之心就是不为苦难所惧。苦难是成功的磨刀石,是对人的胆识、智慧和毅力的考验。生活的道 路不是一帆风顺的,往往荆棘丛生。不少人就是迈不过这道坎,害怕、退缩、放弃、变向,结果只 能与成功失之交臂。努力成为你最喜欢的那种人,就算不成功,至少你会喜欢这样努力的自己。加油,诸君,山顶见!!!