我相信很多人都玩过这个经典的小游戏,它规则简单且有趣,但是为了严谨性和便于思路梳理,我还是再赘述一下这个游戏/doge
这是一张井字棋盘,显然,棋盘是一个九宫格,有9个落棋点。游戏开始,O方或者X方玩家任意一方先落子在棋盘上,每次一颗占一格,双方交替进行,直至有一方玩家的棋子横纵斜“三星一线”时,取得游戏胜利,当然也会出现平局。
由上文知,我们的井字棋需要一个棋盘,我们必须先制作一个棋盘,在C语言中,像九宫格这样的规则平面方格图形,我们都有一个很棒的工具可以实现,那就是二维数组。同时利用数组可以存值的特性,棋子和棋盘的问题我们就都有了下手的地方。
有了棋盘和棋子,我们就可以开始玩我们的游戏了,玩家可以通过输入一个二维坐标把值传到数组里来下棋,而电脑则随机下棋即可(由于现在能力有限,我只能做出这样的“人工智障”,“人工智障不会根据你下的棋来判断它应该如何落子,而是通过随机值下棋”。等日后程度更深的时候,我会回来把它完善!)。
整体的思路好像已经很清楚了,至于实现的细节,我觉得在过程中提及会更好。
void meun()
{
printf("**************************\n");
printf("******** 1.play ********\n");
printf("******** 0.exit ********\n");
printf("**************************\n");
}
int main()
{
do
{
meun();
printf("请选择:");
scanf("%d", &choose);
switch (choose)
{
case 1: //玩家键入“1”,玩游戏,进入我们的游戏函数game()
game();
break;
case 0:
printf("退出游戏\n");
break;
default: //玩家键入了非“1”,“0”的数字,需要重新键入
printf("选择有误,请重新选择!\n");
break;
}
} while (choose); //选择0-1的好处体现了
return 0;
}
char board[3][3];
我相信很多初学者者会如是编写,其实我们在初学的时候就应该养成一个好习惯,尽量少放一些固定的需求变量进入代码,这样当我们需要修改这些变量来改变游戏参数的时候会很麻烦,这里我推荐再创建一个头文件game.h来定义一些参数,当我们需要使用这些参数时,只需要在对应的程序中引用这个头文件即可。同时,修改这些参数也会十分方便。
#pragma once
#include
#define ROW 3
#define LINE 3
game.h还可以帮助我们存放一些函数的声明,只需要在使用函数的地方引用它即可。同时我们还可以将别的多文件使用的头文件放进game.h里,这样做我们在使用它们时只需要引用我们的game.h即可,比如这里我将标准输入输出函数库的头文件就放入其中,非常好用~
void Init_board(char board[ROW][LINE], int row, int line)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < line; j++)
board[i][j] = ' ';
}
}
遍历整个数组中的元素,并把数组中的元素全部打印空格
void Show_board(char board[ROW][LINE], int row, int line)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < line; j++)
{
if (j != line - 1)
printf(" %c |", board[i][j]); //设计棋盘分割线我使用了两种不同写法,这是第一种,也是棋盘内容和纵向分割线
else
printf(" %c ", board[i][j]);
}
printf("\n");
if (i != row - 1) //这是第二种,也是水平分割线和从向分割线
{
for (j = 0; j < line; j++)
{
printf("---");
if (j != line - 1)
printf("|");
}
printf("\n");
}
}
}
这里的难点在于棋盘界面设计的美观性,起初我很是头疼如何设计出格子可以存放数据,后来受人指点才发觉可以将分割线当作数组元素中的一部分打印呈现,这样就能很好的划分棋盘且能存放数据。
打印出的效果是这样的:
由于先前在game.h中定义了ROW和LINE,我们可以随时修改它来改变棋盘大小。
#pragma once
#include
#define ROW 3
#define LINE 3
//声明函数:
void Init_board(char board[ROW][LINE], int row, int line);
void Playermove(char board[ROW][LINE], int row, int line);
void Computermove(char board[ROW][LINE], int row, int line);
void Show_board(char board[ROW][LINE], int row, int line);
玩家下棋:
void Playermove(char board[ROW][LINE], int row, int line)
{
int i = 0;
int j = 0;
while (1)
{
printf("轮到你下了(输入落子坐标以继续):");
scanf("%d %d", &i, &j);
if ((i >= 1) && (i <= row) && (j >= 1) && (j <= line))
{
if (board[i - 1][j - 1] == ' ')
{
board[i - 1][j - 1] = 'o';
break;
}
else
printf("该位置已经有棋子占用!重新输入\n");
}
else
printf("坐标非法!请重新输入\n");
}
}
电脑下棋:
void Computermove(char board[ROW][LINE], int row, int line)
{
int x = 0;
int y = 0;
printf("轮到电脑下:\n");
while (1)
{
x = rand() % row;
y = rand() % line;
if (board[x][y] == ' ')
{
board[x][y] = 'x';
break;
}
}
}
就像我开始说的一样,电脑下棋的操作是完全随机的,也就是我们常调侃的“人工智障”。那么如何随机下棋呢?我们需要随机给定下标,使用随机数生成函数rand(),对行列数字取模就能得到row-1和line-1范围的数字,正好符合了数组的性质。使用rand()必须先在主函数加入一段函数,并且包含两个新的头文件
#include 使用rand的库
#include 时间函数库,便于我们生成时刻变化的随机数
srand((unsigned int)time(NULL)); //这是随机数生成函数。它的使用方法我们可以参考msdn离线软件。
while (1)
{
//玩家下棋:
Playermove(board, ROW, LINE);
Show_board(board, ROW, LINE);
//电脑自动随机下棋:
Computermove(board, ROW, LINE);
Show_board(board, ROW, LINE);
}
int Isfull(char board[ROW][LINE], int row, int line)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < line; j++)
{
if (board[i][j] == ' ')
return 0;
}
}
return 1;
}
char Judge(char board[ROW][LINE], int row, int line)
{
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 < line; 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 (Isfull(board, ROW, LINE))
{
return 'Q';
}
//继续游戏:
return 'C';
}
根据9宫格特点,写出实现横纵斜三星一线即可取胜的代码。
void game()
{
//构建棋盘地基:
char board[ROW][LINE];
//棋盘初始化:
Init_board(board, ROW, LINE);
//打印棋盘界面:
Show_board(board, ROW, LINE);
char rez = 0;
while (1)
{
//玩家下棋:
Playermove(board, ROW, LINE);
Show_board(board, ROW, LINE);
rez = Judge(board, ROW, LINE);
if (rez != 'C')
break;
//电脑自动随机下棋:
Computermove(board, ROW, LINE);
Show_board(board, ROW, LINE);
rez = Judge(board, ROW, LINE);
if (rez != 'C')
break;
}
if (rez == 'o')
printf("你赢了!\n");
else if (rez == 'x')
printf("你输了!\n");
else
printf("平局!\n");
}
玩家每下一次棋,打印一次棋盘并且判断输赢,是玩家赢还是电脑赢还是平局或者是无结果,游戏继续,同时下棋的过程设计为循环。
可以看出,我们的电脑很笨,为了测试我们的代码功能的完整性
我们可以故意让着电脑再来一局:
在我的精心操作下,电脑成功赢得了比赛 ! (/doge)这至少证明我们的电脑也是会赢的,程序运行一切正常。
这是我第一次进行一个完整的小游戏的制作,它功能简单却有我不少心血,日后待编程技术不断提高,我会持续更新这个系列!
通过此次制作,我发现很多时候程序员要做的思考的量要和实践操作相当,甚至大于操作,编程是逻辑的艺术,待我慢慢发掘~