目录
前言
❤️ :热爱编程学习,期待一起交流!
🙏:博主水平有限,如有发现错误,求告知,多谢!
我们先认识一下本章涉及的英文单词。
row:一行; 一排; ;
col:一列;
Init:初始化
InitBoard:初始化棋盘
DisplayBoard:展览棋盘;展出棋盘;
井字棋又称三子棋。此游戏是对前面C语言知识学习的综合应用,主要包括 函数、数组、的应用。可以算是对前面所学知识的复习巩固,以及形成知识的输出。
相信大家也玩过井字棋,甚至熟练掌握井字棋的棋法并且百战百胜。是的,这就是我的1.0版本,对抗人工智障,你将百战百胜。由于博主知识暂时有限,不能写出一个具有战略头脑的电脑玩家与你斗智斗勇。只能设计出一个胡乱下棋的电脑玩家。没错,就是胡乱下的。但是经过我后期的学习一定会对这个游戏进行优化。
游戏设计思路
这里我们把这个游戏项目整体上分为三个模块
头文件(game.h)c语言中头文件中一般定义了函数的声明、结构体的定义、宏定义。(常量和全局变量最好放到源文件中)
源文件(game.c)在这个源文件中我们放置一些函数。来将游戏的具体实现。 源文件(test.c)里面放主函数和游戏的整体功能。
这样写的好处可以不至于一个游戏直接在一个源文件写几百行,不能及时检查错误,而导致bug频出。
把游戏分为一个个的模块就可以提高代码的可读性,减少错误率。
我们规定人下的棋子为 “x”,电脑下的棋子为 “o”。
为了照顾没有设计过的朋友,在这里我会讲的详细一些。
先按照我们正常的思维来设计。
一、工欲善其事,必先利其器。我们首先需要先设计一个3 * 3的一个棋盘,如上图所示。
二、然后玩家先手下棋。
三、电脑下棋。
四、我们需要在第三个回合判断输赢(就是判断三个棋子是否在一条线上)
五、如果没有分出胜负,我们需要继续进行循环 – 步骤三、四、五。直到判断出输赢,或者平局。
现在我们用程序员的话翻译以上句子是什么意思。
一、生成一个3*3的二维数组,并将二维数组初始化后用符号打印出来。
二、运用二维数组输入两个数字定位棋子落下的位置。
三、运用rand函数生成随机数。对二维数组(即3*3的棋盘)进行遍历。if有空位,就下棋 *
四、判断二维数组上的行,列,十字相交,的位置是否构成一条线。
五、运用循环语句对此进行判断输赢,或平局。
生成菜单界面(do while)
玩过超级玛丽,或者魂斗罗的都知道。我们进入游戏的时候都有一个菜单界面,来选择玩游戏,或者退出游戏。因此在我们进行玩游戏之前,需要用do语句先生成一个菜单来进行选择。
void menu() { printf("————1.play————\n"); printf("————2.exit————\n"); }
初始化棋盘
宏定义:
- 将3用ROW,COL代替。
- 提高扩展性,如果将来要修改棋盘尺寸,代码修改会很方便。
#define ROW 3 #define COL 3
运用循环嵌套,对3 *3的二维数组进行遍历,实现9个格子都是空格。
void DisplayBoard(char board[ROW][COL], int row, int col) { int i = 0;//i 控制行数 int j = 0;//j 控制列数 for (i = 0; i < row; i++)//控制打印的行数 { for (j = 0; j < col; j++)//控制每行的列数 { printf(" %c ", board[i][j]); if (j < col - 1)//col为3,if(j<2),意思就是只打印棋盘的第一列和第二列。 printf("|"); } printf("\n");//每打印一行就需要换行 if (i < row - 1) { for (j = 0; j < col; j++) { printf("---"); if (j < col - 1) printf("+"); } } printf("\n"); } }
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 DisplayBoard(char board[ROW][COL], int row, int col) { int i = 0;//i 控制行数 int j = 0;//j 控制列数 for (i = 0; i < row; i++)//控制打印的行数 { for (j = 0; j < col; j++)//控制每行的列数 { printf(" %c ", board[i][j]); if (j < col - 1)//col为3,if(j<2),意思就是只打印棋盘的第一列和第二列。 printf("|"); } printf("\n");//每打印一行就需要换行 if (i < row - 1) { for (j = 0; j < col; j++) { printf("---"); if (j < col - 1) printf("+"); } } printf("\n"); } }
如图所示
玩家下棋
- 运用if的嵌套
void Player_move(char board[ROW][COL], int row, int col) { int x = 0; int y = 0; printf("请玩家输入(x y)坐标下棋:"); while (1) { scanf("%d%d", &x, &y); if (x >= 1 && x <= row && y >= 1 && y <= col)//对下棋位置进行约定,只能下到3*3的棋盘内。 { if (board[x - 1][y - 1] == ' ')//x-1和y-1的写法就是因为对我们程序员来说数组的元素下标识从0开始的。 {//数组通过下标来访问元素。但是玩家却不懂这个。所以要这么写。 board[x - 1][y - 1] = 'x'; break; } else { printf("坐标已被占用,请重新输入\n"); } } else { printf("坐标非法,请重新输入\n"); } } }
电脑下棋(随机数生成)
- 随机数的生成.要在主函数中使用 srand((unsigned int)time(0))
- 将time作为种子,保证时间的随机性。从而使棋子随机生成。
void Computer_move(char board[ROW][COL], int row, int col) { int x = 0; int y = 0; while (1) { x = rand() % ROW; y = rand() % COL; if (board[x][y] == ' ') { board[x][y] = 'o'; break; } } }
判断输赢
- 规定:
- 返回‘Q’是平局
- 返回‘c’是继续
- 下面是判断三行,三列,还有十字相交是否相同,然后还要继续判断棋盘是否满了,最后才能判断是否输赢。
- 判断棋盘满不满需要调用is_full函数。
char is_win(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][0] == board[i][2] && board[i][0] != ' ') { return board[i][0]; } } for (i = 0; i < col; i++) { if (board[0][i] == board[1][i] && board[0][i] == board[2][i] && board[0][i] != ' ') { return board[0][i]; } } if (board[0][0] == board[1][1] && board[0][0] == board[2][2] && board[0][0] != ' ') { return board[0][0]; } if (board[0][2] == board[1][1] && board[0][2] == board[2][0] && board[0][2] != ' ') { return board[0][2]; } if (1 == is_full(board, row, col)) { return 'Q'; } return 'c'; }
判断是否棋格满了
- 对棋盘进行遍历,如果没有空格,就返回1,为真,则是棋盘满了,然后就返回Q来跳出循环。
int is_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.h
#include<stdio.h> #include<stdlib.h> #include<time.h> #define ROW 3 #define COL 3 void InitBoard(char board[ROW][COL], int row, int col); void DisplayBoard(char board[ROW][COL], int row, int col); void Player_move(char board[ROW][COL], int row, int col); void Computer_move(char board[ROW][COL], int row, int col); char is_win(char board[ROW][COL], int row, int col);
test.c
#include "game.h" void game() { char board[ROW][COL] = { 0 }; InitBoard(board, ROW, COL); DisplayBoard(board, ROW, COL); char ret = 0; while (1) { system("cls"); DisplayBoard(board, ROW, COL); Player_move(board, ROW, COL); ret = is_win(board, ROW, COL); if (ret != 'c') { break; } Computer_move(board, ROW, COL); ret = is_win(board, ROW, COL); if (ret != 'c') { break; } } printf("对抗结果如下:\n"); DisplayBoard(board, ROW, COL); if (ret == 'x') { printf("恭喜你对抗人工智障1.0成功!!!\n"); printf("再来一盘吧?\n"); printf("\n"); } else if (ret == 'o') { printf("不会吧?不会还有人玩不过电脑吧?\n"); printf("再来一盘吧?\n"); printf("\n"); } else { printf("你竟然和电脑旗鼓相当!!!\n"); printf("再来一盘吧?\n"); printf("\n"); } } void menu() { printf("————1.play————\n"); printf("————2.exit————\n"); } void test() { srand((unsigned int)time(NULL)); int n = 0; do { printf("开始游戏请选择输入1\n"); menu(); scanf("%d", &n); switch (n) { case 1: game(); break; case 0: printf("退出游戏\n"); break; default: printf("选择错误请重新选择:\n"); break; } }while (n); } int main() { test(); return 0; }
game. c
#define _CRT_SECURE_NO_WARNINGS #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 DisplayBoard(char board[ROW][COL], int row, int col) { int i = 0;//i 控制行数 int j = 0;//j 控制列数 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_move(char board[ROW][COL], int row, int col) { int x = 0; int y = 0; printf("请玩家输入(x y)坐标下棋:"); while (1) { scanf("%d%d", &x, &y); if (x >= 1 && x <= row && y >= 1 && y <= col) { if (board[x - 1][y - 1] == ' ') { board[x - 1][y - 1] = 'x'; break; } else { printf("坐标已被占用,请重新输入\n"); } } else { printf("坐标非法,请重新输入\n"); } } } void Computer_move(char board[ROW][COL], int row, int col) { int x = 0; int y = 0; while (1) { x = rand() % ROW; y = rand() % COL; if (board[x][y] == ' ') { board[x][y] = 'o'; break; } } } int is_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_win(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][0] == board[i][2] && board[i][0] != ' ') { return board[i][0]; } } for (i = 0; i < col; i++) { if (board[0][i] == board[1][i] && board[0][i] == board[2][i] && board[0][i] != ' ') { return board[0][i]; } } if (board[0][0] == board[1][1] && board[0][0] == board[2][2] && board[0][0] != ' ') { return board[0][0]; } if (board[0][2] == board[1][1] && board[0][2] == board[2][0] && board[0][2] != ' ') { return board[0][2]; } if (1 == is_full(board, row, col)) { return 'Q'; } return 'c'; }
游戏效果图
胜利
失败
- 失败的截图可以自己下去试试哦。
最后,如果你觉得我的文章对你有帮助🎉欢迎关注🔎点赞👍收藏⭐️留言📝。