“雾霭来去蒙,归何处,自当去。”
今天来写一个以二维数组为基础的五子棋。(精华部分在于对输赢的判断)
拥有人人,人机两种模式,通过输入点的坐标来下棋,有完善的胜负系统,可以控制棋盘大小。
先看最后效果
可以将其拆分为以下几个模块:
那就开始吧。
1.菜单打印
菜单最好是使用do-while循环,这样在开始运行程序可以先打印一次菜单。
void menu()
{
printf("************************************************\n");
printf("******************1.play 0.exit****************\n");//简易的开始界面
printf("************************************************\n");
}
void test()
{
int input = 0;
srand((unsigned int)time(NULL));//srand函数对电脑下棋做铺垫
do
{
menu();
printf("请选择;>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
printf("五子棋\n");
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误,重新选择\n");
break;
}
} while (input);
}
2.创建二维数组并初始化。
为了可以控制行列数,用宏定义定义行列,这样如果要改变棋盘大小只需要改变宏定义的赋值即可,因为二维字符数组里一开始不可能是空格需要对它进行初始化。用for循环scanf对数组赋值空格即可。
#define ROW 10
#define COL 10
void InitBoard(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++)
{
board[i][j] = ' ';
}
}
}
3.打印棋盘。
总的来说循环打印两种类型的行,一种行是字符数组中的内容两边打空格再打‘|’一种是打‘|’把上一种行类型数组的内容和空格变为‘---’。当然为了可以控制棋盘大小仍用宏定义的值作为参数。
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");
}
}
}
4.玩家下棋。
即玩家输入坐标对该坐标对应店的数组赋值。注意若玩家下到之前本来就下过的地方时需要写出逻辑让他重下,为了区分人人模式下玩家一二,最好先打印类似”玩家*走“这样的标识。(玩家二和玩家一下棋代码基本相同)
void Player1Move(char board[ROW][COL], int row, int col, int* pa, int* pb)
{
int x = 0;
int y = 0;
printf("玩家*走:>");
while (1)
{
printf("请输入要下的坐标:>");
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] = '*';
*pa = x - 1;
*pb = y - 1;
break;
}
else
{
printf("该坐标被占用\n");//判断占用重下
}
}
else
{
printf("非法输入,请重新输入\n");
}
}
void Player2Move(char board[ROW][COL], int row, int col, int* pa, int* pb)
{
int x = 0;
int y = 0;
printf("玩家#走:>");
while (1)
{
printf("请输入要下的坐标:>");
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] = '#';
*pa = x - 1;
*pb = y - 1;
break;
}
else
{
printf("该坐标被占用\n");
}
}
else
{
printf("非法输入,请重新输入\n");
}
}
}
5.电脑下棋
这里其实主要用rand函数随机给数组赋值并不是很智能,但可以模拟电脑下棋。
void ComputerMove(char board[ROW][COL], int row, int col, int* pa, int* pb)
{
int x = 0;
int y = 0;
printf("电脑走:>\n");
while (1)
{
x = rand() % row;
y = rand() % col;
if (board[x - 1][y - 1] == ' ')
{
board[x - 1][y - 1] = '#';
*pa = x - 1;
*pb = y - 1;
break;
}
}
}
6.输赢判断
怎么判断五子棋的输赢,其实很简单,就是检查现在下的这枚棋子的左边四个空格是否与该棋子相同,或者左边三个右边一个是否与它相等,或者左边两个右边两个是否与它相等······以此类推,可以看成一个向某个固定方向前进的五个字符组成的贪吃蛇一样其以所下位置为头部行进到所下位置为尾部时,当前进过程中五个字符相等就赢了。当然为了以防万一也添加了一个当棋盘满了没有人赢的情况。
char Iswin(char board[ROW][COL], int row, int col, int a, int b)
{
//一行上是否相等
for (int i = 0; i < 5; i++)
{
int judge = 1;
for (int j = 0; j < 5; j++)
{
if (board[a][b - i + j] != board[a][b])
{
judge = 0;
break;
}
}
if (judge == 1)
return board[a][b];
}
//一列上是否相等
for (int i = 0; i < 5; i++)
{
int judge = 1;
for (int j = 0; j < 5; j++)
{
if (board[a - i + j][b] != board[a][b])
{
judge = 0;
break;
}
}
if (judge == 1)
return board[a][b];
}
//副对角线
for (int i = 0; i < 5; i++)
{
int judge = 1;
for (int j = 0; j < 5; j++)
{
if (board[a + i - j][b - i + j] != board[a][b])
{
judge = 0;
break;
}
}
if (judge == 1)
return board[a][b];
}//主对角线
for (int i = 0; i < 5; i++)
{
int judge = 1;
for (int j = 0; j < 5; j++)
{
if (board[a - i + j][b - i + j] != board[a][b])
{
judge = 0;
break;
}
}
if (judge == 1)
return board[a][b];
}
if (1 == isfull(board, ROW, COL))
{
return 'Q';
}
return 'C';
}
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;
}
}
}
return 1;
}
最后再将这些模块组合一下就ok了。
void game()
{
int a = 0;
int b = 0;
int judge = 0;
char ret = 0;
char board[ROW][COL] = { 0 };
InitBoard(board, ROW, COL);//初始化棋盘
DisplayBoard(board, ROW, COL);//打印棋盘
printf("\n1.人机对战 2.人人对战\n");
scanf("%d", &judge);
if (judge == 1)//人机对战
{
while (1)
{
Player1Move(board, ROW, COL, &a, &b);//玩家走
DisplayBoard(board, ROW, COL);
ret = Iswin(board, ROW, COL, a, b);//判断
if (ret != 'C')
{
break;
}
ComputerMove(board, ROW, COL, &a, &b);
DisplayBoard(board, ROW, COL);
ret = Iswin(board, ROW, COL, a, b);
if (ret != 'C')
{
break;
}
}
if (ret == '*')
{
printf("玩家赢\n");
}
else if (ret == '#')
{
printf("电脑赢\n");
}
else
{
printf("平局\n");
}
}
else if (judge == 2)//人人对战
{
while (1)
{
Player1Move(board, ROW, COL, &a, &b);
DisplayBoard(board, ROW, COL);
ret = Iswin(board, ROW, COL, a, b);
if (ret != 'C')
{
break;
}
Player2Move(board, ROW, COL, &a, &b);
DisplayBoard(board, ROW, COL);
ret = Iswin(board, ROW, COL, a, b);
if (ret != 'C')
{
break;
}
}
if (ret == '*')
{
printf("玩家1赢\n");
}
else if (ret == '#')
{
printf("玩家2赢\n");
}
else
{
printf("平局\n");
}
}
}