C语言实现三子棋程序
本文实例为大家分享了C语言实现三子棋的具体代码,供大家参考,具体内容如下
先直接上代码:
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> //2.实现三子棋游戏。 #include<Windows.h> //Sleep() RAND_MAX 的头文件 void menu() //打印菜单 { printf("****************************\n"); printf("**** 欢迎来到三子棋游戏 ****\n"); printf("**** 1、 进入游戏 ****\n"); printf("**** 0、 退出游戏 ****\n"); printf("****************************\n"); printf("请输入:->"); } void print_chessboard(char coord[][3]) //打印棋盘函数 { //多维数组在传参时,接收数组的形参最多只能是第一个方括号里没有数字(下标范围) //否则就会出错(因为此时编译器不知道你要把传过来的数组的元素划分成几行几列, //但是当除第一个方括号的其他方括号都有值时,就可以经过计算知道第一个方括号的值是多少 int i = 0; int index_x = 0; int index_y = 0; for (i = 1; i <= 153; i++) { char out_ch = ' '; if ((i % 51 == 20) || (i % 51 == 26) || (i % 51 == 32) ) { out_ch = coord[index_x][index_y]; index_x++; if (index_x < 3) { index_x = 0; index_y++; } } else if ((i % 17 == 6) || (i % 17 == 12)) { out_ch = '|'; } else if( (i >= 35 && i <= 51 && i != 40 && i != 46) || \ (i >= 86 && i <= 102 && i != 91 && i != 97)) { out_ch = '_'; } putchar(out_ch); if (i % 17 == 0) //每输出 17 个字符换下一行输出 { printf("\n"); } } } void winer(char coord[][3], int *flag); //赢家判断函数的声明 int computer(char coord[][3]) //电脑下棋 { int flag = 0; int index_x2 = 0; int index_y2 = 0; srand((unsigned)time(NULL)); while (1) { index_x2 = 2 * rand() / RAND_MAX; //产生 0--2 的随机数 index_y2 = 2 * rand() / RAND_MAX; if ((coord[index_x2][index_y2] != '*') && (coord[index_x2][index_y2] != 'o')) { //判断该位置是否已有落子 coord[index_x2][index_y2] = 'o'; winer(coord, &flag); if (flag == 1) { return 1; } return 0; } } } int player(char coord[][3], int index_x1, int index_y1) //玩家下棋 { int flag = 0; int ret = 0; if ((coord[index_x1][index_y1] == '*') || (coord[index_x1][index_y1] == 'o')) { //判断该位置是否已有落子 printf("此位置已有棋子,请重下!\n"); return 0; } else { coord[index_x1][index_y1] = '*'; winer(coord, &flag); if (flag == 1) { return 1; } ret = computer(coord); if (ret == 1) { return 1; } print_chessboard(coord); //把打印棋盘放在是因为想在两人都走完一次后再打印当前棋盘状态 } return 0; } void winer(char coord[][3],int *flag) //判断是否产生赢家,赢家是谁 { char line_ch[8][4] = { { coord[0][0], coord[1][1], coord[2][2] }, { coord[0][0], coord[0][1], coord[0][2] }, \ { coord[0][0], coord[1][0], coord[2][0] }, { coord[0][1], coord[1][1], coord[2][1] }, \ { coord[0][2], coord[1][2], coord[2][2] }, { coord[1][0], coord[1][1], coord[1][2] }, \ { coord[2][0], coord[2][1], coord[2][2] }, { coord[0][2], coord[1][1], coord[2][0] } }; //把所有能赢的情况定义成一个字符串数组 int i = 0; for (i = 0; i < 8; i++) { if (strcmp(line_ch[i],"***") == 0) //判断此时玩家已输入的落子能不能组成一个使玩家能赢的字符串 { print_chessboard(coord); //先打印棋盘,再判断谁胜谁负 printf("\n恭喜您赢了!\n"); *flag = 1; //玩家赢,使最开始设置的赢的标志位为1,结束此次游戏 return; } else if (strcmp(line_ch[i],"ooo") == 0) { print_chessboard(coord); printf("\n很遗憾,您输了!\n"); *flag = 1; return; } else { ; } } } int main() { while (1) { int num = 0; //决定开始或退出游戏 int x = 0; int y = 0; int i = 4; //一次游戏最多的内层while循环可循环的次数 int ret = 0; //是否结束此次游戏的标志位 int is_play = 0; //是否再次玩游戏的标志位 char coordinate[3][3] = { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' }; //为了拓展游戏比较方便,可以把行和列定义成宏定义 menu(); scanf("%d", &num); if (num == 0) { printf("5秒后退出程序!\n"); Sleep(5000); exit(0); } computer(coordinate); //因为设计电脑智商低,所以游戏开始前先让电脑落一子 print_chessboard(coordinate); while ((i)) //因为总共有九个位置可以落子,已用一个,还剩八个,每次循环不结束的话会用掉两个 //所以最多循环四次 { printf("请输入 X、Y 的坐标(0--2)来确定你下棋的位置:"); //也可以加一个判断输入是否合法 scanf("%d %d", &x, &y); ret = player(coordinate, x, y); if (ret == 1) { break; } i--; } printf("\n"); printf("请选择接下来的操作:\n"); printf("1、 再玩一次游戏 0、退出游戏系统\n"); scanf("%d", &is_play); if(is_play == 0) { printf("5秒后退出程序!\n"); Sleep(5000); exit(0); } else { system("cls"); } } system("pause"); return 0; }
程序一共设计了六个函数,一个主函数,五个自定义函数― 菜单打印函数、棋盘打印函数、电脑下棋函数、玩家下棋函数、赢家判断函数。
其中最难设计的就是棋盘打印函数和赢家判断函数。这两个函数需要完成的任务多,计算量大,逻辑设计麻烦。
下面来分析一下几个函数的设计思路:
1.菜单打印函数
这个函数很简单,一看就能明白,这儿就不多说了。
2.棋盘打印函数
首先得构思一下三子棋的棋盘应该是什么样
简单点,上图就可以作为三子棋棋盘(其实就是利用 putchar() 函数和 printf() 把显示在屏幕上的字符一个个,一行行打印上去)。设计时可把其分成四部分来看,(1) 短竖杠 ; (2) 短横杠 ; (3) 棋子(用一个二维字符数组来定义每一个棋子,用二维是因为方便输入的 X 和 Y 值与数组下标对应) ; (4) 空格(一开始打印的时候,因为还没有落子,所以把棋子也设计成空格)。 先确定要输入几行几列字符,以确定循环输出的次数,还有确定每个位置该输出的字符,这样就可以依靠循环和判断打印出棋盘了。
3 . 赢家判断函数
在每次落子后都要先进行一次判断,看是否已经产生赢家了。
因为会出现赢家的情况就八种―――?C
{ coord[0][0], coord[1][1], coord[2][2] }, { coord[0][0], coord[0][1], coord[0][2] },
{ coord[0][0], coord[1][0], coord[2][0] }, { coord[0][1], coord[1][1], coord[2][1] },
{ coord[2][0], coord[2][1], coord[2][2] }, { coord[1][0], coord[1][1], coord[1][2] },
{ coord[2][0], coord[2][1], coord[2][2] }, { coord[0][2], coord[1][1], coord[2][0] }
定义一个字符串数组,里面共有八个字符串,每一个字符串就是上面的一个花括弧里的内容,当某个字符串的内容与 * 或 ooo 相等,那么说明产生赢家了,否则不会产生赢家,那么就用一个循环,遍历字符串数组里的每一个字符串,判断是否会产生赢家。
4. 玩家下棋函数
玩家通过输入 x,y 坐标来确定落子的位置, x,y 对应的就是 定义的棋子二维字符数组的下标,每次先判断输入的 x,y 值对应数组下标的元素是否是 * 或 o ,是的话就说明此处已有落子,得重新输入,不是的话就落下该棋子,接着判断是否产生赢家,是的话就结束此次游戏,不是的话就判断棋盘上是否还有空位置没落子,有的话就轮到电脑继续落子,没有的话就结束此次游戏。
5. 电脑下棋函数
因为电脑是自动落子,所以得为电脑产生一个随机的 棋子二维数组下标值,使电脑随机落子,这个用srand((unsigned)time(NULL)); index_x2 = 2 * rand() / RAND_MAX; index_y2= 2 * rand() / RAND_MAX;来实现把它们放在一个while 死循环里,因为可能产生的两个随机下标那儿已经有棋子了,需要重新产生一次随机下标,当下标值与已落棋子不冲突时,就落下该棋子,接着判断是否产生赢家,是的话,就结束此次游戏,不是的话就判断棋盘上是否还有空位置没落子,有的话就轮到玩家继续落子,没有的话就结束此次游戏。
6. 主函数
在主函数里适当调用以上定义的几个函数,实现正确的逻辑功能。