目录
1.游戏规则
2.设计思路
1.棋盘的初始化
2.打印棋盘
3.玩家操作
4.电脑下棋
6.输赢判断
7.完整代码展示
1.游戏规则
井字棋又叫三子棋,作为童年经典小游戏,相信各位无论是在上课摸鱼亦或者打磨时间的时候一定与小伙伴来过这么几局游戏。游戏规则很简单,玩家只需要在3*3格子棋盘上进行连珠,双方轮流依次下棋,率先在棋盘上连成三子者获胜。
2.设计思路
1.主体思路
作为玩家,我们面对一个游戏首先进入眼帘的是菜单部分,然后根据个人意愿再选择进行游戏或者退出游戏,因此我们可以轻易创建出test.c项目文件并写出以下代码
void menu()
{
printf("***********************************\n");
printf("*********** 1.游戏开始 **********\n");
printf("*********** 0.退出游戏 **********\n");
printf("***********************************\n");
}
void text()
{
int input = 0;
do
{
menu();
printf("请选择:");
scanf("%d ", &input);
switch (input)
{
case 0:
printf("退出游戏\n");
break;
case 1:
printf("开始游戏\n");
game();
break;
default :
printf("选择错误,请重新输入\n");
break;
}
} while (input);
}
int main()
{
text();
return 0;
}
到这里,游戏的框架就完成了一半了,随后我们就需要对game进行详细补充。
要设计game函数内的部分,我们就要先清楚游戏是如何进行的。首先是创建一个3*3的棋盘,在游戏开始前棋盘内为空格,随后展示出棋盘,紧接着玩家下棋,随后电脑下棋;并且在每一次下棋结束后判断输赢。有了这样一个思路,我们就可以轻松的写出
void game()
{
char board[ROW][COL];
char ret = 0;
init_board(board, ROW, COL);//初始化棋盘
print_board(board, ROW, COL);//打印棋盘
while (1)//确保能够重复进行下棋
{
player_move(board, ROW, COL);//玩家操作
print_board(board, ROW, COL);
ret = is_win(board, ROW, COL);//判断输赢
// C-继续游戏 #-电脑获胜,玩家失败 *-玩家胜利 Q-平局
if (ret != 'C')
{
break;
}
computer_move(board, ROW, COL);//电脑操作
print_board(board, ROW, COL);
ret = is_win(board, ROW, COL);
if (ret != 'C')
{
break;
}
}
if (ret == '#')
{
printf("很遗憾,您失败了\n");
}
else if (ret == '*')
{
printf("恭喜您获得胜利\n");
}
else if (ret == 'Q')
{
printf("平局\n");
}
}
(对于board[ROW][COL]中棋盘的变量,为了方便后续更改变量大小,我们可以才用宏定义的方法来创建ROW与COL;当然对于本游戏也可直接写成board[3][3],这里是为了代码更工程化)
#define ROW 3
#define COL 3
//直接修改ROW/COL后的数字即可重新定义变量大小
由于在这里直接引用了我们自定义的函数,因此为了使项目整洁,可以再创建两个项目game.c和game.h前者用来实现自定义函数的内容,后者声明函数。这样我们就需要在test.c和game.c中包含game.h,即
#include "game.h"
//自己创建的头文件用“ ”
//game.h
#define ROW 3
#define COL 3
#include <stdio.h>
void init_board(char board[ROW][COL], int row, int col);
void print_board(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);
而在game.c中,我们就要一步一步实现各个函数内容了。
2.函数设计
前面我们说到函数内容我们要在game.c内完成设计,因此以下内容全部在game.c内进行。
1.棋盘的初始化
我们创建好3*3的二维数组后,在游戏开始前需要棋盘内全部为 ‘空格’ 。对此,我们只需要将棋盘内每一格的内容都设置成 ‘空格’ 即可
void init_board(char board[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}
}
2.打印棋盘
我们希望一个棋盘是这样子的,为了美观我们需要适当加入边界线。而为了达到这个效果,我们可以将棋盘内容与边界线的两行看成一行来进行打印,这样就能写出
void print_board(char board[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
if (i < row - 1)//最后一行不打印
{
printf("---|---|---\n");
}
}
}
到这里棋盘打印的函数就创建好了,但是存在一个弊端
row和col确定的。而为了程序的严谨性,我们需要重新设计函数内容。
怎么办呢?显然,我们只需要依次打印出每一个格子的内容即可,从而产生了
void print_board(char board[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
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");
}
}
3.玩家操作
我们希望在这一个函数中实现玩家落子(‘ * ’),而对于玩家给出的落子位置,我们也需要对其进行判断合理性。同时,数组下标是从0开始的,因此对于玩家所下位置我们需要-1来得到合理的下标。
void player_move(char board[ROW][COL], int row, int col)
{
printf("玩家请下棋\n");
while (1)
{
printf("请输入所下位置坐标: ");
int x = 0;
int y = 0;
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] = '*';
break;
}
else
{
printf("该位置被占用,请重新选择坐标\n");
}
}
else
{
printf("输入坐标不合理,请重新输入正确坐标\n");
}
}
}
4.电脑下棋
对于电脑下棋,思路和玩家下棋其实差不多,但是也存在差异。首先电脑可以识别从0开始的下标,因此我们也就不必要进行-1操作了;其次电脑落子位置随机,也就需要产生随机数,而说到随机数我们很容易想到time函数这样也就能写出
//game.h
#include <stdlib.h>
#include <time.h>
//修改test.c的内容
void text()
{
srand((unsigned int)time(NULL));//time函数作为随机值的调用
int input = 0;
do
{
menu();
printf("请选择:");
scanf("%d ", &input);
switch (input)
{
case 0:
printf("退出游戏\n");
break;
case 1:
printf("开始游戏\n");
game();
break;
default :
printf("选择错误,请重新输入\n");
break;
}
} while (input);
}
//game.c
void computer_move(char board[ROW][COL], int row, int col)
{
printf("电脑下棋\n");
while (1)
{
int x = rand() % row;//将随机值的范围固定在0~3之间
int y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
6.输赢判断
为了让游戏能够完整,我们在最后加入判断游戏输赢的函数。这一步需要判断相邻的三个元素是否相同且不为空,这里就很简单了,不难写出
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][1] == board[i][2] && board[i][0] != ' ')
{
return board[i][0];//返回的#或者*在test.c的game函数中直接作为判断条件
}
}
for (i = 0; i < col; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
{
return board[0][i];
}
}
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
{
return board[1][1];
}
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
{
return board[1][1];
}
}
到这里我们判断完了游戏的输赢,但是还存在平局的情况。而所谓平局也就是棋盘填满且没有三子相连的情况,这里我们可以创建函数is_full来判断,而这个函数我们只需要在game.c中实现就可以,因此不需要在game.h中进行声明。对于is_full我们可以写出
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][1] == board[i][2] && board[i][0] != ' ')
{
return board[i][0];
}
}
for (i = 0; i < col; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
{
return board[0][i];
}
}
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
{
return board[1][1];
}
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
{
return board[1][1];
}
if (is_full(board, row, col) == 1)
{
return 'Q';
}
return 'C';
}
7.完整代码展示
//test.c
#include "game.h"
void menu()
{
printf("***********************************\n");
printf("*********** 1.游戏开始 **********\n");
printf("*********** 0.退出游戏 **********\n");
printf("***********************************\n");
}
void game()
{
char board[ROW][COL];
char ret = 0;
init_board(board, ROW, COL);
print_board(board, ROW, COL);
while (1)
{
player_move(board, ROW, COL);
print_board(board, ROW, COL);
ret = is_win(board, ROW, COL);
if (ret != 'C')
{
break;
}
computer_move(board, ROW, COL);
print_board(board, ROW, COL);
ret = is_win(board, ROW, COL);
if (ret != 'C')
{
break;
}
}
if (ret == '#')
{
printf("很遗憾,您失败了\n");
}
else if (ret == '*')
{
printf("恭喜您获得胜利\n");
}
else if (ret == 'Q')
{
printf("平局\n");
}
}
void text()
{
srand((unsigned int)time(NULL));
int input = 0;
do
{
menu();
printf("请选择:");
scanf("%d ", &input);
switch (input)
{
case 0:
printf("退出游戏\n");
break;
case 1:
printf("开始游戏\n");
game();
break;
default :
printf("选择错误,请重新输入\n");
break;
}
} while (input);
}
int main()
{
text();
return 0;
}
//game.h
#define ROW 3
#define COL 3
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void init_board(char board[ROW][COL], int row, int col);
void print_board(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);
//game.c
#include "game.h"
void init_board(char board[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}
}
void print_board(char board[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
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)
{
printf("玩家请下棋\n");
while (1)
{
printf("请输入所下位置坐标: ");
int x = 0;
int y = 0;
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] = '*';
break;
}
else
{
printf("该位置被占用,请重新选择坐标\n");
}
}
else
{
printf("输入坐标不合理,请重新输入正确坐标\n");
}
}
}
void computer_move(char board[ROW][COL], int row, int col)
{
printf("电脑下棋\n");
while (1)
{
int x = rand() % row;
int y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
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][1] == board[i][2] && board[i][0] != ' ')
{
return board[i][0];
}
}
for (i = 0; i < col; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
{
return board[0][i];
}
}
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
{
return board[1][1];
}
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
{
return board[1][1];
}
if (is_full(board, row, col) == 1)
{
return 'Q';
}
return 'C';
}
以上就是完整的井字棋游戏设计思路,相信大家看完之后稍加思考也能独立写出属于自己的“井字棋”。