目录
前言
本篇文章主要运用C语言中二维数组的知识来一步步实现三子棋小游戏,进而巩固对知识的理解,提升代码能力。
一:三子棋的游戏规则
开始游戏后玩家会看到一个3✖️3的网格,玩家输入坐标后电脑自动下棋 ,如果三个相同的棋成行,列,或者对角则一方胜利,如果棋盘下满未分胜负,则游戏结束,玩家现选择是否重新玩。
二:创建源文件和头文件
头文件:game.h
源文件:text.c game.c
text.c包含主函数,用来判断游戏逻辑是否正确。
为了让代码更加简洁,更易于维护,我们把每一个功能的实现封装成函数,game.h用来定义这些函数。
其中头文件game.h用来包含需要用到的头文件,宏定义一些符号常量和声明game.c中的函数。
game.h中包含的头文件:
三:代码基础逻辑和菜单的打印。
基础逻辑:为了让玩家进行一次游戏后依然能够选择是否重新开始,我们需要在text.c中设计一个循环,并设计一个game()函数,我们将游戏的逻辑写入game函数()中,运行一次game()函数就代表进行了一次游戏。
菜单:在进行游戏以前我们需要知道玩家是否想玩,我们在game.h中声明一个函数DisMenu()并在game.c中进行函数定义(后续函数声明定义都是如此),通过scanf()函数获取到玩家输入的信息,如果为1就进行游戏,0就跳出循环,结束程序 其他就打印输出错误提示,进行新一次循环。
主函数:
DisMenu函数():
四:初始化棋盘。
我们先在game.h中宏定义棋盘的规格,ROW代表行数,COL代表列数。
然后在game()函数中定义一个char类型的数组Board[ROW][COL]用来保存棋盘每一格的信息。
声明并定义函数initBoard(),函数传入的参数为数组和棋盘行列数,此时Board数组并没有初始化,为了方便后续判断网格状态,我们统一初始化为’ ’(即空格)。
五:打印棋盘。
声明并定义一个函数DisPlayBoard(),函数参数为Board数组和棋盘行列数。在主函数中调用DisPlayBoard()函数。注意棋盘打印到每一行最后时一定要进行换行,并且每一行元素打印要用下划线间隔开。
六:玩家下棋
声明并定义一个函数playerMove(),函数参数为Board数组和棋盘行列数。
下棋其实就是通过玩家输入的坐标来改变对应数组中的元素,我们规定玩家的棋为*。
注意:玩家输入的坐标应当是行标列标均从1开始,使用数组进行修改时要将下标改为x-1和y-1,避免数组越界访问。
七:电脑下棋。
声明并定义一个函数computerMove(),函数参数为Board数组和棋盘行列数。
我们选择让电脑随机下棋 (我不会设计算法,大家可以自己尝试一下),调用srand()函数取当今时间为随机数生成的种子,rand()函数随机生成不为负数的整数,用rand()对任意整数x取余可以得到[0,x)范围内的整数。
八:game()函数中的设计
我们想让一次game()函数的执行代表一次游戏结束,三子棋在两方下完棋后如果游戏未结束就继续下棋,使用我们将玩家和电脑的下棋设计成一个循环,如果游戏结束就跳出一次循环。
九:判断游戏是否结束。
我们声明并定义一个函数IsWin(),函数参数为Board数组和棋盘行列数,并且返回可以判断游戏状态的字符。
平局:如果上述情况都不成立,我们考虑是否平局,如果棋盘全满就返回Q,我们声明并定义函数IsFull(),函数参数为Board数组和棋盘行列数,函数返回值为int类型,如果全满返回1,否则返回0。
每一次玩家电脑下完棋我们都进行判断,如果返回值不为C就分别打印结果,并跳出game()函数中的循环,否则玩家继续下棋。
我们将判断游戏状态的函数IsWin()放入game函数的循环中,并依据返回值判断游戏是否继续
十:完整代码
game.h
#define ROW 3
#define COL 3
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
//菜单
void DisMenu();
//初始化棋盘
void initBoard(char Board[ROW][COL], int row, int col);
//打印棋盘
void DisPlayBoard(char Board[ROW][COL],int row,int col);
//玩家下棋
void PlayMove(char Board[ROW][COL], int row, int col);
//电脑下棋
void ComputerMove(char Board[ROW][COL], int row, int col);
//判断是否游戏结束
char IsWin(char Board[ROW][COL], int row, int col);
//判断棋盘是否下满
int IsFull(char Board[ROW][COL], int row, int col);
game.c
#include "game.h"
//打印菜单
void DisMenu()
{
printf("*********************\n");
printf("*******/1.play*******\n");
printf("*******/0.exit*******\n");
printf("*********************\n");
printf("选择是否玩游戏->");
}
//判断是否下满
int IsFull(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; //遍历数组,找到任意一个为空格的元素就返回0
}
}
return 1;//数组中没有空格,返回1,游戏平局
}
//初始化棋盘
void initBoard(char Board[ROW][COL], int row, int col)
{
int i = 0, j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
Board[i][j] = ' '; //双重for循环遍历数组中元素,都初始化为空格
}
}
//打印棋盘
void DisPlayBoard(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 PlayMove(char Board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0; //记录坐标
while (1)
{
printf("玩家->");
scanf_s("%d %d", &x, &y); //玩家输入坐标
if (x > 0 && x < 4 && y > 0 && y < 4) //输入坐标在合法范围内
{
if (Board[x - 1][y - 1] == ' ')//数组元素为空格代表可以写入
{
Board[x - 1][y - 1] = '*';
DisPlayBoard(Board, ROW, COL);
break;//修改了一次元素,代表下了一次棋,应该换电脑下棋,跳出循环。
}
else //如果数组元素不为空格代表已经被占用
{
printf("输入非法,重新输入\n");
}
}
//输入坐标超出范围
else
printf("输入非法,重新输入\n");
}
}
//电脑下棋
void ComputerMove(char Board[ROW][COL], int row, int col)
{
while (1) //设计一个死循环来生成合法坐标
{
int x = rand() % ROW;
int y = rand() % COL; //记录坐标
if (x < 3&& y < 3) //合法
{
if (Board[x][y] == ' ') //如果坐标未被占用,就修改数组元素(下棋)
{
Board[x][y] = '#';
printf("电脑->\n");
DisPlayBoard(Board, ROW, COL);
break; //下了一步棋,跳出循环
}
}
}
}
//判断游戏输赢
char IsWin(char Board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
//判断3行
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];
}
//判断三列
for (j = 0; j < COL; j++)
{
if (Board[0][j] == Board[1][j] && Board[1][j] == Board[2][j] && Board[0][j] != ' ')
return Board[0][j];
}
//判断对角线
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, COL) == 1)
return 'Q';
else //上述情况都不是,游戏继续
return 'C';
}
text.c
#include "game.h"
void game()
{
char Board[ROW][COL];
initBoard(Board,ROW,COL); //初始化棋盘
//打印棋盘
DisPlayBoard(Board, ROW, COL);
while (1)
{
//玩家下棋
PlayMove(Board, ROW, COL);
//电脑下棋
ComputerMove(Board, ROW, COL);
//判断是否结束
char end=IsWin(Board, ROW, COL);
if (end == '*')
{
printf("玩家胜利\n");
break;
}
else if (end == '#')
{
printf("电脑胜利\n");
break;
}
else if (end == 'Q')
{
printf("平局\n");
break;
}
}
}
int main()
{
int n = 0;
srand((unsigned int)time(NULL)); //以当前时间为随机数种子
do
{
DisMenu(); //打印菜单
scanf_s("%d", &n);
//判断是否进行游戏
if (n == 1) //n为1,进行游戏
{
game(); //进行游戏
}
else if (n == 0) //n为0,结束游戏
{
break;
}
else //其它值,重新输入
{
printf("非法输入,请重新输入。\n");
}
} while (1);
return 0;
}