上篇博客实现了三子棋的小游戏,那么如何实现五子棋和多子棋呢?
文章目录
棋盘外观的小优化
先说一下棋盘的问题,因为后期我在测试的时候,不能一眼看出来棋落子的坐标,所以对棋盘进行了一点小优化。
优化分了3X3—9X9的棋盘布局,和3X3—99X99的棋盘布局,因为10X10及以上的话,纵坐标10会占两个空,所以另外设计了一下。
修改的代码放到最后了,有兴趣的大佬可以看一下对不对,执行后的效果如下:
个位数规格的棋盘
****************************************
*****1.开始游戏 0.退出游戏*****
****************************************
系统提示:请选择:>>>1
1 2 3 4 5 6 7 8 9
1 | | | | | | | |
---|---|---|---|---|---|---|---|---
2 | | | | | | | |
---|---|---|---|---|---|---|---|---
3 | | | | | | | |
---|---|---|---|---|---|---|---|---
4 | | | | | | | |
---|---|---|---|---|---|---|---|---
5 | | | | | | | |
---|---|---|---|---|---|---|---|---
6 | | | | | | | |
---|---|---|---|---|---|---|---|---
7 | | | | | | | |
---|---|---|---|---|---|---|---|---
8 | | | | | | | |
---|---|---|---|---|---|---|---|---
9 | | | | | | | |
系统提示:请输入您要下的坐标:>>>
十位数规格的棋盘
****************************************
*****1.开始游戏 0.退出游戏*****
****************************************
系统提示:请选择:>>>1
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15
01 | | | | | | | | | | | | | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---
02 | | | | | | | | | | | | | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---
03 | | | | | | | | | | | | | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---
04 | | | | | | | | | | | | | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---
05 | | | | | | | | | | | | | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---
06 | | | | | | | | | | | | | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---
07 | | | | | | | | | | | | | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---
08 | | | | | | | | | | | | | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---
09 | | | | | | | | | | | | | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---
10 | | | | | | | | | | | | | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---
11 | | | | | | | | | | | | | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---
12 | | | | | | | | | | | | | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---
13 | | | | | | | | | | | | | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---
14 | | | | | | | | | | | | | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---
15 | | | | | | | | | | | | | |
系统提示:请输入您要下的坐标:>>>
五子棋
说明一下,我理解的五子棋这里有两种:
- 5X5的棋盘,行、列、对角线连成线,即为游戏胜利。
- 多行X多列,行、列,对角线存在五子成线,即为游戏胜利。
这里的多子棋指的是:
- 多行X多列,行、列、对角线存在N子成线,即为游戏胜利。
下面逐一对游戏实现过程进行分析。
第一类五子棋
思考在原有的三子棋基础上改变哪些量可以实现第一类五子棋。
- 棋盘大小(五行&五列)
- 胜负判断条件(行,列,对角线存在五子连线)
对原有三子棋程序做出如下更改。
- 改变宏定义中
ROW
和COL
的值为5,意思是棋盘的规格是五行五列。头文件更改后的代码如下。
//宏定义
#define _CRT_SECURE_NO_WARNINGS 1
#define ROW 5
#define COL 5
//引用库函数
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
//函数声明
void InitBoard(char board[ROW][COL], int row, int col);
void DisplayBoard(char board[ROW][COL], int row, int col);
void PlayerMove(char board[ROW][COL], int row, int col);
void ComputerMove(char board[ROW][COL], int row, int col);
char Win(char board[ROW][COL], int row, int col);
char Full(char board[ROW][COL], int row, int col);
- 胜负判断条件
//判断胜负
char Win(char board[ROW][COL], int row, int col)
{
int i = 0;
//判断行
for (i = 0; i < row; i++)
{
if (board[i][0] == board[i][1] && board[i][1] == board[i][2]&&board[i][2] == board[i][3] && board[i][3] == board[i][4] && board[i][1] != ' ')//行元素一样且不是空格
{
return board[i][1];
}
}
//判断列
for (i = 0; i < col; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] &&board[2][i] == board[3][i] && board[3][i] == board[4][i] && board[1][i] != ' ')//列元素一样且不是空格
{
return board[1][i];
}
}
//判断对角线
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] &&board[2][2] == board[3][3] && board[3][3] == board[4][4] && board[1][1] != ' ')//对角线元素一样且不是空格
{
return board[1][1];
}
if (board[4][0] == board[3][1] && board[3][1] == board[2][2] && board[2][2] == board[1][3] && board[1][3] == board[0][4] &&board[2][2] != ' ')
{
return board[1][1];
}
//判断是否平局
if (1 == Full(board, ROW, COL))//平局判断,函数在下面,已在头文件中声明,位置就无所谓了
{
return 'Q';
}
return 'C';
}
经测试,程序可执行,且无bug。
第二类五子棋
思考在原有的第一类五子棋的基础上改变和加入哪些量可以实现第二类五子棋。
- 棋盘大小(多行多列,以15*15的棋盘为例)
- 胜负判断条件(行,列,对角线存在五子连线)
对原有的三子棋(第一类五子棋)程序做出如下更改。
- 改变宏定义中
ROW
和COL
的值为15,意思是棋盘的规格是十五行十五列,头文件更改后的代码如下
//新加入一个CHESS常量,意味设置几个棋子连线为胜利。
//宏定义
#define _CRT_SECURE_NO_WARNINGS 1
#define ROW 15
#define COL 15
#define CHESS 5//!!!!新加入的量
//引用库函数
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
//函数声明
void InitBoard(char board[ROW][COL], int row, int col);
void DisplayBoard(char board[ROW][COL], int row, int col);
void PlayerMove(char board[ROW][COL], int row, int col);
void ComputerMove(char board[ROW][COL], int row, int col);
char Win(char board[ROW][COL], int row, int col);
char Full(char board[ROW][COL], int row, int col);
- 胜负判断条件
char Win(char board[ROW][COL], int row, int col)//五子棋
{
int x = 0;
int y = 0;
int i = 0;
for (x = 0; x < row; x++)
{
for (y = 0; y < col; y++)
{
//纵向
for (i = 0; i < CHESS - 1; i++)
{
if (board[x][y] == board[x][y + i] && board[x][y] != ' ')
{
continue;
}
else
break;
}
if (board[x][y] == board[x][y + i] && board[x][y] != ' ')
{
return board[x][y];
}
//横向
for (i = 0; i < CHESS - 1; i++)
{
if (board[x][y] == board[x + i][y] && board[x][y] != ' ')
{
continue;
}
else
break;
}
if (board[x][y] == board[x + i][y] && board[x][y] != ' ')
{
return board[x][y];
}
//捺 斜向
for (i = 0; i < CHESS - 1; i++)
{
if (board[x][y] == board[x + i][y + i] && board[x][y] != ' ')
{
continue;
}
else
break;
}
if (board[x][y] == board[x + i][y + i] && board[x][y] != ' ')
{
return board[x][y];
}
//撇 斜向
for (i = 0; i < CHESS - 1; i++)
{
if (board[x][y] == board[x - i][y + i] && board[x][y] != ' ')
{
continue;
}
else
break;
}
if (board[x][y] == board[x - i][y + i] && board[x][y] != ' ')
{
return board[x][y];
}
}
}
if (Full(board, ROW, COL))
{
return 'Q';
}
return 'C';
}
经测试,程序可执行,且无bug。
多子棋
修改二类五子棋中的宏定义常量值
思考在原有的第二类五子棋上改变和添加哪些量可以实现多子棋。
其实在这里将五子棋和多子棋分开是为了更好的理解
多子棋的实现只要更改第二类五子棋中宏定义下的
ROW
COL
CHESS
三个值就可以实现了
- 比如更改下面的代码代表游戏模式为13*13的方阵棋盘中,六子成龙(六个棋子连成一条线)即为胜利
#define ROW 13
#define COL 13
#define CHESS 6
- 下面的代码代表15*15的方阵棋盘中,八子成龙(八个棋子连成一条线)即为胜利
#define ROW 15
#define COL 15
#define CHESS 8
棋盘优化改动代码
对棋盘打印函数做了如下改变,新增和改动已在注释标出。
个位数规格
//打印棋盘(3*3-9*9)
void DisplayBoard(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < col; i++) //新增
{
if (i == 0) //新增
{
printf(" %d ", i + 1);//新增
}
else //新增
{
printf("%d ", i + 1);
}
}
printf("\n"); //新增,棋盘网格上加入相应列数
for ( int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
if (j == 0) //新增
{
printf("%d %c |",i+1,board[i][j]); //新增,在第一列之前打印出相应行数。
}
else if (j>0 && j < col - 1) //改动
{
printf(" %c |", board[i][j]);
}
else
printf(" %c ", board[i][j]);
}
printf("\n");
if (i < row - 1)
{
for (int k = 0; k < col; k++)
{
if (k == 0)
{
printf(" ---|");//改动改动改动了前面加空格以适应上面的变化
}
else if (k>0 && k < col - 1)
{
printf("---|");
}
else
{
printf("---");
}
}
}
printf("\n");
}
}
十位数规格
//打印棋盘(10*10-99*99)
void DisplayBoard(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < col; i++)
{
if (i == 0)
{
printf(" %02d ", i + 1);
}
else
{
printf("%02d ", i + 1);
}
}
printf("\n");
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
if (j == 0)
{
printf("%02d %c |", i + 1, board[i][j]);//这里修改了下,自动补0,
}
else if (j > 0 && j < col - 1)
{
printf(" %c |", board[i][j]);
}
else
printf(" %c ", board[i][j]);
}
printf("\n");
if (i < row - 1)
{
for (int k = 0; k < col; k++)
{
if (k == 0)
{
printf(" ---|");
}
else if (k > 0 && k < col - 1)
{
printf("---|");
}
else
{
printf("---");
}
}
}
printf("\n");
}
}
完整代码
第一类五子棋完整代码
//宏定义
#define _CRT_SECURE_NO_WARNINGS 1
#define ROW 5
#define COL 5
//引用库函数
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
//函数声明
void InitBoard(char board[ROW][COL], int row, int col);
void DisplayBoard(char board[ROW][COL], int row, int col);
void PlayerMove(char board[ROW][COL], int row, int col);
void ComputerMove(char board[ROW][COL], int row, int col);
char Win(char board[ROW][COL], int row, int col);
char Full(char board[ROW][COL], int row, int col);
#include"game.h"
//初始化棋盘
void InitBoard(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}
}
//打印棋盘
void DisplayBoard(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < col; i++)
{
if (i == 0)
{
printf(" %d ", i + 1);
}
else
{
printf("%d ", i + 1);
}
}
printf("\n");
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
if (j == 0)
{
printf("%d %c |", i + 1, board[i][j]);
}
else if (j > 0 && j < col - 1)
{
printf(" %c |", board[i][j]);
}
else
printf(" %c ", board[i][j]);
}
printf("\n");
if (i < row - 1)
{
for (int k = 0; k < col; k++)
{
if (k == 0)
{
printf(" ---|");
}
else if (k > 0 && k < col - 1)
{
printf("---|");
}
else
{
printf("---");
}
}
}
printf("\n");
}
}
//玩家输入
void PlayerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
while (1)
{
printf("系统提示:请输入您要下的坐标:>>>");
scanf("%d%d", &x, &y);
printf("\n");
//判断xy是否合法,一个是是否溢出,一个是是否被占用
if (x > 0 && x < row + 1 && y>0 && y < col + 1)
{
if (board[x - 1][y - 1] == ' ')
{
board[x - 1][y - 1] = '*';
break;
}
else
{
printf("电脑:这下过了,你个憨憨。\n");
printf("\n");
}
}
else
{
printf("电脑:FBI warning 非法输入,非法输入!!!请您自觉点。\n\n电脑:乖,咱重新输入!!!\n\n");
}
}
}
//电脑输入
void ComputerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("电脑:我走过啦!!!到你啦!!!\n\n");
while (1)
{
x = rand() % row;
y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
//判断胜负
char Win(char board[ROW][COL], int row, int col)
{
int i = 0;
//判断行
for (i = 0; i < row; i++)
{
if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][2] == board[i][3] && board[i][3] == board[i][4] && board[i][1] != ' ')//行元素一样且不是空格
{
return board[i][1];
}
}
//判断列
for (i = 0; i < col; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[2][i] == board[3][i] && board[3][i] == board[4][i] && board[1][i] != ' ')//列元素一样且不是空格
{
return board[1][i];
}
}
//判断对角线
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[2][2] == board[3][3] && board[3][3] == board[4][4] && board[1][1] != ' ')//对角线元素一样且不是空格
{
return board[1][1];
}
if (board[4][0] == board[3][1] && board[3][1] == board[2][2] && board[2][2] == board[1][3] && board[1][3] == board[0][4] && board[2][2] != ' ')
{
return board[1][1];
}
//判断是否平局
if (1 == Full(board, ROW, COL))//平局判断,函数在下面,已在头文件中声明,位置就无所谓了
{
return 'Q';
}
return 'C';
}
//平局算法函数
char Full(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
if (board[i][j] == ' ')
return 0;
}
}
return 1;
}
#include"game.h"
//游戏菜单
void menu(void)
{
printf("****************************************\n");
printf("*****1.开始游戏 0.退出游戏*****\n");
printf("****************************************\n");
}
void game(void)
{
char ret = 0;
char board[ROW][COL] = {
0 };
//初始化棋盘
InitBoard(board, ROW, COL);
//打印棋盘
DisplayBoard(board, ROW, COL);
while (1)
{
//玩家下棋
PlayerMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
//判断玩家是否胜利
ret = Win(board, ROW, COL);
if (ret != 'C')
{
break;
}
//电脑下棋
ComputerMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
//判断电脑是否胜利
ret = Win(board, ROW, COL);
if (ret != 'C')
{
break;
}
}
if (ret == '*')
{
printf("恭喜你赢啦!!!(不过我是随机下的,我的算法没有任何技术含量(狗头狗头狗头))\n");
printf("\n");
}
else if (ret == '#')
{
printf("你输了!!!你真笨!!!你是个憨憨吧!\n");
printf("\n");
}
else
{
printf("平局!!!你真笨!!!略略略!\n");
printf("\n");
}
}
void test(void)
{
srand((unsigned int)time(NULL));
int input = 0;
do
{
menu();
printf("\n");
printf("系统提示:请选择:>>>");
scanf("%d", &input);
printf("\n");
switch (input)
{
case 1:
game();
break;
case 0:
printf("破游戏,俺不玩了。\n");
break;
default:
printf("电脑:FBI warning 非法输入,非法输入,请您自觉点。\n\n电脑:乖,咱重新输入!!!\n");
break;
}
} while (input);
}
int main(void)
{
test();
return 0;
}
第二类五子棋完整代码
//宏定义
#define _CRT_SECURE_NO_WARNINGS 1
#define ROW 15
#define COL 15
#define CHESS 5
//引用库函数
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
//函数声明
void InitBoard(char board[ROW][COL], int row, int col);
void DisplayBoard(char board[ROW][COL], int row, int col);
void PlayerMove(char board[ROW][COL], int row, int col);
void ComputerMove(char board[ROW][COL], int row, int col);
char Win(char board[ROW][COL], int row, int col);
char Full(char board[ROW][COL], int row, int col);
#include"game.h"
//初始化棋盘
void InitBoard(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}
}
//打印棋盘
void DisplayBoard(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < col; i++)
{
if (i == 0)
{
printf(" %02d ", i + 1);
}
else
{
printf("%02d ", i + 1);
}
}
printf("\n");
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
if (j == 0)
{
printf("%02d %c |", i + 1, board[i][j]);
}
else if (j > 0 && j < col - 1)
{
printf(" %c |", board[i][j]);
}
else
printf(" %c ", board[i][j]);
}
printf("\n");
if (i < row - 1)
{
for (int k = 0; k < col; k++)
{
if (k == 0)
{
printf(" ---|");
}
else if (k > 0 && k < col - 1)
{
printf("---|");
}
else
{
printf("---");
}
}
}
printf("\n");
}
}
//玩家输入
void PlayerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
while (1)
{
printf("系统提示:请输入您要下的坐标:>>>");
scanf("%d%d", &x, &y);
printf("\n");
//判断xy是否合法,一个是是否溢出,一个是是否被占用
if (x > 0 && x < row + 1 && y>0 && y < col + 1)
{
if (board[x - 1][y - 1] == ' ')
{
board[x - 1][y - 1] = '*';
break;
}
else
{
printf("电脑:这下过了,你个憨憨。\n");
printf("\n");
}
}
else
{
printf("电脑:FBI warning 非法输入,非法输入!!!请您自觉点。\n\n电脑:乖,咱重新输入!!!\n\n");
}
}
}
//电脑输入
void ComputerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("电脑:我走过啦!!!到你啦!!!\n\n");
while (1)
{
x = rand() % row;
y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
char Win(char board[ROW][COL], int row, int col)//五子棋
{
int x = 0;
int y = 0;
int i = 0;
for (x = 0; x < row; x++)
{
for (y = 0; y < col; y++)
{
//纵向
for (i = 0; i < CHESS - 1; i++)
{
if (board[x][y] == board[x][y + i] && board[x][y] != ' ')
{
continue;
}
else
break;
}
if (board[x][y] == board[x][y + i] && board[x][y] != ' ')
{
return board[x][y];
}
//横向
for (i = 0; i < CHESS - 1; i++)
{
if (board[x][y] == board[x + i][y] && board[x][y] != ' ')
{
continue;
}
else
break;
}
if (board[x][y] == board[x + i][y] && board[x][y] != ' ')
{
return board[x][y];
}
//捺 斜向
for (i = 0; i < CHESS - 1; i++)
{
if (board[x][y] == board[x + i][y + i] && board[x][y] != ' ')
{
continue;
}
else
break;
}
if (board[x][y] == board[x + i][y + i] && board[x][y] != ' ')
{
return board[x][y];
}
//撇 斜向
for (i = 0; i < CHESS - 1; i++)
{
if (board[x][y] == board[x - i][y + i] && board[x][y] != ' ')
{
continue;
}
else
break;
}
if (board[x][y] == board[x - i][y + i] && board[x][y] != ' ')
{
return board[x][y];
}
}
}
if (Full(board, ROW, COL))
{
return 'Q';
}
return 'C';
}
//平局算法函数
char Full(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
if (board[i][j] == ' ')
return 0;
}
}
return 1;
}
#include"game.h"
//游戏菜单
void menu(void)
{
printf("****************************************\n");
printf("*****1.开始游戏 0.退出游戏*****\n");
printf("****************************************\n");
}
void game(void)
{
char ret = 0;
char board[ROW][COL] = {
0 };
//初始化棋盘
InitBoard(board, ROW, COL);
//打印棋盘
DisplayBoard(board, ROW, COL);
while (1)
{
//玩家下棋
PlayerMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
//判断玩家是否胜利
ret = Win(board, ROW, COL);
if (ret != 'C')
{
break;
}
//电脑下棋
ComputerMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
//判断电脑是否胜利
ret = Win(board, ROW, COL);
if (ret != 'C')
{
break;
}
}
if (ret == '*')
{
printf("恭喜你赢啦!!!(不过我是随机下的,我的算法没有任何技术含量(狗头狗头狗头))\n");
printf("\n");
}
else if (ret == '#')
{
printf("你输了!!!你真笨!!!你是个憨憨吧!\n");
printf("\n");
}
else
{
printf("平局!!!你真笨!!!略略略!\n");
printf("\n");
}
}
void test(void)
{
srand((unsigned int)time(NULL));
int input = 0;
do
{
menu();
printf("\n");
printf("系统提示:请选择:>>>");
scanf("%d", &input);
printf("\n");
switch (input)
{
case 1:
game();
break;
case 0:
printf("破游戏,俺不玩了。\n");
break;
default:
printf("电脑:FBI warning 非法输入,非法输入,请您自觉点。\n\n电脑:乖,咱重新输入!!!\n");
break;
}
} while (input);
}
int main(void)
{
test();
return 0;
}
写在后面
这篇博客对原有的三子棋进行了扩展,扩展到了五子棋以及多子棋,但是电脑下棋的算法采用的仍然是伪随机数,电脑还是个智障,下篇博客对电脑算法进行优化吧。
依然如此,如果上述程序中的代码逻辑或者是表述有问题,还请各位大佬批评指正哈。