经典小游戏——三子棋|C语言
每篇一句,与同行的你共勉:
不应该追求一切种类的快乐,而是应该追求高尚的快乐。
重温那些年草稿本上的勾勾叉叉的爱恨情仇。那年的夏天,那年同桌的你…
以下便是回忆的开始。
游戏构思
数据存储
这里我们主要是3字棋,棋盘都是以井字出现。棋盘落子得让别人知道,让别人输的明明白白,所以这里需要进行数据存储。二维数组便最合适不过。
int ret=0;
//棋盘需要存数据,使用数组
//int arr[3][3];
// 方便后期改变
int arr[ROW][COL];
//打印棋盘布局
数组安排后,这里为了后面方便改变数组大小就需要定义变量在头文件中;
//定义行列
#define ROW 3
#define COL 3
棋盘布局
这里可以通过一张图进行了解到棋盘的布局。
这是在画图中可以这么丝滑,但在C语言中就必须用一些字符来表示,
下面便是棋盘的代码
//棋盘打印
void Display_board(int arr[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i <row; i++)
{
for (j = 0; j < col; j++)
{
printf(" %c ",arr[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");
}
}
}
以上可以得到一个框架,但是因为没有初始化,所以会存在一些随机值生成。这就需要下面步骤初始化棋盘。
初始化棋盘
可能会想着使用0进行数组初始化,但是因为我们需要预留位置而棋盘看着就是一个框架,不需要显示任何值,所以这里直接使用字符空格进行初始化。
void Init(int arr[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
arr[i][j] = ' ';
}
}
}
这里我们就可以得到一个3行3列的一个表格。下面就要开始进行棋艺的切磋。
玩家下棋
这里为了便于观察玩家落子为 ,后面电脑落子为#。这里进行落子是我们的棋子一定要在数组内所以需要进行判断数组坐标是否合法*、坐标是否被占这里需要注意进行条件判断时我们需要注意一些代码的书写。避免一些bug。
void Player_move(int arr[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("玩家下棋\n");
while (1)
{
printf("请输入下棋坐标:");
//是否在数组内,防止越界
scanf("%d%d", &x, &y);
if ((x >= 1) && (x <= row) && (y >= 1) && (y <= col))
{
//坐标是否有效
if (arr[x-1][y-1]==' ')
{
arr[x-1][y-1] = '*';
break;
}
else
{
printf("坐标占用\n");
}
}
else
{
printf("输入坐标无效\n");
}
}
}
在书写坐标是否有效时,笔者便出现了一个bug一直显示坐标被占用,后面进行排查时发现条件判断时多了一个 == 前面多了一个空格。所以一直显示不对。
//坐标是否有效
if (arr[x-1][y-1]==' ')
{
arr[x-1][y-1] = '*';
break;
}
else
{
printf("坐标占用\n");
}
}
电脑下棋
经过上面代码书写,这和个代码书写便是大同小异。条件不同罢了。
代码放下;
//电脑下棋
void Computer_move(int arr[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("电脑下棋\n");
while (1)
{
x = rand() % row;
y = rand() % col;
if ((x >= 1) && (x <= row) && (y >= 1) && (y <= col))
{
//坐标是否有效
if (arr[x - 1][y - 1] != '*')
{
arr[x - 1][y - 1] = '#';
break;
}
}
}
}
输赢判断
既然是博弈,便会有高低。虽然这里对手有一点不给力(这里编程中电脑并没有达到Al智能程度)。输赢就只有行列三连,对角线三连。
//判断输赢
static int is_full(char arr[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
if (' ' == arr[i][j])
{
return 0;
}
}
}
return 1;
}
int who_win(int arr[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
if (arr[i][0] == arr[i][1] && arr[i][1] == arr[i][2] && arr[i][0] != ' ')
{
return arr[i][0];
}
}
for (i = 0; i < col; i++)
{
if (arr[0][i] == arr[1][i] && arr[1][i] == arr[2][i] && arr[0][i] != ' ')
{
return arr[0][i];
}
}
if (arr[0][0] == arr[1][1] && arr[1][1] == arr[2][2] && arr[1][1] != ' ')
{
return arr[1][1];
}
if (arr[0][2] == arr[1][1] && arr[1][1] == arr[2][0] && arr[1][1] != ' ')
{
return arr[1][1];
}
//判断平局
if (is_full(arr, row, col) == 1)
{
return 'Q';
}
//继续
return 'C';
}
以上便完成了所以模块代码书写。最后我们根据书写的代码片段以及对头文文件使用频率我们进行头文件书写。
有了前面准备好的代码最后进行代码块的布局调用
完成—测试
void game()
{
int ret=0;
//棋盘需要存数据,使用数组
//int arr[3][3];
// 方便后期改变
int arr[ROW][COL];
//打印棋盘布局
Init(arr,ROW,COL);
Display_board(arr, ROW, COL);
while (1)
{
Player_move(arr, ROW, COL);
//Display_board(arr, ROW, COL);
ret = who_win(arr, ROW, COL);
if (ret != 'C')
break;
Computer_move(arr, ROW, COL);
Display_board(arr, ROW, COL);
ret = who_win(arr, ROW, COL);
if (ret != 'C')
break;
}
printf("\n");
if (ret == '*')
{
printf("玩家赢\n");
}
else if (ret == '#')
{
printf("电脑赢\n");
}
else if (ret == 'Q')
{
printf("平局\n");
}
Display_board(arr, ROW, COL);
}
//玩家赢 - '*'
//电脑赢 - '#'
//平局了 - 'Q'
//游戏继续 - 'C'
void menu()
{
printf("######################\n");
printf("### 1.play 0.exit ###\n");
printf("######################\n");
}
int main()
{
srand((unsigned int)time(NULL));
int input = 0;
do
{
menu();
flag:
printf("请选择是否游戏:");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏");
break;
default:
printf("输入错误");
goto flag;
break;
}
} while (input);
return 0;
}
以上便是三子棋实现全部过程。如有错误,请多指正。