准备👏
今晚是个大工程,但是咱不急,工欲善其事,必先利其器,先来看看需要哪些“器”:
1.一大饼函数(随机值rand函数,srand函数,自义定函数……);
2.一小撮头文件:<stdlib.h>,<time.h>,<stdio.h>;
3.格局打开:封装函数,提高可读性与逻辑感;test.c存放main函数,用来当作程序的入口,引用game.h头文件(引用自己写的头文件记得是双引号“game.h”),game.c中存放实现工程的主体函数,game.h中则存放各种函数的声明以及VS提供的头文件的包含;
4.一大堆二维数组的运用;
5.错综的分支与循环语句的嵌套使用;
6.善于分析的脑瓜子和勤快的小手手;
如果以上东西你都没有问题,那我们就不用废话,直接进入正题。
洋葱战略👏
对待问题就要像洋葱一样一层一层一层的剥开,接下来就带大家来剥洋葱
**
1.万金油开头少不了😎
int main() { test(); return 0; }
2.上菜得先上菜单😎
先用一个test函数将菜单唤出来,之所以不写在main函数里面是方便食用。
void test() { int input = 0; srand((unsigned int)time(NULL));//随机数发生器的初始化函数,利用时间戳生成伪随机数 do//至少进行一次该过程 { menu(); printf("请选择菜单:>"); scanf("%d", &input);//将值存入input以实现菜单选择功能 switch (input) { case 1: { printf("三子棋\n"); game();//进入游戏主体 break; } case 0: { printf("即将退出……"); break; } default: { printf("玩儿呢?\n");//防特殊情况防皮 break; } } } while (input);//实现游戏的重复游玩 }
3.游戏的入口——菜单😎
简简单单搞了一个菜单出来,诸君可肆意发挥,我懒惰的天性造就了它平庸的外表。
void menu() { printf("------------------------------------\n"); printf("------------------------------------\n"); printf("-------1.P L A Y-----------\n"); printf("-------0.E X I T-----------\n"); printf("------------------------------------\n"); printf("------------------------------------\n"); }
当你输入“ 1 ”时就正式开始了。
4.游戏主体😎
这里就需要动一下脑筋了,因为需要安排的东西突然就暴涨,制定规则就重在效率与目的并持。
首先在规则之下,需要实现的是三子棋的物质表达,即棋盘的设计,高大上一点就是在搭建游戏环境。棋盘是方的,那我们就用二维数组行列式的相似性来模拟棋盘,这里我设置一个名为 board 的数组。
**
1.棋盘初始化🎉
**
为了能搞出一个棋盘,我得用数据告诉编译器一个棋盘的轮廓:既然是三子棋,我们就先从最简单的3*3开始,分别用ROW(行),COL(列)来指定数组元素。
为了方便写也为了方便读,我们将ROW和COL在game.h头文件中宏定义使用:
# define ROW 3 # define COL 3
这样写也有一个好处,想要改变棋盘大小就会很简单,只需改变数字的大小,无需大费周章的到处去改这改那。
void Printboard(char board[ROW][COL], int row, int col) { int i = 0;//数组下标从0开始 int j = 0; for (i = 0; i < row; i++) { for (j = 0; j < col; j++)//嵌套循环来完成整个数组 { board[i][j] = ' ';//将i行j列的数组初始化为空,用来布局和放入棋子 } } }
2.打印棋盘🎉
**
万事俱备只欠东风,代码直接上:
void Display(char board[ROW][COL], int row, int col) { int i, j = 0; for (i = 0; i < row; i++) { for (j = 0; j < col; j++) { printf(" %c ", board[i][j]);//放入%c以作为棋子位存放棋子 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"); } }
这里自定义的Display函数,效果如下:
棋手操作🎉
**
棋盘搞好了就可以下了嘛,这里要实现下的话,就需要我们玩家的下棋函数和一个24小时在线陪玩的憨憨人机,我们就用 player 函数和 X_MAN函数实现(取名是一种艺术):
void player(char board[ROW][COL], int row, int col)//玩家 { int x = 0;//模拟行数 int y = 0;//模拟列数 printf("玩家请输入棋子坐标:>");坐标模拟棋格 scanf("%d%d", &x, &y); while (1) { if (row >= x && x >= 1 && y >= 1 && y <= col)//界定有效范围 { if (board[x - 1][y - 1] == ' ')//人性化,按玩家眼中的棋盘设计 { board[x - 1][y - 1] = '*';//如果本格为空,则将棋子*放入 Display(board, row, col);//显示当前布局 break; } else { printf("无效棋格,请重新输入\n");//防止占用 break; } } else { printf("你下到棋盘外了!\n");//越界警告 } } }
相比之下,人机就好写一些了;
这里注意两个重点:1.伪随机数初始化函数记得放在上一级函数或者主函数里面;
2.电脑不需要像对玩家一样“ -1”操作,电脑自己是可以识别的;
void x_man(char board[ROW][COL], int row, int col)//人机 { int x = 0; int y = 0; printf("人机下:\n"); while(1) { x = rand() % ROW;//ROW,COL范围0~2,得到0~2随机值 y = rand() % COL;//同理 if (board[x][y] == ' ') { board[x][y] = '#'; Display(board, row, col); break; } } }
判断🎉
**
下棋要判断才有输赢对吧,不然咱就是在和电脑搞打字联谊。
我们就搞一个 winor函数来实现,基本思路是要实现三种情况:
1.玩家赢:
分为横三列赢,竖三列赢,对角线赢。实现条件判断我的思路简单粗暴,就是传递性连着三个元素俩俩相等,最后保证都不为空格就行(其中一个不为空就行);
2.五五开;我们又需要一个Full函数来满足平局的判断,即棋盘下满时并未满足输赢条件我们就给出平局的结果
3.电脑赢;
具体如下:
char winor(char board[ROW][COL], int row, int col) { int i = 0; for (i = 0; i < row; i++) { if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')//横赢 { return board[i][1]; } if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')//竖赢 { return board[1][i]; } } if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ')//对角线赢 { return board[0][0]; } if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != ' ')//对角线赢 { return board[0][2]; } if (1==Full(board, row, col))//Full函数判断平局 { return 'p'; } return 'c'; }
Full函数定义如下:
int Full(char board[ROW][COL], int row, int col) { int i,j = 0; for (i = 0; i < ROW; i++) { for (j = 0; j < COL; j++) { if (board[i][j] == ' ')//有空格则不满足平局继续循环 { return 0; } } } return 1;循环完未发现空格则返回1表示平局 }
当以上步骤完成时,我们代入主体的game函数中进行逻辑组装,如下:
void game() { char board[ROW][COL] = { 0 }; Printboard(board, ROW, COL); //初始化棋盘 Display(board, ROW, COL);//打印棋盘 char ret = 0; while (1)//循环以持续游戏进行 { player(board, ROW, COL);//玩家先走 ret = winor(board, ROW, COL);//进入结果判断 if (ret != 'c')//非“继续”结果跳出 { break; } x_man(board, ROW, COL);//人机后走 ret = winor(board, ROW, COL);//再次判断 if (ret != 'c') { break; } } if (ret == 'p') printf("平局!\n"); else if (ret == '*') printf("你赢了!\n"); else printf("你输了\n");//返回值对应判断三种游戏结果 }
战略总览👏
整个游戏到这里就完成了,给整理出来完整的工程如下:
test.c👏
# include"game.h" void menu() { printf("------------------------------------\n"); printf("------------------------------------\n"); printf("-------1.P L A Y-----------\n"); printf("-------0.E X I T-----------\n"); printf("------------------------------------\n"); printf("------------------------------------\n"); } void game() { char board[ROW][COL] = { 0 }; Printboard(board, ROW, COL); Display(board, ROW, COL); char ret = 0; while (1) { player(board, ROW, COL); ret = winor(board, ROW, COL); if (ret != 'c') { break; } x_man(board, ROW, COL); ret = winor(board, ROW, COL); if (ret != 'c') { break; } } if (ret == 'p') printf("平局!\n"); else if (ret == '*') printf("你赢了!\n"); else printf("你输了\n"); } void test() { int input = 0; srand((unsigned int)time(NULL)); do { menu(); printf("请选择菜单:>"); scanf("%d", &input); switch (input) { case 1: { printf("三子棋\n"); game(); break; } case 0: { printf("即将退出……"); break; } default: { printf("玩儿呢?\n"); break; } } } while (input); } int main() { test(); return 0; }
game.c👏
# define _CRT_SECURE_NO_WARNINGS # include"game.h" 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++) { board[i][j] = ' '; } } } void Display(char board[ROW][COL], int row, int col) { int i, 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"); } } void player(char board[ROW][COL], int row, int col)//玩家 { int x = 0; int y = 0; printf("玩家请输入棋子坐标:>"); scanf("%d%d", &x, &y); while (1) { if (row >= x && x >= 1 && y >= 1 && y <= col) { if (board[x - 1][y - 1] == ' ') { board[x - 1][y - 1] = '*'; Display(board, row, col); break; } else { printf("无效棋格,请重新输入\n"); break; } } else { printf("你下到棋盘外了!\n"); } } } void x_man(char board[ROW][COL], int row, int col)//人机 { int x = 0; int y = 0; printf("电脑走:\n"); while(1) { x = rand() % ROW; y = rand() % COL; //0~2 if (board[x][y] == ' ') { board[x][y] = '#'; Display(board, row, col); break; } } } int Full(char board[ROW][COL], int row, int col) { int i,j = 0; for (i = 0; i < ROW; i++) { for (j = 0; j < COL; j++) { if (board[i][j] == ' ') { return 0; } } } return 1; } char winor(char board[ROW][COL], int row, int col) { int i = 0; for (i = 0; i < row; i++) { if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ') { return board[i][1]; } if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ') { return board[1][i]; } } if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ') { return board[0][0]; } if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != ' ') { return board[0][2]; } if (1==Full(board, row, col)) { return 'p'; } return 'c'; }
game.h👏
#pragma once # define ROW 3 # define COL 3 # include<stdio.h> # include<stdlib.h> # include<time.h> void game(); void Printboard(char board[ROW][COL], int row, int col); void menu(); void Display(char board[ROW][COL], int row, int col); void player(char board[ROW][COL], int row, int col); void x_man(char board[ROW][COL], int row, int col); char winor(char board[ROW][COL], int row, int col);
运行结果如下: