课堂上完成的五子棋逻辑代码,主要功能如下
1:绘制地图
使用一个16*16的二维数组代表地图,X表示黑子,O表示白子,没有棋子的地方用*表示,由于坐标范围不超过128,所以使用了char数据类型足以
2:下棋
通过控制台输入坐标,梅花间竹的给二维数组相应的下标的元素赋值
3:判断胜负
最麻烦的功能,最简单的方法是葱二维数组的第一个元素开始遍历,通过对应关系找出是否存在有5个连续的颜色相同的棋子。但身为一个爱偷懒的程序员,我是不会采用这么耗费时间和麻烦的办法的。
在这里我主要用4个函数,通过下棋的坐标,分别判断该坐标的纵向、横向、左上到右下和右上到左下这四个方向是否存在5个连续的棋子。本来打算用一个函数实现的,但逻辑思维跟不上,所以只好采用4个函数来计算。
代码如下
/*
项目名称:控制台版五子棋游戏
作 者:
所 有 者:
版 本:v1.0
项目功能:要求实现支持两人对战的游戏
备注:
X是黑子
O是白子
*/
#include <stdio.h>
char who; //0表示黑子下,1表示白子下
unsigned char g_MAP[16][16]; //用一个二维数组表示地图
void show_map(void); //显示地图
char play_chess(void); //下棋
char is_true(char who); //判断下棋的位置是否正确
char is_win(char row, char col, char* count); //判断胜负
/*********************************************************************************************************************************/
/*
把用户输入的下棋坐标传进以下四个函数,采用递归的方式判断是否有5个连续相同颜色的棋子
用up函数做例子,如果用户下的是黑子,那黑子的坐标传进up函数后,up判断该坐标上方是否有黑子,有的话继续往上找
如果超出棋盘,或者上方不再是黑子的时候,函数会以最上方的黑子坐标做参照,计算出下方连续的黑子数(包含最上方的黑子),返回给函数
如果返回的是5,证明有5个连续的黑子,黑子胜
up_left 函数能找出相邻的最左上方的棋子,
left 函数能找出相邻的最左方的棋子,
up_right 函数能找出相邻的最右上方的棋子;
up 函数能找出相邻的最上方的棋子
*/
char up(char row, char col);
char up_left(char row, char col);
char up_right(char row, char col);
char left(char row, char col);
/**********************************************************************************************************************************/
int main(void)
{
char wind = 1; //判断游戏是否结束
while (wind)
{
system("clear");
show_map();
if (5 == play_chess()) //下棋函数返回5,证明已经有5个相邻的同颜色棋子
{
wind = 0;
system("clear");
show_map();
if (1 == who) //判断哪个颜色获胜
{
printf("黑子胜,结束游戏\n");
}
else
{
printf("白子胜, 结束游戏\n");
}
}
}
return 0;
}
/************************************************************************************************************************************************/
//显示地图
void show_map()
{
int i = 0;
int j = 0;
printf(" ");
//打印棋盘的上方提示的横标
for (i = 0; i < 16; i++)
{
printf("%x ", i);
}
printf("\n");
//打印棋盘,和棋子
for (i = 0; i < 16; i++)
{
printf("%x ", i);
for (j = 0; j < 16; j++)
{
if (0 == g_MAP[i][j])
{
printf("* ");
continue;
}
printf("%c ", g_MAP[i][j]);
}
printf("\n");
}
}
//下棋函数
char play_chess(void)
{
/*
res的返回值是相邻棋子数最多的方向的相邻棋子个数(包括刚下的棋子)
res == 0,代表棋子没下到棋盘上,或者下到有棋子的地方
*/
char res;
if (0 == who)
{
printf("黑方请下棋:");
//黑子下棋,无效坐标重新下
while (0 == (res = is_true(who)));
//下子成功后who++,代表到白子下
who++;
}
else
{
printf("白方请下棋:");
while (0 == (res = is_true(who)));
//下子成功后who--,代表到黑子下
who--;
}
return res;
}
//输入棋子的坐标,并判断是否有效坐标
char is_true(char who)
{
char row, col;
char i = 0;
scanf("%hhd%hhd", &row, &col);
//避免不合法的输入,清空缓冲区
scanf("%*[^\n]");
scanf("%*c");
//判断坐标是否合法
if (row > 16 || col > 16 || row < 0 || col < 0 || (g_MAP[row][col] != 0))
{
printf("请输入正确坐标:");
return 0;
}
//如果是黑子下子的话,赋值为'x',白子的话赋值位'O'
g_MAP[row][col] = (who == 0) ? 'X' : 'O';
//使用4个变量,记录4个方向相邻的棋子数
char up1 = up(row, col);
char left1 = left(row, col);
char up_left1 = up_left(row, col);
char up_right1 = up_right(row, col);
//把上面4个变量加入数组中
char arr[] = {up1, left1, up_left1, up_right1};
char max = arr[0];
//选出相邻棋子数最多的方向的相邻棋子数目作为返回值
for (i = 1; i < 4; i++)
{
max = arr[i] > max ? arr[i] : max;
}
return max;
}
//计算纵向相同颜色的连续棋子数目
char up(char row, char col)
{
//超出棋盘,返回-1
if (row > 15 || row < 0)
{
return -1;
}
//如果上方还是相同的棋子,继续递归
if (g_MAP[row - 1][col] == g_MAP[row][col])
{
return up(row - 1, col);
}
//如果为边界上的棋子,或上方不再有相同颜色的棋子,而且距离下方边界还有4个格子以上的位置,则条件为真
else if (row - 2 == -1 || (g_MAP[row - 1][col] != g_MAP[row][col] && row + 4 < 16))
{
char i = 0;
//计算下方相同颜色连续的棋子数量,由于要包含第一个棋子,所以循环从1开始
for (i = 1; i < 5; i++)
{
//如果下方不是相同颜色的棋子或者没有棋子的话,循环结束
if (g_MAP[row + i][col] != g_MAP[row][col])
{
break;
}
}
return i;
}
}
//计算横向相同颜色的连续棋子数目
char left(char row, char col)
{
if (col > 15 || col < 0)
{
return -1;
}
if (g_MAP[row][col - 1] == g_MAP[row][col])
{
return left(row, col - 1);
}
else if ((col - 2) == -1 || (g_MAP[row][col - 1] != g_MAP[row][col] && col + 4 < 16))
{
char i = 0;
for (i = 1; i < 5; i++)
{
if (g_MAP[row][col + i] != g_MAP[row][col])
{
break;
}
}
return i;
}
}
//计算左上到右下相同颜色的连续棋子数目
char up_left(char row, char col)
{
if (row > 15 || row < 0 || col > 15 || col < 0)
{
return -1;
}
if (g_MAP[row - 1][col - 1] == g_MAP[row][col])
{
return up_left(row - 1, col - 1);
}
else if (((row - 2) == -1 || (col - 2) == -1) || (g_MAP[row - 1][col - 1] != g_MAP[row][col] && row + 4 < 16 && col + 4 < 16))
{
char i = 0;
for (i = 1; i < 5; i++)
{
if (g_MAP[row + i][col + i] != g_MAP[row][col])
{
break;
}
}
return i;
}
}
//计算右上到左下相同颜色的连续棋子数目
char up_right(char row, char col)
{
if (row > 15 || row < 0 || col > 15 || col < 0)
{
return -1;
}
if (g_MAP[row - 1][col + 1] == g_MAP[row][col])
{
return up_right(row - 1, col + 1);
}
else if (((row - 2) == -1 || (col + 2) == 16) || (g_MAP[row - 1][col + 1] != g_MAP[row][col] && row + 4 < 16 && col - 4 > 0))
{
char i = 0;
for (i = 1; i < 5; i++)
{
if (g_MAP[row + i][col - i] != g_MAP[row][col])
{
break;
}
}
return i;
}
}