赞
踩
你好,本期内容,纯干货,三子棋详细教程,现在开始!
目录
- #include "game.h"
- void menu()
- {
- printf("********************\n");
- printf("***1.play 0.exit***\n");
- printf("********************\n");
- }
- void game()
- {
- char board[ROW][COL] = { 0 };
- char ret = 0;
- initboard(board, ROW, COL); //初始化棋盘
- printboard(board, ROW, COL); //打印棋盘
- while (1)
- {
- playerdown(board, ROW, COL); //玩家下棋
- ret = is_winner(board, ROW, COL); //判断赢家
- if (ret != 'C')
- {
- break;
- }
- printboard(board, ROW, COL); //打印棋盘
- computerdown(board, ROW, COL); //电脑下棋
- ret = is_winner(board, ROW, COL); //判断赢家
- if (ret != 'C')
- {
- break;
- }
- printboard(board, ROW, COL); //打印棋盘
- }
- if (ret == '*') //判断赢家
- printf("玩家赢\n");
- else if (ret == '#')
- printf("电脑赢\n");
- else if (ret == 'Q')
- printf("平局\n");
- printboard(board, ROW, COL); //打印胜利的战果
- }
-
-
- //主函数
- int main()
- {
- int input = 0;
- srand((unsigned int)time(NULL)); //用于电脑下棋时所需要的随机值
- do
- {
- menu(); //菜单
- printf("请选择:>");
- scanf_s("%d", &input);
- switch (input) //选择
- {
- case 1:
- game(); break;
- case 0:
- printf("退出游戏\n"); break;
- default: //输入1开始游戏,输入0退出游戏
- printf("选择错误,请从新选择\n"); break; //while条件为真则继续,为假终止循环
- } //输入非1非0 从新选择,非0继续循环
- } while (input); //
- return 0;
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
1.main函数内容的框架
- 菜单
- 选择
- 根据选择调用所属函数
2.srand与rand
1.大致内容
srand意思为设置rand的生成器,初始化随机数生成器它是个库函数,头文件为#include <stdlib.h>
详细内容请见:srand参考
rand()生成的是1-RANDMAX(32767)的随机值,头文件与srand一样
详细内容请见: rand参考
2.srand( (unsigned int) time(NULL) )
time设置时间戳(下面会给你讲解),time是一个库函数,头文件#include <time.h>
传参NULL意思为空指针,将time强制转换为无符号整形(unsigned int)
详细内容请见:time参考
时间戳(单位为秒):系统当前时间-系统起始时间
3.game()函数的框架
1.大致内容:
棋盘的初始化需要一个字符类型的二维数组来实现,棋盘的初始内容应当是空格,玩家输入坐标,将某个字符存储到所选坐标x-1,坐标y-1为下标的二维数组内,判断是否赢了,其次电脑利用srand设置的生成器后的rand来设置随机值,利用这个随机值%上棋盘的行数或者列数,得到的值的范围是小于行数的,放心将其作为下标,引用棋盘的二维数组,将咱们自己所设置的字符存入这个二维数组。判断是否赢了,如果赢了,则打印赢家。
2.ROW行与COL列的初始化
由于行与列需要我们自己任意定义,所以我们应当选择更合适的#define来标识符常量,排除需要换行改列的隐患,#define ROW 3 #define COL 3,由于实现整个程序不止test.c源文件要使用ROW行与COL列,我们要把ROW,COL设置在game.h头文件里,在test.c文件头部输入代码#include "game.h",注意:双引号所引用的头文件为咱们自己设置的头文件,尖括号所引用的头文件为库函数所需要的头文件。
- #include <stdio.h> //输入输出头文件
- #include <time.h> //time设置时间戳头文件
- #include <stdlib.h> //rand,srand设置随机值头文件
- #define ROW 5 //行的设置
- #define COL 5 //列的设置
- void initboard(char board[ROW][COL], int row, int col); //初始化棋盘
- void printboard(char board[ROW][COL], int row, int col); //打印棋盘
- void playerdown(char board[ROW][COL], int row, int col); //玩家下棋
- void computerdown(char board[ROW][COL], int row, int col);//电脑下棋
- char is_winner(char board[ROW][COL], int row, int col); //谁是赢家
1.为什么要把这些头文件放在game.h里面?
因为咱的test.c源文件的代码里面包含了game.h的头文件,所以它能够实现game.h里面的功能。
2.头文件与源文件的区别
头文件来声明,源文件来定义。
例如:
#include <stdio.h> int main() { int a = 10; int b = 20; printf("%d\n",add(a, b)); return 0; } int add(int a, int b) { return a + b; }上面的代码控制台会出现:
咱知道程序的扫描是自上而下的,在main函数之前定义add函数是非不可选的,那么如何将其“add未定义,假设外部返回int”的这段话不报告的话,这里就是需要“声明”上线了
#include <stdio.h> int add(int a, int b); //这就是声明,标注其函数的返回类型,函数参数的类型 int main() { int a = 10; int b = 20; printf("%d\n",add(a, b)); return 0; } int add(int a, int b) { return a + b; }
棋盘的执行效果:
board[ROW][COL]中的元素与 | 打印在一行,但 | 有限制条件,就是当j < col - 1 注意:col是COL传参后的临时拷贝,意思为列
其次打印 --- 与 | ,--- 的限制条件是i < row-1,i为行的循环, | 的限制条件为j < col - 1, row为行
1.输入坐标x,y
2.判断该坐标x-1,y-1引用下标后的二维数组那个元素是否为空格,或者是否为电脑所下过的棋子,或者坐标非法,如果条件满足,则执行board[x-1][y-1] = '*';break;
- void playerdown(char board[ROW][COL], int row, int col) //玩家下棋
- {
- int x = 0;
- int y = 0;
- while (1)
- {
- printf("玩家下棋\n");
- printf("请输入坐标:>");
- scanf_s("%d %d", &x, &y);
- if ((x <= row && x - 1 >= 0) || (y <= col && y - 1 >= 0))
- {
- if (board[x - 1][y - 1] == '#')
- {
- printf("坐标已经被占用,请从新输入\n");
- }
- if (board[x - 1][y - 1] == ' ')
- {
- board[x - 1][y - 1] = '*';
- break;
- }
- }
- else
- printf("坐标非法,请从新输入\n");
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
1.初始化x,y
初始化的值为rand%row和rand%col,即大于等于0,小于row或者col的值的范围
2.判断条件
如果满足,赋值'#'
- void computerdown(char board[ROW][COL], int row, int col) //电脑下棋
- {
- int x = rand() % row;
- int y = rand() % col;
- printf("电脑下棋\n");
- while (1)
- {
- if (board[x][y] == ' ')
- {
- board[x][y] = '#';
- break;
- }
- else
- {
- x = rand() % row;
- y = rand() % col;
- }
- }
-
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
1.框架
①横向连线判断
②竖向连线判断
③X型连线判断
2.具体
for (i = 0; i < row; i++) { count = 0; for (j = 0; j < col - 1; j++) { if (board[i][j] == board[i][j + 1] && board[i][j] != ' ' && board[i][j + 1] != ' ') { count++; } } if (count == ROW - 1) { return board[i][0]; } } ①横向连线判断
横向的和行、列都有关系,所以嵌套两层循环,比如第一行,咱需要判断两个紧挨着的1列和2列的内容是否相同,那这需要需要一个变量来计数,我设置整形count,利用count++来计数,那咱这计数也需要判断条件吧,咱知道紧挨着的凑两对的数量极限是board[0][2]吧,那么if条件中的==操作符右值应当撑死是board[0][2],所以你思考一下,j+1中j的值是否是应该撑死是col-1-1,由于我们for循环中j的初值是0,所以判断条件应当是j<col-1。
注意:空格也是存在相同的内容的,所以这里也需要判断该坐标-1后为下标的元素是否是空格,count最终计算的值应当是判断是否相等我们的列-1,如果条件满足,返回这个返回值,设置board[i][0]意思为返回第i行下标为0的元素,这个元素不是#就是*,因为*是玩家,#是电脑.
for (i = 0; i < row; i++) { count = 0; for (j = 0; j < col - 1; j++) { if (board[j][i] == board[j + 1][i] && board[j][i] != ' ' && board[j + 1][i] != ' ') { count++; } } if (count == COL - 1) { return board[0][i]; } }②竖向连线判断
竖向就是先把列固定住,循环行来判断紧邻两个元素是否相等
具体实践就是board[j][i] == board[j+1][i]
并且这两个元素不为空格
与①横向连线判断中的count的计算相同道理,返回值主要与列有关。
//左上-右下 count = 0; for (i = 0; i < col - 1; i++) { if (board[i][i] == board[i + 1][i + 1] && board[i][i] != ' ' && board[i + 1][i + 1] != ' ') { count++; } } if (count == col - 1) return board[0][0];③X型连线判断
1.左上---右下
无非是一层循环判断board[i][i] = board[i+1][i+1]并且两个元素不为空格,再count++;
这里对角线的x与y相等,就好比数学中的函数y=x的图像。
//右上---左下 count = 0; for (i = 0; i < row - 1; i++) { if (board[i][row-1-i] == board[i+1][row-2-i] && board[i][row - 1 - i] != ' ' && board[i + 1][row - 2 - i] != ' ') { count++; } } if (count == col - 1) { return board[i][row-1-i]; }③X型连线判断
2.右上---左下
经过上面一些代码的磨练,这个难度相对较高一点
我们知道这个列是从row-1开始的,行是从0开始的,但是每次循环都是从row-1的列下标开始的吗?答案是:NO!我们总要把列下标与行建立关系吧,所以就有了row-1-i,一层循环就够了,跟1.左上---右下相似,最终返回的值为与咱们判断的需要的任意一个值一样就ok了。
看代码,你就懂了。
- int if_full(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++)
- {
- if (board[i][j] == ' ')
- return 0;
- }
- }
- return 1;
- }
四.game.c源代码:
#include "game.h" /*----------------------------------------------------------------------------------*/ void initboard(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 printboard(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"); for (j = 0; j < col; j++) { if (i < row - 1) { printf("---"); if (j < col - 1) { printf("|"); } } } printf("\n"); } } /*----------------------------------------------------------------------------------*/ void playerdown(char board[ROW][COL], int row, int col) //玩家下棋 { int x = 0; int y = 0; while (1) { printf("玩家下棋\n"); printf("请输入坐标:>"); scanf_s("%d %d", &x, &y); if ((x <= row && x - 1 >= 0) || (y <= col && y - 1 >= 0)) { if (board[x - 1][y - 1] == '#') { printf("坐标已经被占用,请从新输入\n"); } if (board[x - 1][y - 1] == ' ') { board[x - 1][y - 1] = '*'; break; } } else printf("坐标非法,请从新输入\n"); } } /*----------------------------------------------------------------------------------*/ void computerdown(char board[ROW][COL], int row, int col) //电脑下棋 { int x = rand() % row; int y = rand() % col; printf("电脑下棋\n"); while (1) { if (board[x][y] == ' ') { board[x][y] = '#'; break; } else { x = rand() % row; y = rand() % col; } } } int if_full(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++) { if (board[i][j] == ' ') return 0; } } return 1; } /*----------------------------------------------------------------------------------*/ char is_winner(char board[ROW][COL], int row, int col) //谁是赢家 { int i = 0; int j = 0; int count = 0; //行 for (i = 0; i < row; i++) { count = 0; for (j = 0; j < col - 1; j++) { if (board[i][j] == board[i][j + 1] && board[i][j] != ' ' && board[i][j + 1] != ' ') { count++; } } if (count == ROW - 1) { return board[i][0]; } } //列 for (i = 0; i < row; i++) { count = 0; for (j = 0; j < col - 1; j++) { if (board[j][i] == board[j + 1][i] && board[j][i] != ' ' && board[j + 1][i] != ' ') { count++; } } if (count == COL - 1) { return board[0][i]; } } //X //左上-右下 count = 0; for (i = 0; i < col - 1; i++) { if (board[i][i] == board[i + 1][i + 1] && board[i][i] != ' ' && board[i + 1][i + 1] != ' ') { count++; } } if (count == col - 1) return board[0][0]; //左下-右上 count = 0; for (i = 0; i < row - 1; i++) { if (board[i][row-1-i] == board[i+1][row-2-i] && board[i][row - 1 - i] != ' ' && board[i + 1][row - 2 - i] != ' ') { count++; } } if (count == col - 1) { return board[i][row-1-i]; } if (if_full(board, ROW, COL)) { return 'Q'; //Q为平局 } return 'C'; //返回值C为继续 }
本期内容当中的ROW行与COL列可以设置任何无符号整形值,棋盘大小可不止3X3。
那么你应该收获了许多吧,代码哪里需要改正的话,评论区留言,多多指教,共同进步!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。