本科毕业设计——基于C++的棋类游戏自动生成工具的设计与实现

目录

〇,前言

一,论文

1,摘要

2,主要研究内容

3,棋盘

4,棋位

5,棋面符号

6,着法

7,特殊规则

8,设计

8.1,解析模块的设计

8.2 棋盘模块的设计

8.3 下棋模块的设计

8.4 棋谱和悔棋模块的设计

二,实现

1,代码V1.0

2,代码V2.0

三,实例

1,五子棋

(1)配置

(2)运行

(3)测试

(4)未实现特殊规则

2,黑白棋

(1)配置

(2)运行

(3)测试

3,田字上谷老虎棋

(1)配置

(2)运行

(3)测试

4,三角上谷老虎棋10羊版

(1)配置

(2)运行

(3)测试

(4)未实现特殊规则

5,三角上谷老虎棋12羊版

(1)配置

(2)运行

(3)测试

6,正定老虎棋

(1)配置

(2)运行

(3)测试

7,圈叉棋

(1)配置

(2)运行

(3)测试

8,米字棋(移一格版)

(1)配置

(2)运行

(3)测试

9,米字棋(任意移动版)

(1)配置

(2)运行

(3)测试

10,独立钻石棋

(1)配置

(2)运行

(3)测试

11,独立钻石棋变种(八边形)

(1)配置

(2)运行

 (3)测试

12,独立钻石棋变种(9行9列)

(1)配置

(2)运行

(3)测试

13,独立钻石棋变种(Hopping dots)

(1)配置

(2)运行

(3)测试


〇,前言

本博文是我本科毕业论文的节选,目录和论文目录不对应。

有极少量的内容改动。

因为源代码已丢失,所以我决定重写代码。

一,论文

1,摘要

目前市场上还只出现了很少一部分的棋类游戏的程序,大部分棋类没有对应的程序。这些棋类游戏的程序都是专门针对一个游戏开发出来的,没办法扩展成其他棋类游戏,因此每开发一种新的棋类游戏都需要不少的成本。实际上棋类游戏共性很强,因此设计并实现一个通用游戏框架是有必要的。

本课题对常见的100种棋类游戏进行了分析和抽象,提炼出了棋类游戏的通用逻辑和流程,并对流程中每个步骤的规则进行了总结和实现常见规则,利用回调函数机制和设计模式实现了可拓展性较强的框架,并在此框架基础上实现了五子棋、黑白棋和老虎棋这三种规则差别较大的棋,从而验证了框架的功能完备性。

利用本框架实现棋类游戏,简单的游戏可以自动生成整个游戏,复杂的游戏只需要提供描述特殊规则的函数也可以生成整个游戏,为了验证框架的性能本课题又实现了另外三种棋类游戏,结果表明本框架可以完成自动生成。

2,主要研究内容

(1)研究如何根据棋类游戏的分类和共性,抽象、提炼出棋类游戏的通用逻辑和流程。

(2)实现棋类游戏的通用编程框架。

(3)将每个步骤的规则进行总结并实现常见规则。

(4)在框架和已实现的规则基础上实现五子棋、黑白棋和老虎棋。

3,棋盘

棋盘不能太过于复杂,要选择可以用若干矩阵表示出来的棋盘。

常见的棋盘分为网络棋盘、点阵棋盘、容器棋盘。其中网络棋盘包括四边形棋盘、圆弧类棋盘、三角形棋盘、凸多边形棋盘、凹多边形棋盘、分枝类棋盘。对于某些棋盘可以做几何拓扑变换。例如下图展示了如何将西瓜棋的棋盘作拓扑变换。

这样的拓扑变换之后就可以用一个7*7的数组记录棋盘中的格点,要想记录连线还需要邻接矩阵。据《棋类游戏100种》一书中统计,在410种棋中,有186种是四边形棋盘。四边形棋盘是不需要拓扑变换的,其他224种棋类绝大部分也是可以通过拓扑变换变成矩阵可存储的格式的。

4,棋位

对于网络棋盘来说,棋位分为三种,顶点式棋位、格式棋位、线段式棋位。其中线段式棋位非常少见,不纳入考虑范围。

顶点式棋位(以网络棋盘的各个顶点作为棋位,如五子棋)和格式棋位(以网络棋盘的各个格作为棋位,如圈叉棋)都很常见,本质上差别不大,实际上即使是线段式棋位也可以通过变换变成顶点式棋位,但是会影响下棋的思路,不可取。

5,棋面符号

按照棋面符号的数量,可以分为无符号棋类、单一符号棋类和多符号棋类。无符号棋类就是所有棋子都是双方共用,单一符号棋类就是双方各一种棋子,多符号棋类就是类似象棋有多种棋子。无符号棋类不太常见,但是和单一符号棋类共性很强,可以纳入考虑范围,多符号棋类不纳入考虑范围。

例如五子棋这种只有黑棋和白棋的游戏,再例如老虎棋,只有老虎和羊2种棋子,都可以纳入考虑范围,而像象棋这种棋子复杂的棋本课题不考虑。

6,着法

棋类游戏的着法包括布子方式、走子方式、吃子方式等。

布子方式有一次性布子、轮流布子、分段布子三种,三种布子方式的不同只在于游戏初始化和下棋之后对棋盘的更新不同,所以都可以纳入考虑范围。

走子方式分为步行和跳行两类,而步行中最常见的两种是直行和斜行,这两种走子方式要考虑,其他的走子方式暂时可以不考虑。

吃子方式包括很多种,其中较常见的是围吃、走吃、跳吃、夹吃等,吃子方式不用限制,框架中有一个专门的函数判断每种局面情况下,被吃掉的所有棋子,并返回一个数组,所以这个不需要限制约束。

7,特殊规则

特殊规则分为两大类:第一类是为了保证游戏正常进行所必须的,例如围棋中的劫争禁手点,第二类是为了维护游戏的公平性和趣味性等,例如五子棋中的黑棋禁手

如果去掉第一类特殊规则,那么游戏规则体系将是不完备的,会出现下棋下到程序崩溃的情况,但是如果去掉第二类特殊规则,游戏规则体系还是完备的。

在简化复杂度的需求之下,可以考虑去掉第二类特殊规则。实际上,市场上很多很多五子棋程序也是不考虑黑棋禁手的。可能是因为考虑到很多用户并不了解黑棋禁手,也有可能是有些程序员自己都不懂黑棋禁手,又或者可能是为了降低程序复杂度(尤其是带AI的程序)而不考虑黑棋禁手。

8,设计

8.1,解析模块的设计

(1)棋盘

目前只考虑2类最常见的棋盘,一种是矩形棋盘,另一种是在水平竖直线的基础上加上若干个米字型格点的棋盘,这2种棋盘涵盖的范围非常广,对于没有涵盖到的情况,也可以直接拓展,不影响框架的使用。这样,只需要初始化board[maxr][maxc]和ismi[maxr][maxc]这2个数组,即可记录棋盘的所有信息。board数组记录每个格点的信息,有4种取值,0表示一方的棋子,1表示另外一方的棋子,-1表示空,-2表示无效格子。ismi记录每个格点是否是米字型格点,有了board和ismi这2各数组,就可以确定所有的相邻关系,从而确定整个棋盘。

(2)棋规

棋规对应的是下棋模块的功能,下棋模块涉及到非常复杂的函数调用关系,这也是本框架的核心所在,即将复杂的逻辑总结并实现出来,使用本框架时就不需要再考虑这些复杂的逻辑了。如图显示了下棋模块的详细流程。

本框架并没有实现将各种不同的行棋规则抽象成数据可描述的程度,本框架只是将棋类游戏的核心逻辑和流程抽象并实现,而流程的每一个具体的步骤,每个棋类游戏都不尽相同,本框架采用桥接模式解决这个问题,在主流程中有若干抽象函数,而各个棋类游戏负责提供具体函数,这样就完成了整个游戏。然而实际上,每个步骤对应的规则都有常见的几种,不同的棋类游戏其实就是每个步骤的不同规则的组合,所以本框架拟总结并实现每个步骤中常见的规则,这样,描述一个棋类游戏的棋规只需要一些id和参数,每个id对应一个步骤的某个具体规则,这样,由解析模块解析这些id就可以描述整个棋规。为了实现这个架构,本框架采用函数指针数组和回调机制,每个步骤就对应一个函数指针数组,数组中每个函数指针都是一个具体函数,在抽象函数中利用解析到的id即可回调。

8.2 棋盘模块的设计

根据解析模块得到的棋盘信息(board[maxr][maxc]和ismi[maxr][maxc]这2个数组)即可完成自动绘制棋盘,棋盘有2大类(一种是矩形棋盘,另一种是在水平竖直线的基础上加上若干个米字型格点的棋盘),分别采取不同的方案进行绘制,都是采用制表符,一种方案是紧密型棋盘,每个格点要么画棋子,要么画棋盘,格点之间紧密相连,这种方案适合矩形棋盘。另一种方案是松散型棋盘,每个格点要么画棋盘,要么打印空格,格点和相邻的格点之间全部用线条连接,这种方案适合在水平竖直线的基础上加上若干个米字型格点的棋盘,实际上所有棋盘都可以用这种方案来绘制,只是对于相邻关系比较复杂的棋盘需要拓展数据结构才能描述相邻关系,但这个绘制棋盘的方案仍然是可行的。

8.3 下棋模块的设计

下棋模块包括解析输入、判断能否落子、落子、判断胜负这4个步骤,每个步骤都根据解析模块解析出的id来确定对应的规则。下面一一讲述每个步骤是如何设计的。

(1)解析输入

行棋方式如果是落子就需要输入2个整数,行棋方式如果是移子就需要输入4个整数,有些游戏的双方,一方是落子而另一方是移子,所以为了统一数据结构,对于解析输入、判断能否落子、落子、判断胜负这4个步骤,每个步骤都需要2个id,分别表示下棋双方对应的规则。

(2)判断能否落子

行棋方式包括落子和移子两种,但是根据博弈论的思想,为了更加统一地表述,可以把移子理解并表述为在一个四维空间落子,所以这里的判断能否落子实际上指的是判断能否落子或移子,下面将分别讨论本框架是如何抽象出统一的逻辑的。

本框架将判断在目标坐标处能否落子的逻辑总结如下:首先,目标坐标必须在棋盘范围内,而且必须是空的,即没有双方棋子。其次,有些游戏还有其他附加规则,有些游戏没有。例如五子棋,没有其他规则,而黑白棋,附加规则是在目标坐标处落子之后,必须改变其他地方的至少一个棋子,否则不能落子。本框架将黑白棋的这种规则进行抽象,不需要具体判断落子会改变哪些棋子,而只需要调用落子函数,然后比较前后差异即可。

本框架将判断能否移子的逻辑总结如下:(为了表述方便,把移子表述成将出发坐标处的棋子移动到目标坐标处)首先,出发坐标和目标坐标必须在棋盘范围内,而且目标坐标必须是空的,而出发坐标必须有正在下棋方的棋子。其次,每种棋子移动的规则都不一样,但是可以归为三类:移动到相邻位置、跳吃子、固定方式的路线。这里的跳吃子指的是沿着一个方向跳过对方棋子并降落在空处,同时吃掉对方棋子。

(3)落子

这里的落子也是包含两种情况,一种是狭义的落子,一种是移子。

对于第一种情况,落子,落子函数只负责在指定坐标处落子,不负责其他任何功能。落子函数不做任何有关判断能否落子的计算,更不能调用判断能否落子的函数,否则会造成逻辑循环,可能会导致程序死循环。因为在判断能否落子时可能会调用落子函数,也就是落子函数接收的坐标不一定是真实可以落子的坐标,但一定是棋盘范围内的坐标,所以不需要对坐标做范围检测,但是必须保证程序不会造成死循环。

对于第二种情况,移子,因为判断能否落子时不需要调用落子函数,所以这里的落子函数可以调用判断能否落子的函数,因为有些棋子不止一种移子方式,所以需要调用判断能否落子的函数。

(4)判断胜负

判断胜负的函数,需要在任何时刻判断当前局面游戏是否已经结束,如果结束了,判断是先手胜还是后手胜还是平局。判断胜负是棋类游戏最多样的地方,几乎所有棋类游戏之间判断胜负的规则都不一样,不过本框架还是对最常见的几种情况进行了抽象并实现。最常见的几种情况是:第一种,如果还能落子就继续游戏,不能落子就判为负方。第二种,如果还能落子就继续游戏,不能落子就换对方落子,对方也不能落子就结束游戏。第三种,一方棋子数量到达某个范围就结束游戏。第四种,成形目棋类,一方形成某种棋形就结束游戏,否则就按照前三种情况的某一种来处理。除了这四种最常见的情况之外,也有其他特殊复杂规则,但是都类似于第四种情况,先判断特殊规则,如果没有结束游戏的话再按照前三种规则判断。

8.4 棋谱和悔棋模块的设计

完整的棋谱,应该包括两部分,每一步是谁下,每一步下的位置。因为有些棋并不是严格地双方轮流下,例如黑白棋,所以记录每一步是谁下能更好地显示信息。但是这并不是必须的,因为棋谱的最重要两个功能是方便调试和用来实现悔棋功能,调试的时候需要支持把整个棋谱粘贴到控制台,然后自动地执行每一步行棋,而悔棋就是直接读取棋谱中的数据然后执行每一步行棋。为了方便调试(实际上不仅是调试,当下棋者需要回顾之前的某一步的时候,也是同样的道理,利用棋谱直接粘贴跳转到需要的那一步,比不断悔棋方便些),在显示棋谱的时候要依次输出每一步下的位置,然后调试者(或者下棋者)可以直接复制棋谱,然后粘贴即可。所以,显示棋谱的时候是不能带每一步是谁下的信息的,棋谱可以存这个信息,但不能打印出来,而把棋谱直接粘贴到控制台的时候,程序就必须支持运行时自动判断每一步是谁下,所以棋谱是完全不需要存每一步是谁下的。这样,棋谱的设计就完成了,只存储每一步下的位置。下一章将详细介绍各个功能是如何实现的。

悔棋功能就是从开局开始,按照棋谱处理除掉最后一步的每一步,这样就实现了悔棋功能。有些游戏可以按照落子规则进行回溯,不需要棋谱即可实现悔棋,例如五子棋,只需要知道最后一步下的位置即可实现悔棋,当然,要实现连续不限次数的悔棋的话还是需要存棋谱,但是仍然不需要从开局开始一步步处理,这样时间效率就比较高。但是,有些游戏是无法按照落子规则进行回溯的,例如黑白棋,即使知道当前局面和最后落子位置,也无法推断出落子之前的局面,因为可能会有多种情况。所以,为了实现统一的悔棋功能,本框架采用的方案是所有游戏悔棋都利用棋谱从开局开始一步步处理。

二,实现

1,代码V1.0

代码包含了框架本身,和用框架实现的各个棋类游戏。

在"D:\init.txt"中写配置数据,运行程序即可。

本程序只读其中的数字,中文和字母可以随便写。

#include<iostream>
#include<string>
#include<vector>
#include<windows.h>
#include<iomanip>
#include<algorithm>
using namespace std;

#define MAXR 20 //棋盘最大行数
#define MAXC 20 //棋盘最大列数
#define PLAYER 2 //下棋人数
#define cinInt(x) while(!(cin>>x)){cin.clear();cin.ignore();}
#define cinInt2(x,y) cinInt(x)cinInt(y)

typedef void(*func_void)();
typedef void(*func_void2)(int, int);
typedef void(*func_void4)(int, int, int, int);
typedef string(*func_string1)(int);
typedef string(*func_string2)(int,int);
typedef bool(*func_bool)();
typedef bool(*func_bool2)(int, int);
typedef bool(*func_bool4)(int, int, int, int);

const char* dataInTxt = "D:\init.txt";//存放本地配置的文件
const int dr[8] = { -1, -1, 0, 1, 1, 1, 0, -1 };//用8个方向向量实现flat技术
const int dc[8] = { 0, 1, 1, 1, 0, -1, -1, -1 };

//begin 配置数据,缩进代表子参数
int row, col;//整个棋盘一共row行,编号1-row,一共col列,编号1-col
int board[MAXR + 2][MAXC + 2];//棋盘的每个格点,=1表示一方的棋子,=2表示另外一方的棋子,0表示空,-1表示无效格子
int boardStyle;//棋盘样式,=0表示只有横线和竖线的棋盘,=1表示除了横竖还有米字的棋盘,=2表示其他棋盘
	int isMi[MAXR + 2][MAXC + 2];//每个格点是不是米字型,当boardStyle为一时有此参数
int chessman;//棋子样式
int displayContent;//额外显示内容,=0表示显示各方棋子数量,=1表示不显示
int turn;//轮到谁下,=1,=2
bool isEnd;//游戏是否结束
int howToChangeTurn;//如何换下棋方,=0表示正常轮换
int playMod;//表示行棋的方式,=0表示落子,=1表示移子,=2表示其他
	int placeMod;//表示落子的具体规则,=0表示仅落子,=1表示夹吃
	int placeOkMod;//表示能否落子的具体规则,=0表示有空格即可,=1表示有空格而且还要落子改变其他棋子
	int moveMod;//表示移动棋子的具体规则,=0表示移到相邻处,=1表示跳跃并吃子,=2表示老虎棋
	int moveOkMod;//表示能否移动棋子的具体规则,=0表示移到相邻处,=1表示跳跃并吃子,=2表示老虎棋
int ifEndMod;//表示是否结束具体规则,=1表示一方不可下就换另一方,双方都不能下就结束,=2表示五子棋,=3表示老虎棋
//end 配置数据
vector<vector<int>>manual;
int temp[MAXR + 2][MAXC + 2]; //board的备份

//begin 初始化
void initBoard()
{
	for (int i = 0; i <= MAXR + 1; i++)for (int j = 0; j <= MAXC + 1; j++)
	{
		board[i][j] = -1, isMi[i][j] = 0;
	}
	for (int i = 1; i <= row; i++)for (int j = 1; j <= col; j++)
	{
		cinInt(board[i][j]);
	}
	cinInt(boardStyle);
	if (boardStyle == 1)
	{
		for (int i = 1; i <= row; i++)for (int j = 1; j <= col; j++)
		{
			cinInt(isMi[i][j]);
		}
	}
}
void init()//读取配置,完成变量初始化
{
	cinInt2(row,col);
	if (row <= 0 || col <= 0)
	{
		isEnd = true;
		return;
	}
	initBoard();
	cinInt2(chessman, displayContent);
	cinInt(turn);
	isEnd = false;
	cinInt2(howToChangeTurn, playMod);
	if (playMod == 0)
	{
		cinInt2(placeMod, placeOkMod);
	}
	else if (playMod == 1)
	{
		cinInt2(moveMod, moveOkMod);
	}
	cinInt(ifEndMod);
}
//end 初始化

//begin 棋子样式
string getChessman0(int num)//黑白棋
{
	if (num == 1)return "●";
	if (num == 2)return "▲";
	return "?";
}
string getChessman1(int num)
{
	return "?";
}
func_string1 f_getChessman[] = { getChessman0, getChessman1 };
string getChessman(int num)
{
	return f_getChessman[chessman](num);
}
//end 棋子样式

//begin 棋子数量
int getNum(int key)
{
	int ans = 0;
	for (int i = 1; i <= row; i++)for (int j = 1; j <= col; j++)
		ans += (board[i][j] == key);
	return ans;
}
//end 棋子数量

//begin 棋盘
string getString0(int r, int c)
{
	if (board[r][c] > 0)return getChessman(board[r][c]);
	if (r == 1)
	{
		if (c == 1)return "┌";
		if (c == col)return "┐";
		return "┬";
	}
	if (r == row)
	{
		if (c == 1)return "└";
		if (c == col)return "┘";
		return "┴";
	}
	if (c == 1)return "├";
	if (c == col)return "┤";
	return "┼";
}
string getString1(int r, int c)
{
	if (board[r][c] > 0)return getChessman(board[r][c]);
	return "  ";
}
func_string2 f_getString[] = { getString0, getString1 };
string getString(int r, int c)
{
	return f_getString[boardStyle](r, c);
}
//end 棋盘

//begin 显示界面
void addedDisplay0()
{
	cout << getChessman(1) << "有" << getNum(1) << "个,";
	cout << getChessman(2) << "有" << getNum(2) << "个\n";
}
void addedDisplay1()
{
	return;
}
int getOddEven(int k1,int k2)
{
	int ans = 0;
	for (int i = 1; i <= row; i++)for (int j = 1; j <= col; j++)
	{
		if (board[i][j] > 0)ans += (i + k1) % 2 * ((j + k2) % 2);
	}
	return ans;
}
void addedDisplay2()
{
	cout << "(奇,奇)有" << getOddEven(0, 0) << "个,(偶,偶)有" << getOddEven(1, 1) << "个,";
	cout << "(奇,偶)有" << getOddEven(0, 1) << "个,(偶,奇)有" << getOddEven(1, 0) << "个\n";
}
func_void f_addedDisplay[] = { addedDisplay0, addedDisplay1, addedDisplay2 };

void display0()
{
	cout << ' ';
	for (int i = 1; i <= col; i++)cout << ' ' << i % 10;
	for (int i = 1; i <= row; i++)
	{
		cout << endl << setw(2) << i;
		for (int j = 1; j <= col; j++)
		{
			cout << getString(i, j);
		}
	}
	cout << endl;
}
void display1()
{
	for (int i = 1; i <= col; i++)cout << "   " << i % 10;
	for (int i = 1; i <= row; i++)
	{
		cout << endl << setw(2) << i;
		for (int j = 1; j <= col; j++)
		{
			cout << getString(i, j);
			if (j == col)continue;
			if (board[i][j] != -1 && board[i][j + 1] != -1)cout << "┄";
			else cout << "  ";
		}
		if (i == row)continue;
		cout << endl << "  ";
		for (int j = 1; j <= col; j++)
		{
			if(board[i][j] != -1 && board[i+1][j] != -1)cout << "┆";
			else cout << "  ";
			if (isMi[i][j] || isMi[i + 1][j + 1])cout << "╲";
			else if (isMi[i + 1][j] || isMi[i][j + 1])cout << "╱";	
			else cout << "  ";
		}		
	}
	cout << endl;
}
func_void f_display[] = { display0, display1 };
void display()
{
	system("cls");
	f_display[boardStyle]();
	f_addedDisplay[displayContent]();
	cout << "轮到" << turn << getChessman(turn) << "下\n";
}

void displayManual()//显示棋谱
{
	vector<int>tmp;
	for (auto it = manual.begin(); it != manual.end(); it++)
	{
		tmp = *it;
		for (auto it = tmp.begin(); it != tmp.end(); it++)cout << *it << " ";
	}
	Sleep(5000);
}
//end 显示界面

//begin 下棋方控制
void changeTurn0() //黑白棋
{
	turn = 3 - turn; //turn在1,2之间轮换
}
void changeTurn1()
{
	return;
}
func_void f_changeTurn[] = { changeTurn0, changeTurn1 };
void changeTurn()
{
	return f_changeTurn[howToChangeTurn]();
}
//end 下棋方控制

//begin 落子
void place0(int r, int c) //仅落子,如五子棋
{
	return;
}
void place1(int r, int c)//夹吃,如黑白棋
{
	int k = board[r][c], tr, tc;
	for (int i = 0; i < 8; i++)
	{
		tr = r, tc = c;
		while (true)
		{
			tr += dr[i], tc += dc[i];
			if (tr <= 0 || tr >= row + 1 || tc <= 0 || tc >= col + 1)break;
			if (board[tr][tc] == 3 - k)continue;
			if (board[tr][tc] == k)
			{
				for (int jr = r + dr[i], jc = c + dc[i]; jr != tr || jc != tc; jr += dr[i], jc += dc[i])
					board[jr][jc] = k;
			}
			break;
		}
	}
}
func_void2 f_place[] = { place0, place1 };
void place(int r, int c)
{
	board[r][c] = turn;
	f_place[placeMod](r, c);
}
//end 落子

//begin 移子
void move0(int r, int c, int r2, int c2)//仅移子
{
	int tmp = board[r][c];
	board[r][c] = board[r2][c2], board[r2][c2] = tmp;
}
void move1(int r, int c, int r2, int c2)//移子或跳吃子
{
	move0(r, c, r2, c2);
	if (abs(r - r2)>1 || abs(c-c2)>1)board[(r + r2) / 2][(c + c2) / 2] = 0;
}
void move2(int r, int c, int r2, int c2)//双方不同
{
	if (turn == 1)move0(r, c, r2, c2);
	else move1(r, c, r2, c2);
}
func_void4 f_move[] = { move0, move1, move2 };
void move(int r, int c, int r2, int c2)
{
	f_move[moveMod](r, c, r2, c2);
}
//end 移子

//begin 能否落子
bool placeOk0(int r, int c)//五子棋,圈叉棋
{
	return true;
}
int getChangeNum(int r, int c)//落子前后有多少棋子改变
{
	for (int i = 1; i <= row; i++)for (int j = 1; j <= col; j++)
		temp[i][j] = board[i][j];
	place(r, c);
	int changeNum = 0;
	for (int i = 1; i <= row; i++)for (int j = 1; j <= col; j++)
		changeNum += (temp[i][j] != board[i][j]), board[i][j] = temp[i][j];
	return changeNum;
}
bool placeOk1(int r, int c)//黑白棋
{
	return getChangeNum(r, c) > 1;
}
func_bool2 f_placeOk[] = { placeOk0, placeOk1 };
bool placeOk(int r, int c) //能否落子
{
	if (r<1 || r>row || c<1 || c>col)return false;
	if (board[r][c] !=0)return false;
	return f_placeOk[placeOkMod](r, c); 
}
//end 能否落子

//begin 能否移子
bool moveOk0(int r, int c, int r2, int c2)//移到相邻处
{
	if (board[r][c] != turn)return false;//只能移自己的棋
	if (r == r2 && c == c2)return false;
	if (abs(r - r2) > 1 || abs(c - c2) > 1)return false;//不是8邻居	
	if (r == r2 || c == c2)return true;//上下左右
	return isMi[r][c] || isMi[r2][c2];//有斜线
}
bool moveOkJump(int r, int c, int r2, int c2)
{
	bool ans = false;
	if (r == r2 && abs(c - c2) == 2 || c == c2 && abs(r - r2) == 2 || abs(c - c2) == 2 && abs(r - r2) == 2 && isMi[(r + r2) / 2][(c + c2) / 2])
	{
		ans = board[(r + r2) / 2][(c + c2) / 2] == 3 - board[r][c];
	}
	return ans;
}
bool moveOk1(int r, int c, int r2, int c2)//移子或跳吃
{
	if (board[r][c] != turn)return false;//只能移自己的棋
	return moveOk0(r, c, r2, c2) || moveOkJump(r, c, r2, c2);
}
bool moveOk2(int r, int c, int r2, int c2)
{
	if (board[r][c] != turn)return false;//只能移自己的棋
	if (turn == 1)return moveOk0(r, c, r2, c2);
	else return moveOk1(r, c, r2, c2);
}
bool moveOk3(int r, int c, int r2, int c2)
{
	if (board[r][c] != turn)return false;//只能移自己的棋
	return true;
}
bool moveOk4(int r, int c, int r2, int c2)
{
	return moveOkJump(r, c, r2, c2);
}
func_bool4 f_moveOk[] = { moveOk0, moveOk1, moveOk2, moveOk3, moveOk4 };
bool moveOk(int r, int c, int r2, int c2)
{
	if (r<1 || r>row || c<1 || c>col)return false;
	if (r2<1 || r2>row || c2<1 || c2>col)return false;
	if (board[r2][c2] != 0)return false;
	return f_moveOk[moveOkMod](r,c,r2,c2);
}
//end 能否移子

//begin 是否结束
bool hasPlaceOk()
{
	for (int i = 1; i <= row; i++)for (int j = 1; j <= col; j++)
		if (placeOk(i, j))return true;
	return false;
}
bool ifEnd0()//不可下就结束
{
	return isEnd = !hasPlaceOk();
}
bool ifEnd1()//黑白棋,一方不可下就换另一方,双方都不能下就结束
{
	isEnd = !hasPlaceOk();
	if (!isEnd)return false;
	changeTurn();
	return isEnd = !hasPlaceOk();
}
int numInLine(int row, int col, int u)//坐标(row,col),方向向量u,返回该方向有多少连续同色棋子,不包括此坐标本身
{
	int i = row + dr[u], j = col + dc[u], sum = 0, ref = board[row][col];
	if (ref == 0)return 0;
	while (board[i][j]==ref)sum++, i += dr[u], j += dc[u];
	return sum;
}
int maxNumInLine(int row, int col)//坐标(row,col),返回四条直线最多的有多少连续同色棋子,包括此坐标本身
{
	int ans = 0;
	for (int u = 0; u < 4; u++)ans = max(ans, numInLine(row, col, u) + numInLine(row, col, u + 4));
	return ans+1;
}
bool ifEnd2()//五子棋
{
	if (!hasPlaceOk())
	{
		return isEnd = true;
	}
	vector<int>tmp = *(manual.end() - 1);
	if (maxNumInLine(tmp[0], tmp[1]) >= 5)return isEnd = true;
	return false;
}
bool hasMoveOk()
{
	for (int i = 1; i <= row; i++)for (int j = 1; j <= col; j++)
		for (int ii = 1; ii <= row; ii++)for (int jj = 1; jj <= col; jj++)
			if (moveOk(i, j, ii, jj))return true;
	return false;
}
bool ifEnd3()
{
	if (turn == 1 && getNum(1) <= 5)return isEnd = true;
	return isEnd = !hasMoveOk();
}
bool ifEnd4()//圈叉棋
{
	vector<int>tmp = *(manual.end() - 1);
	if (maxNumInLine(tmp[tmp.size() - 2], tmp[tmp.size() - 1]) >= 3)return isEnd = true;
	return false;
}
bool ifEnd5()
{
	if (getNum(2) == 3)playMod = 1, moveMod = moveOkMod = 0;
	return ifEnd4();
}
bool ifEnd6()
{
	if (getNum(2) == 3)playMod = 1, moveMod = 0, moveOkMod = 3;
	return ifEnd4();
}
bool ifEnd7()//独立钻石棋
{
	if (getNum(1)+getNum(2) <= 1)return isEnd = true;
	return isEnd = !hasMoveOk();
}
func_bool f_ifEnd[] = { ifEnd0, ifEnd1, ifEnd2, ifEnd3, ifEnd4, ifEnd5, ifEnd6, ifEnd7 };
bool ifEnd()
{
	return f_ifEnd[ifEndMod]();
}
//end 是否结束

//begin 行棋
void play0()//输入坐标落子
{
	display();
	int r=-1, c=-1;
	cout << "输入落子坐标(行,列)\n输入0 0可查看棋谱\n";	
	cinInt2(r,c);
	if (r == 0 && c == 0)
	{
		displayManual();
		return play0();
	}
	if (placeOk(r, c))
	{
		place(r, c);
		vector<int>tmp;
		tmp.insert(tmp.end(), r);
		tmp.insert(tmp.end(), c);
		manual.insert(manual.end(), tmp);
	}
	else
	{
		cout << "输入坐标有误,请重新输入";
		Sleep(1500);//暂停...ms
		play0();
	}
}
void play1()//输入坐标移子
{
	display();
	int r, c, r2, c2;
	cout << "输入移子坐标(行,列)->(行,列)\n输入0 0可查看棋谱\n";
	cinInt2(r, c);
	if (r == 0 && c == 0)
	{
		displayManual();
		return play1();
	}
	cinInt2(r2, c2);
	if (moveOk(r, c, r2, c2))
	{
		move(r, c, r2, c2);
		vector<int>tmp;
		tmp.insert(tmp.end(), r);
		tmp.insert(tmp.end(), c);
		tmp.insert(tmp.end(), r2);
		tmp.insert(tmp.end(), c2);
		manual.insert(manual.end(), tmp);
	}
	else
	{
		cout << "输入坐标有误,请重新输入";
		Sleep(1500);//暂停...ms
		play1();
	}
}
func_void f_play[] = { play0, play1 };
void play()
{
	while (isEnd == false)
	{
		f_play[playMod]();
		display();
		changeTurn();
		ifEnd();		
	}	
	cout << "游戏结束";
	Sleep(5000);
}
//end 行棋

int main()
{
	freopen(dataInTxt, "r", stdin);
	init();
	freopen("CON", "r", stdin);
	cin.clear();
	play();
	return 0;
}

2,代码V2.0

#include<iostream>
#include<string>
#include<vector>
#include<windows.h>
#include<iomanip>
#include<algorithm>
using namespace std;

#define MAXR 20 //棋盘最大行数
#define MAXC 20 //棋盘最大列数
#define PLAYER 2 //下棋人数
#define MOVELINE 10 //需要去掉的边的最大数量

#define cinInt(x) while(!(cin>>x)){cin.clear();cin.ignore();}
#define cinInt2(x,y) cinInt(x)cinInt(y)

typedef void(*func_void)();
typedef void(*func_void2)(int, int);
typedef void(*func_void4)(int, int, int, int);
typedef string(*func_string1)(int);
typedef string(*func_string2)(int, int);
typedef bool(*func_bool)();
typedef bool(*func_bool2)(int, int);
typedef bool(*func_bool4)(int, int, int, int);

const char* dataInTxt = "D:\init.txt";//存放本地配置的文件
const int dr[] = { -1, -1, 0, 1, 1, 1, 0, -1 };//用8个方向向量实现flat技术
const int dc[] = { 0, 1, 1, 1, 0, -1, -1, -1 };//从上开始,顺时针转,到左上结束
const int errValue = -1;//无效点都配为-1

//begin 配置数据,缩进代表子参数
int row, col;//整个棋盘一共row行,编号1-row,一共col列,编号1-col
int board[MAXR + 2][MAXC + 2];//棋盘的每个格点,=1表示一方的棋子,=2表示另外一方的棋子,0表示空,-1表示无效格子
int boardStyle;//棋盘样式,=0表示只有横线和竖线的棋盘,=1表示除了横竖还有米字的棋盘,=2表示除了横竖和米字还需要去掉边
int isMi[MAXR + 2][MAXC + 2];//每个格点是不是米字型,当boardStyle=1或2时有此参数
int removeLineNum; //需要去掉的边的数量,当当boardStyle=2时有此参数
int removeLines[MOVELINE][4]; //需要去掉的边的两点坐标
int chessman;//棋子样式
int displayContent;//额外显示内容,=0表示显示各方棋子数量,=1表示不显示
int turn;//轮到谁下,=1,=2
int howToChangeTurn;//如何换下棋方,=0表示正常轮换,=1表示双方可任意顺序操作,=2表示双方轮换但玩家一次可以操控多个棋子
int turnOptNum[PLAYER+1];//双方一次可以操控棋子的个数,howToChangeTurn=2时有此参数 
int playMod;//表示行棋的方式,=0表示落子,=1表示移子,=2表示其他
int placeMod;//表示落子的具体规则,=0表示仅落子,=1表示夹吃
int placeOkMod;//表示能否落子的具体规则,=0表示有空格即可,=1表示有空格而且还要落子改变其他棋子
int moveMod;//表示移动棋子的具体规则,=0表示移到相邻处,=1表示跳跃并吃子,=2表示老虎棋
int moveOkMod;//表示能否移动棋子的具体规则,=0表示移到相邻处,=1表示跳跃并吃子,=2表示老虎棋
int ifEndMod;//表示是否结束具体规则,=1表示一方不可下就换另一方,双方都不能下就结束,=2表示五子棋,=3表示老虎棋
int endNum;//表示剩余多少棋子就判负,当ifEndMod=3时有此参数
//end 配置数据

bool isEnd;//游戏是否结束
vector<vector<int>>manual;
int temp[MAXR + 2][MAXC + 2]; //board的备份

bool isErrLoca(int r, int c)
{
	if (r<1 || r>row)return true;
	if (c<1 || c>col)return true;
	return board[r][c] == errValue;
}

//begin 初始化
void initBoard()
{
	for (int i = 0; i <= MAXR + 1; i++)for (int j = 0; j <= MAXC + 1; j++)
	{
		board[i][j] = errValue, isMi[i][j] = 0;
	}
	for (int i = 1; i <= row; i++)for (int j = 1; j <= col; j++)
	{
		cinInt(board[i][j]);
	}
	cinInt(boardStyle);
	if (boardStyle == 1 || boardStyle == 2)
	{
		for (int i = 1; i <= row; i++)for (int j = 1; j <= col; j++)
		{
			cinInt(isMi[i][j]);
		}
	}
	if (boardStyle == 2)
	{
		cinInt(removeLineNum);
		for (int i = 0; i < removeLineNum; i++) {
			for (int j = 0; j < 4; j++)cinInt(removeLines[i][j]);
		}
	}
}
void init()//读取配置,完成变量初始化
{
	cinInt2(row, col);
	if (row <= 0 || col <= 0)
	{
		isEnd = true;
		return;
	}
	initBoard();
	cinInt2(chessman, displayContent);
	cinInt(turn);
	isEnd = false;
	cinInt(howToChangeTurn);
	if (howToChangeTurn == 2) {
		cinInt2(turnOptNum[1], turnOptNum[2]);
	}
	cinInt(playMod);
	if (playMod == 0)
	{
		cinInt2(placeMod, placeOkMod);
	}
	else if (playMod == 1)
	{
		cinInt2(moveMod, moveOkMod);
	}
	cinInt(ifEndMod);
	if (ifEndMod == 3)cinInt(endNum);
}
//end 初始化

//begin 棋子样式
string getChessman0(int num)//黑白棋
{
	if (num == 1)return "●";
	if (num == 2)return "▲";
	return "?";
}
string getChessman1(int num)
{
	return "?";
}
func_string1 f_getChessman[] = { getChessman0, getChessman1 };
string getChessman(int num)
{
	return f_getChessman[chessman](num);
}
//end 棋子样式

//begin 棋子数量
int getNum(int key)
{
	int ans = 0;
	for (int i = 1; i <= row; i++)for (int j = 1; j <= col; j++)
		ans += (board[i][j] == key);
	return ans;
}
//end 棋子数量

//begin 棋盘
string getString0(int r, int c)
{
	if (board[r][c] > 0)return getChessman(board[r][c]);
	if (r == 1)
	{
		if (c == 1)return "┌";
		if (c == col)return "┐";
		return "┬";
	}
	if (r == row)
	{
		if (c == 1)return "└";
		if (c == col)return "┘";
		return "┴";
	}
	if (c == 1)return "├";
	if (c == col)return "┤";
	return "┼";
}
string getString1(int r, int c)
{
	if (board[r][c] > 0)return getChessman(board[r][c]);
	return "  ";
}
func_string2 f_getString[] = { getString0, getString1, getString1};
string getString(int r, int c)
{
	return f_getString[boardStyle](r, c);
}
//end 棋盘

//begin 显示界面
void addedDisplay0()
{
	cout << getChessman(1) << "有" << getNum(1) << "个,";
	cout << getChessman(2) << "有" << getNum(2) << "个\n";
}
void addedDisplay1()
{
	return;
}
int getOddEven(int k1, int k2)
{
	int ans = 0;
	for (int i = 1; i <= row; i++)for (int j = 1; j <= col; j++)
	{
		if (board[i][j] > 0)ans += (i + k1) % 2 * ((j + k2) % 2);
	}
	return ans;
}
void addedDisplay2()
{
	cout << "(奇,奇)有" << getOddEven(0, 0) << "个,(偶,偶)有" << getOddEven(1, 1) << "个,";
	cout << "(奇,偶)有" << getOddEven(0, 1) << "个,(偶,奇)有" << getOddEven(1, 0) << "个\n";
}
func_void f_addedDisplay[] = { addedDisplay0, addedDisplay1, addedDisplay2 };

void display0()
{
	cout << ' ';
	for (int i = 1; i <= col; i++)cout << ' ' << i % 10;
	for (int i = 1; i <= row; i++)
	{
		cout << endl << setw(2) << i;
		for (int j = 1; j <= col; j++)
		{
			cout << getString(i, j);
		}
	}
	cout << endl;
}
bool ismovedLine(int i1, int j1, int i2, int j2)
{
	for (int i = 0; i < removeLineNum; i++) {
		auto p = removeLines[i];
		if (p[0] == i1 && p[1] == j1 && p[2] == i2 && p[3] == j2)return true;
		if (p[0] == i2 && p[1] == j2 && p[2] == i1 && p[3] == j1)return true;
	}
	return false;
}
bool hasHorizontalLine(int i, int j)//往右横线
{
	if (isErrLoca(i, j) || isErrLoca(i, j + 1))return false;
	return !ismovedLine(i, j, i, j + 1);
}
bool hasVerticalLine(int i, int j)//往下竖线
{
	if(isErrLoca(i, j) || isErrLoca(i + 1, j))return false;
	return !ismovedLine(i, j, i + 1, j);
}
bool hasRightSlash(int i, int j)//往右下的斜线
{
	if (isErrLoca(i, j) || isErrLoca(i + 1, j + 1))return false;
	return isMi[i][j] || isMi[i + 1][j + 1] && !ismovedLine(i, j, i + 1, j + 1);
}
bool hasLeftSlash(int i, int j)//右边和下边连起来的斜线
{
	if (isErrLoca(i + 1, j) || isErrLoca(i, j + 1))return false;
	return isMi[i + 1][j] || isMi[i][j + 1] && !ismovedLine(i + 1, j, i, j + 1);
}
void display1()
{
	for (int i = 1; i <= col; i++)cout << "   " << i % 10;
	for (int i = 1; i <= row; i++)
	{
		cout << endl << setw(2) << i;
		for (int j = 1; j <= col; j++)
		{
			cout << getString(i, j);
			if (j == col)continue;
			if (hasHorizontalLine(i,j))cout << "┄";
			else cout << "  ";
		}
		if (i == row)continue;
		cout << endl << "  ";
		for (int j = 1; j <= col; j++)
		{
			if (hasVerticalLine(i,j))cout << "┆";
			else cout << "  ";
			if (j == col)break;
			if (hasRightSlash(i, j))cout << "╲";
			else if (hasLeftSlash(i, j))cout << "╱";
			else cout << "  ";
		}
	}
	cout << endl;
}
func_void f_display[] = { display0, display1, display1 };
void display()
{
	system("cls");
	f_display[boardStyle]();
	f_addedDisplay[displayContent]();
	cout << "轮到" << turn << getChessman(turn) << "下\n";
}

void displayManual()//显示棋谱
{
	vector<int>tmp;
	for (auto it = manual.begin(); it != manual.end(); it++)
	{
		tmp = *it;
		for (auto it = tmp.begin(); it != tmp.end(); it++)cout << *it << " ";
	}
	Sleep(5000);
}
//end 显示界面

int numInLine(int row, int col, int u, int ref)//坐标(row,col),方向向量u,返回该方向有多少该色棋子,不包括此坐标本身
{
	int i = row + dr[u], j = col + dc[u], sum = 0;
	while (board[i][j] == ref)sum++, i += dr[u], j += dc[u];
	return sum;
}
int numInLine(int row, int col, int u)//坐标(row,col),方向向量u,返回该方向有多少连续同色棋子,不包括此坐标本身
{
	int ref = board[row][col];
	if (ref == 0)return 0;
	return numInLine(row,col,u,ref);
}
int neighborNum(int row, int col, int ref)//上下左右4个邻居里面,有几个该色棋子
{
	int ans = 0;
	for (int u = 0; u < 8; u += 2)if (numInLine(row, col, u, ref))ans++;
	return ans;
}
int maxNumInLine(int row, int col)//坐标(row,col),返回四条直线最多的有多少连续同色棋子,包括此坐标本身
{
	int ans = 0;
	for (int u = 0; u < 4; u++)ans = max(ans, numInLine(row, col, u) + numInLine(row, col, u + 4));
	return ans + 1;
}

//begin 下棋方控制
void changeTurn0() //黑白棋
{
	turn = 3 - turn; //turn在1,2之间轮换
}
void changeTurn2()
{
	static int optNum = 0;
	optNum++;
	if (optNum == turnOptNum[turn])turn = 3 - turn, optNum = 0;
}
func_void f_changeTurn[] = { changeTurn0, changeTurn0, changeTurn2 };
void changeTurn()
{
	return f_changeTurn[howToChangeTurn]();
}
//end 下棋方控制

//begin 落子
void place0(int r, int c) //仅落子,如五子棋
{
	return;
}
void place1(int r, int c)//夹吃,如黑白棋
{
	int k = board[r][c], tr, tc;
	for (int i = 0; i < 8; i++)
	{
		tr = r, tc = c;
		while (true)
		{
			tr += dr[i], tc += dc[i];
			if (tr <= 0 || tr >= row + 1 || tc <= 0 || tc >= col + 1)break;
			if (board[tr][tc] == 3 - k)continue;
			if (board[tr][tc] == k)
			{
				for (int jr = r + dr[i], jc = c + dc[i]; jr != tr || jc != tc; jr += dr[i], jc += dc[i])
					board[jr][jc] = k;
			}
			break;
		}
	}
}
func_void2 f_place[] = { place0, place1 };
void place(int r, int c)
{
	board[r][c] = turn;
	f_place[placeMod](r, c);
}
//end 落子

//begin 移子
void move0(int r, int c, int r2, int c2)//仅移子
{
	board[r2][c2] = board[r][c], board[r][c] = 0;
}
void move1(int r, int c, int r2, int c2)//移子或跳吃子,吃掉被跳过的棋子
{
	move0(r, c, r2, c2);
	if (abs(r - r2) > 1 || abs(c - c2) > 1)board[(r + r2) / 2][(c + c2) / 2] = 0;
}
void move2(int r, int c, int r2, int c2)//双方不同
{
	if (turn == 1)move0(r, c, r2, c2);
	else move1(r, c, r2, c2);
}
void move3(int r, int c, int r2, int c2)//双方不同
{
	move0(r, c, r2, c2);
	if (turn == 1)return;
	if (neighborNum(r2, c2, 3-board[r2][c2]) != 1)return;
	for (int u = 0; u < 8; u += 2)
		if(board[r2 + dr[u]][c2 + dc[u]] == 3 - board[r2][c2])board[r2 + dr[u]][c2 + dc[u]] = 0;
}
func_void4 f_move[] = { move0, move1, move2, move3 };
void move(int r, int c, int r2, int c2)
{
	f_move[moveMod](r, c, r2, c2);
}
//end 移子

//begin 能否落子
bool placeOk0(int r, int c)//五子棋,圈叉棋
{
	return true;
}
int getChangeNum(int r, int c)//落子前后有多少棋子改变
{
	for (int i = 1; i <= row; i++)for (int j = 1; j <= col; j++)
		temp[i][j] = board[i][j];
	place(r, c);
	int changeNum = 0;
	for (int i = 1; i <= row; i++)for (int j = 1; j <= col; j++)
		changeNum += (temp[i][j] != board[i][j]), board[i][j] = temp[i][j];
	return changeNum;
}
bool placeOk1(int r, int c)//黑白棋
{
	return getChangeNum(r, c) > 1;
}
func_bool2 f_placeOk[] = { placeOk0, placeOk1 };
bool placeOk(int r, int c) //能否落子
{
	if (r<1 || r>row || c<1 || c>col)return false;
	if (board[r][c] != 0)return false;
	return f_placeOk[placeOkMod](r, c);
}
//end 能否落子

//begin 能否移子
bool isJumpPos(int r, int c, int r2, int c2)
{
	return r == r2 && abs(c - c2) == 2 || c == c2 && abs(r - r2) == 2 ||
		abs(c - c2) == 2 && abs(r - r2) == 2 && isMi[(r + r2) / 2][(c + c2) / 2];
}
bool moveOkJump0(int r, int c, int r2, int c2)//跳吃,吃掉被跳过的任意棋子
{
	if (board[r2][c2] != 0)return false;//只能到空地
	return isJumpPos(r, c, r2, c2);
}
bool moveOkJump1(int r, int c, int r2, int c2)//跳吃,吃掉被跳过的对方棋子
{
	return moveOkJump0(r, c, r2, c2) && board[(r + r2) / 2][(c + c2) / 2] == 3 - board[r][c];
}
bool moveOkJump2(int r, int c, int r2, int c2)
{
	if (r>1 && board[r2][c2] != 3 - board[r][c])return false;//只能跳到对方棋子并吃掉
	return isJumpPos(r, c, r2, c2) && board[(r + r2) / 2][(c + c2) / 2] != 0;
}
bool moveOk0(int r, int c, int r2, int c2)//移到相邻处
{
	if (board[r2][c2] != 0)return false;//只能到空地
	if (r == r2 && c == c2)return false;
	if (abs(r - r2) > 1 || abs(c - c2) > 1)return false;//不是8邻居	
	if (r == r2 || c == c2)return true;//上下左右
	return isMi[r][c] || isMi[r2][c2];//有斜线
}
bool moveOk1(int r, int c, int r2, int c2)//移子或跳吃
{
	return moveOk0(r, c, r2, c2) || moveOkJump1(r, c, r2, c2);
}
bool moveOk2(int r, int c, int r2, int c2)
{
	if (turn == 1)return moveOk0(r, c, r2, c2);
	else return moveOk1(r, c, r2, c2);
}
bool moveOk3(int r, int c, int r2, int c2)
{
	if (board[r2][c2] != 0)return false;//只能到空地
	return true;
}
bool moveOk4(int r, int c, int r2, int c2)
{
	return moveOkJump0(r, c, r2, c2);
}
bool moveOk5(int r, int c, int r2, int c2)
{
	if (turn == 1)return moveOk0(r, c, r2, c2);
	if (r == 1 && c == 2 && r2 == 1 && c2 == 4)return true;
	if (r == 1 && c == 4 && r2 == 1 && c2 == 2)return true;
	if (r > 1 && r2 == 1)return false;// 离开三角形就不能再回来
	if (moveOk0(r, c, r2, c2))return true;
	return moveOkJump2(r, c, r2, c2);
}
func_bool4 f_moveOk[] = { moveOk0, moveOk1, moveOk2, moveOk3, moveOk4, moveOk5};
bool moveOk(int r, int c, int moveOkMod)//只能移自己的棋
{
	if (howToChangeTurn == 1)return true;//独立钻石棋
	return board[r][c] == turn;//一般只能移自己的棋
}
bool moveOk(int r, int c, int r2, int c2)
{
	if (isErrLoca(r, c) || isErrLoca(r2, c2))return false;
	return moveOk(r,c, moveOkMod) && f_moveOk[moveOkMod](r, c, r2, c2);
}
//end 能否移子

//begin 是否结束
bool hasPlaceOk()
{
	for (int i = 1; i <= row; i++)for (int j = 1; j <= col; j++)
		if (placeOk(i, j))return true;
	return false;
}
bool ifEnd0()//不可下就结束
{
	return isEnd = !hasPlaceOk();
}
bool ifEnd1()//黑白棋,一方不可下就换另一方,双方都不能下就结束
{
	isEnd = !hasPlaceOk();
	if (!isEnd)return false;
	changeTurn();
	return isEnd = !hasPlaceOk();
}
bool ifEnd2()//五子棋
{
	if (!hasPlaceOk())
	{
		return isEnd = true;
	}
	vector<int>tmp = *(manual.end() - 1);
	if (maxNumInLine(tmp[0], tmp[1]) >= 5)return isEnd = true;
	return false;
}
bool hasMoveOk()
{
	for (int i = 1; i <= row; i++)for (int j = 1; j <= col; j++)
		for (int ii = 1; ii <= row; ii++)for (int jj = 1; jj <= col; jj++)
			if (moveOk(i, j, ii, jj))return true;
	return false;
}
bool ifEnd3()
{
	if (turn == 1)isEnd = (getNum(1) <= endNum);
	else isEnd = !hasMoveOk();
	return isEnd;
}
bool ifEnd4()//圈叉棋
{
	vector<int>tmp = *(manual.end() - 1);
	if (maxNumInLine(tmp[tmp.size() - 2], tmp[tmp.size() - 1]) >= 3)return isEnd = true;
	return false;
}
bool ifEnd5()
{
	if (getNum(2) == 3)playMod = 1, moveMod = moveOkMod = 0;
	return ifEnd4();
}
bool ifEnd6()
{
	if (getNum(2) == 3)playMod = 1, moveMod = 0, moveOkMod = 3;
	return ifEnd4();
}
bool ifEnd7()//独立钻石棋
{
	if (getNum(1) + getNum(2) <= 1)isEnd = true;
	else isEnd = !hasMoveOk();
	return isEnd;
}
func_bool f_ifEnd[] = { ifEnd0, ifEnd1, ifEnd2, ifEnd3, ifEnd4, ifEnd5, ifEnd6, ifEnd7 };
bool ifEnd()
{
	return f_ifEnd[ifEndMod]();
}
//end 是否结束

//begin 行棋
void play0()//输入坐标落子
{
	display();
	int r = errValue, c = errValue;
	cout << "输入落子坐标(行,列)\n输入0 0可查看棋谱\n";
	cinInt2(r, c);
	if (r == 0 && c == 0)
	{
		displayManual();
		return play0();
	}
	if (placeOk(r, c))
	{
		place(r, c);
		vector<int>tmp;
		tmp.insert(tmp.end(), r);
		tmp.insert(tmp.end(), c);
		manual.insert(manual.end(), tmp);
	}
	else
	{
		cout << "输入坐标有误,请重新输入";
		Sleep(1500);//暂停...ms
		play0();
	}
}
void play1()//输入坐标移子
{
	display();
	int r, c, r2, c2;
	cout << "输入移子坐标(行,列)->(行,列)\n输入0 0可查看棋谱\n";
	cinInt2(r, c);
	if (r == 0 && c == 0)
	{
		displayManual();
		return play1();
	}
	cinInt2(r2, c2);
	if (moveOk(r, c, r2, c2))
	{
		move(r, c, r2, c2);
		vector<int>tmp;
		tmp.insert(tmp.end(), r);
		tmp.insert(tmp.end(), c);
		tmp.insert(tmp.end(), r2);
		tmp.insert(tmp.end(), c2);
		manual.insert(manual.end(), tmp);
	}
	else
	{
		cout << "输入坐标有误,请重新输入";
		Sleep(1500);//暂停...ms
		play1();
	}
}
func_void f_play[] = { play0, play1 };
void play()
{
	while (isEnd == false)
	{
		f_play[playMod]();
		display();
		changeTurn();
		ifEnd();
	}
	cout << "游戏结束";
	Sleep(5000);
}
//end 行棋

int main()
{
	freopen(dataInTxt, "r", stdin);
	init();
	freopen("CON", "r", stdin);
	cin.clear();
	play();
	return 0;
}

三,实例

1,五子棋

(1)配置

五子棋
row=15 col=15
棋盘格点board[][]=
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
棋盘样式boardStyle=0表示只有横线和竖线的棋盘
棋子样式chessman=0表示用●和▲代表双方棋子
额外显示内容displayContent=0显示各方棋子数量
轮到谁下turn=1
如何换下棋方howToChangeTurn=0表示正常轮换
输入行棋方式playMod=0表示双方落子
落子的具体规则placeMod=0表示仅落子,仅当playMod为零时有此参数
能否落子的具体规则placeOkMod=0表示有空格即可
是否结束具体规则ifEndMod=2

(2)运行

(3)测试

(3.1)先手胜

7 7 6 6  6 7 5 7 7 5 7 6  8 6  6 8 9 7  6 4  10 8  11 9  8 7 10 7 8 5  8 4  8 8  8 9  9 5  6 5  9 8  11 8 9 6  9 4  9 9

(3.2)后手胜

7 7  7 8  6 7  6 8  8 7   8 8  9 7  9 8  5 8  10 8

(3.3)和局

7 7 6 6 6 7 5 7 7 5 7 6 8 6 6 8 9 7 6 4 10 8 
11 9 8 7 10 7 8 5 8 4 8 8 8 9 9 5 6 5 9 8  
11 8 9 9 9 6 10 5 11 5 11 7 12 6 8 10 7 11 
9 10 9 11 10 10 7 10 11 10 12 10 10 9 
12 11 12 9 11 11 10 11 10 12 9 13 13 9 
14 8 13 11 5 6 4 6 3 5 7 9 7 12 7 8 8 11 
6 13 10 4 11 3 10 6 6 3 6 2 7 4 10 3 10 2 
5 4 9 12 5 5 11 12 8 12 12 12 13 12 12 13  
12 14 14 11 15 11 5 8 13 8 14 7 11 6 12 7 
9 4 5 9 8 3 7 2 5 3 5 2 7 1 4 4 11 2 12 1 
11 4 12 5 8 13 8 14 6 11 5 10 5 11 4 8 4 7 
6 10 3 7 6 9 4 9 4 10 3 8 3 6 3 10 3 9 2 10 
13 10 14 9 10 13 9 14 10 15 10 14 11 13 
11 14 13 14 12 4 13 4 12 3 12 2 13 2 14 1 
13 3 13 1 11 1 9 3 9 2 9 1 8 2 7 3 8 1 10 1 
12 8 13 6 13 7 13 5 14 6 14 5 15 5 15 3  
15 4 15 6 15 7 15 8 15 9 14 10 15 10 4 11 
6 12 4 5 5 12 4 12 7 13 4 13 4 14 5 13 
2 7 2 9 2 8 1 8 1 7 1 6 2 6 2 5 4 3 4 2 4 1 
5 1 6 1 2 4 2 3 3 3 3 4 1 4 1 5 1 3 1 2 1 1 
2 2 2 1 3 2 3 1 3 12 3 11 2 12 2 11 3 13  
2 13 3 14 2 14 3 15 2 15 1 11 1 12 1 13  
1 14 1 15 1 9 1 10 7 14 6 14 5 14 4 15  
5 15 6 15 7 15 8 15 9 15 11 15 12 15 13 15  
14 15 15 15 15 12 14 12 13 13 14 14 15 14  
14 13 15 13 14 4 14 3 14 2 15 2 15 1

(4)未实现特殊规则

没有实现禁手,不影响游戏规则的完备性。

2,黑白棋

(1)配置

黑白棋
row=8 col=8
棋盘格点board[][]=
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 2 1 0 0 0
0 0 0 1 2 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
棋盘样式boardStyle=0表示只有横线和竖线的棋盘
棋子样式chessman=0表示用●和▲代表双方棋子
额外显示内容displayContent=0显示各方棋子数量
轮到谁下turn=1
如何换下棋方howToChangeTurn=0表示正常轮换
输入行棋方式playMod=0表示双方落子
落子的具体规则placeMod=1表示夹吃,仅当playMod为零时有此参数
能否落子的具体规则placeOkMod=1表示有空格而且还要落子改变其他棋子
是否结束具体规则ifEndMod=1表示一方不可下就换另一方,双方都不能下就结束

(2)运行

(3)测试

(3.1)▲方胜利,51:0,含连下现象
3 4 3 5 4 6 3 7 4 7   3 3 2 7 5 6 3 6 5 3 
4 3 1 8 1 7 1 6 2 5   1 5 2 4 2 6 2 3 2 8 
6 3 3 8 6 4 1 3 5 7   6 5 1 4 6 7 1 2 1 1 
4 8 5 8 6 6 2 2 6 8   3 2 2 1 3 1 
4 2 5 2 4 1 5 1 7 8   7 7 7 6 7 5 7 4
从4 2开始出现连下现象
(3.2)●方胜利,下满
3 4 3 5 4 6 3 3 2 4   3 6 2 3 1 3 1 4 1 5
2 5 2 6 1 6 1 7 6 5   5 6 4 3 4 2 5 3 6 4 
5 2 6 1 3 2 3 1 4 1   5 1 6 3 6 2 2 1 7 3 
7 1 2 2 5 7 6 6 6 7   5 8 1 1 1 2 1 8 7 2 
8 3 8 1 8 2 7 4 8 4   7 5 8 5 7 8 7 6 8 6 
6 8 4 7 8 8 8 7 7 7   4 8 2 7 3 7 3 8 2 8
(3.3)未下满但双方都无法下
3 4 3 3 4 3 3 5 2 2   1 1 2 3 3 2 2 4 2 5 
1 2 1 3 2 1 3 1 1 4   1 5 1 6 1 7 2 6 2 7 
6 5 5 3 3 6 3 7 4 2   5 6 4 6 5 1 4 1 5 2 
6 1 7 1 6 2 6 3 6 4   4 7 7 2 7 3 7 4 7 6 
6 6 7 5 8 6 7 7 6 8   7 8 8 8
(3.4)和局
3 4 5 3 6 4 7 5 5 2   5 1 6 5 3 5 5 6 3 3 
2 5 4 6 3 2 2 2 7 4   6 3 1 1 5 7 4 7 3 7
7 2 4 3 3 6 2 3 4 2   6 7 2 4 8 1 6 1 7 1 
6 2 1 2 1 3 8 4 7 3   8 2 8 3 2 6 8 5 6 6 
2 1 8 6 6 8 5 8 3 1   1 4 4 1 7 8 7 6 7 7 
8 8 8 7 4 8 3 8 2 8   2 7 1 6 1 8 1 5 1 7

3,田字上谷老虎棋

(1)配置

老虎棋
row=7 col=5
棋盘格点board[][]=
-1 0 0 0 -1
-1 0 0 0 -1
1 1 1 1 1
1 0 0 0 1
1 0 2 0 1
1 0 0 0 1
1 1 1 1 1
棋盘样式boardStyle=1表示除了横竖还有米字的棋盘
米字型isMi[][]=
0 0 0 0 0
0 0 1 0 0
0 0 0 0 0
0 1 0 1 0
0 0 1 0 0
0 1 0 1 0
0 0 0 0 0
棋子样式chessman=0表示用●和▲代表双方棋子
额外显示内容displayContent=0显示各方棋子数量
轮到谁下turn=1
如何换下棋方howToChangeTurn=0表示正常轮换
输入行棋方式playMod=1表示移子
移动棋子的具体规则moveMod=2
能否移动棋子的具体规则moveOkMod=2
是否结束具体规则ifEndMod=3

endNum=5

(2)运行

(3)测试

(3.1)羊只剩5只,老虎胜
3 2 4 2 5 3 4 3 3 5 4 4 4 3 2 3 3 4 3 3 2 3 4 3 4 2 5 2 4 3 4 2
4 4 4 3 4 2 4 4 5 2 5 3 4 4 6 2 5 1 4 2 6 2 5 1 4 2 5 2 5 1 5 3
3 1 4 2 5 3 3 1 7 3 6 3 3 1 5 1 7 1 6 2 5 1 7 3 6 3 6 2 7 3 7 1
5 5 5 4 7 1 5 1 7 5 6 4 5 1 7 3
(3.2)老虎无法移动,羊胜
3 3 4 2 5 3 4 3 6 1 6 2 4 3 3 3 6 2 5 2 3 3 2 3 5 2 5 3 2 3 2 2
3 4 3 3 2 2 2 3 5 3 4 3 2 3 1 2 3 5 3 4 1 2 2 3 4 5 4 4 2 3 2 2 
3 4 2 4 2 2 2 3 4 4 3 4 2 3 1 3 3 2 2 3 1 3 1 4 3 1 3 2 1 4 1 3 
3 2 2 2 1 3 1 4 4 2 3 2 1 4 1 3 2 4 1 4 1 3 1 2 2 3 1 3 1 2 2 3 
5 5 4 4 2 3 2 4 1 3 2 3

4,三角上谷老虎棋10羊版

(1)配置

老虎棋
row=6 col=5
棋盘格点board[][]=
-1 2 -1 2 -1
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
1 1 1 1 1
1 1 1 1 1
棋盘样式boardStyle=2
米字型isMi[][]=
0 0 0 0 0
0 0 1 0 0
0 1 0 1 0
0 0 1 0 0
0 1 0 1 0
0 0 0 0 0
removeLineNum = 2
去掉从1 2到2 2
去掉从1 4到2 4
棋子样式chessman=0表示用●和▲代表双方棋子
额外显示内容displayContent=0显示各方棋子数量
轮到谁下turn=1
如何换下棋方howToChangeTurn=2
turnOptNum=1 2 羊走一步,虎走两步
输入行棋方式playMod=1表示移子
移动棋子的具体规则moveMod =0
能否移动棋子的具体规则moveOkMod =5
是否结束具体规则ifEndMod=3

endNum=5

(2)运行

省略了最上面的三角形的横线。 

(3)测试

(3.1)老虎无法移动,羊胜

5 1 4 1 1 2 2 3 1 4 3 2 5 2 4 2 3 2 3 3 2 3 3 2 5 4 4 3 3 2 3 1 3 3 3 2 5 5 5 4 3 2 3 3 3 1 3 2 5 4 4 4 3 2 2 3 3 3 3 4 4 3 3 3 3 4 4 3 2 3 3 4 6 5 5 5 3 4 4 5 4 3 5 4 3 3 4 3 5 4 6 5 4 5 5 4 6 1 5 1 5 4 4 5 6 5 5 4 6 4 6 5 5 4 6 4 4 5 5 4 4 1 3 1 5 4 4 5 6 4 5 4 3 1 2 1 5 4 6 4 4 5 5 4 2 1 2 2 5 4 4 5 6 4 5 4 2 2 2 3 5 4 6 4 4 5 5 4 2 3 2 4 5 4 4 5 6 4 5 4 2 4 2 5 5 4 6 4 4 5 5 4 2 5 3 5 5 4 4 5 6 4 5 4 5 1 4 1 5 4 6 4 4 5 5 4 3 5 4 5

(4)未实现特殊规则

未限制双虎走完后必须实有线紧邻。

未限制双虎轮换先行,所以在判断游戏是否结束时,只要虎A走了一步,虎B没地方走,但是虎A还是地方走,就不会被判定为游戏结束。

5,三角上谷老虎棋12羊版

(1)配置

老虎棋
row=6 col=5
棋盘格点board[][]=
-1 2 -1 2 -1
0 0 0 0 0
0 0 0 0 0
1 0 0 0 1
1 1 1 1 1
1 1 1 1 1
棋盘样式boardStyle=2
米字型isMi[][]=
0 0 0 0 0
0 0 1 0 0
0 1 0 1 0
0 0 1 0 0
0 1 0 1 0
0 0 0 0 0
removeLineNum = 2
去掉从1 2到2 2
去掉从1 4到2 4
棋子样式chessman=0表示用●和▲代表双方棋子
额外显示内容displayContent=0显示各方棋子数量
轮到谁下turn=1
如何换下棋方howToChangeTurn=2
turnOptNum=1 2 羊走一步,虎走两步
输入行棋方式playMod=1表示移子
移动棋子的具体规则moveMod =0
能否移动棋子的具体规则moveOkMod =5
是否结束具体规则ifEndMod=3

endNum=5

(2)运行

(3)测试

6,正定老虎棋

(1)配置

老虎棋
row=5 col=5
棋盘格点board[][]=
0 0 2 0 0
0 0 0 0 0
0 0 0 0 0
1 1 1 1 1
1 1 1 1 1
棋盘样式boardStyle =0
棋子样式chessman=0表示用●和▲代表双方棋子
额外显示内容displayContent=0显示各方棋子数量
轮到谁下turn=1
如何换下棋方howToChangeTurn=0
输入行棋方式playMod=1表示移子
移动棋子的具体规则moveMod =3
能否移动棋子的具体规则moveOkMod =0
是否结束具体规则ifEndMod=3
endNum=4

(2)运行

(3)测试

(3.1)老虎无法移动,羊胜

4 1 3 1 1 3 1 2 4 2 3 2 1 2 1 1 3 2 2 2 1 1 2 1 4 3 3 3 2 1 1 1 3 3 2 3 1 1 2 1 2 3 1 3 2 1 1 1 3 1 2 1 1 1 1 2 2 1 1 1

(3.2)羊只剩4只,老虎胜

4 3 3 3 1 3 2 3 4 2 3 2 2 3 3 3 4 4 3 4 3 3 4 3 4 1 3 1 4 3 4 2 5 1 5 2 4 2 4 1 3 4 3 3 4 1 4 2

7,圈叉棋

本文实现了圈叉棋,不过不是把棋子落到格子中,而是落到格点上,逻辑是一样的。

(1)配置

圈叉棋
row=3 col=3
棋盘格点board[][]=
0 0 0 
0 0 0 
0 0 0 
棋盘样式boardStyle=0
棋子样式chessman=0表示用●和▲代表双方棋子
额外显示内容displayContent=1
轮到谁下turn=1
如何换下棋方howToChangeTurn=0表示正常轮换
行棋方式playMod=0
placeMod=0
placeOkMod=0
是否结束具体规则ifEndMod=4

(2)运行

(3)测试

(3.1)先手胜,横线
3 1 1 1 3 2 2 3 3 3
(3.2)后手胜,竖线
1 1 1 2 1 3 2 2 2 1 3 2
(3.3)先手胜,右斜线
1 1 2 1 2 2 2 3 3 3
(3.4)后手胜,左斜线
1 1 2 2 1 2 1 3 2 1 3 1

8,米字棋(移一格版)

(1)配置

米字棋
row=3 col=3
棋盘格点board[][]=
0 0 0 
0 0 0 
0 0 0 
棋盘样式boardStyle=1
isMi[]=
0 0 0
0 1 0 
0 0 0
棋子样式chessman=0表示用●和▲代表双方棋子
额外显示内容displayContent=1
轮到谁下turn=1
如何换下棋方howToChangeTurn=0表示正常轮换
行棋方式playMod=0
placeMod=0
placeOkMod=0
是否结束具体规则ifEndMod=5

(2)运行

       

(3)测试

(3.1)先手胜
2 2 1 1 3 2 1 2 1 3 3 1 2 2 2 3 1 1 2 1 3 2 3 3
(3.2)先手胜
2 2 1 2 3 1 1 3 1 1 2 1 3 1 3 2 1 3 2 3 3 2 3 3
(3.3)后手胜
2 2 1 1 1 2 3 2 3 1 1 3 2 2 2 1 1 3 2 2 1 2 1 3 3 2 3 3

PS:这2个先手胜的数据,就是先手必胜策略的2种情况。

9,米字棋(任意移动版)

(1)配置

米字棋
row=3 col=3
棋盘格点board[][]=
0 0 0 
0 0 0 
0 0 0 
棋盘样式boardStyle=1
isMi[]=
0 0 0
0 1 0 
0 0 0
棋子样式chessman=0表示用●和▲代表双方棋子
额外显示内容displayContent=1
轮到谁下turn=1
如何换下棋方howToChangeTurn=0表示正常轮换
行棋方式playMod=0
placeMod=0
placeOkMod=0
是否结束具体规则ifEndMod=6

其实,和米字棋的配置,只有最后一个数字不一样,而实际调用的代码,也只有几行不一样。

(2)运行

(3)测试

(3.1)先手胜

2 2 1 2 1 3 3 1 2 3 2 1 2 2 3 3

(3.2)后手胜
2 2 1 1 1 2 3 2 1 3 3 1 1 2 2 1 1 1 3 3

10,独立钻石棋

(1)配置

独立钻石棋
row=7 col=7
棋盘格点board[][]=
-1 -1 2 1 2 -1 -1
-1 -1 1 2 1 -1 -1
2 1 2 1 2 1 2
1 2 1 0 1 2 1
2 1 2 1 2 1 2
-1 -1 1 2 1 -1 -1 
-1 -1 2 1 2 -1 -1
棋盘样式boardStyle=1
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
棋子样式chessman=0表示用●和▲代表双方棋子
额外显示内容displayContent=2
轮到谁下turn=1
如何换下棋方howToChangeTurn=1表示只有一方
行棋方式playMod=1
moveMod=1
moveOkMod=4
是否结束具体规则ifEndMod=7

PS:本来只要我写的是,全部是同色棋子,只要修改turn的逻辑,一直是turn=1就行。

后来为了便于从奇偶性的角度推导答案,我就改成了用双色棋子表示,turn就无所谓了,但是要注意就是不像其他游戏,轮到谁下的时候只能移动自己的棋子,这里就没有这个限制。

(2)运行

(3)测试

2 4 4 4 3 2 3 4 5 3 3 3 5 1 5 3 2 3 4 3 3 1 5 1 5 4 5 2 5 1 5 3 3 5 3 3 1 5 3 5 1 3 1 5 4 5 2 5 1 5 3 5 3 6 3 4 3 4 3 2 3 2 5 2 5 2 5 4 7 3 5 3 6 5 4 5 5 7 5 5 3 7 5 7 5 4 5 6 5 7 5 5 4 5 6 5 7 4 5 4 7 5 5 5 4 3 4 5 4 5 6 5 5 3 5 5 6 5 4 5 4 6 4 4

11,独立钻石棋变种(八边形)

(1)配置

独立钻石棋
row=7 col=7
棋盘格点board[][]=
-1 -1 2 1 2 -1 -1
-1 2 1 2 1 2 -1
2 1 2 1 2 1 2
1 2 1 2 1 2 1
2 1 2 1 2 1 0
-1 2 1 2 1 2 -1 
-1 -1 2 1 2 -1 -1
棋盘样式boardStyle=1
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
棋子样式chessman=0表示用●和▲代表双方棋子
额外显示内容displayContent=2
轮到谁下turn=1
如何换下棋方howToChangeTurn=1表示只有一方
行棋方式playMod=1
moveMod=1
moveOkMod=4
是否结束具体规则ifEndMod=7

(2)运行

 (3)测试

 5 5 5 7 3 6 5 6 5 7 5 5 3 7 5 7 5 4 5 6 5 7 5 5 7 4 5 4 5 4 5 6 5 2 5 4 7 5 5 5 6 6 4 6 7 3 5 3 5 4 5 2 5 1 5 3 3 4 5 4 5 4 5 2 3 3 5 3 3 1 3 3 4 1 4 3 6 2 4 2 1 4 3 4 3 4 3 2 3 2 5 2 5 2 5 4 5 4 5 6 5 6 3 6 3 6 3 4 1 3 3 3 1 5 3 5 4 3 2 3 4 5 2 5 2 6 2 4 3 4 1 4 2 2 2 4 1 4 3 4

12,独立钻石棋变种(9行9列)

(1)配置

独立钻石棋
row=9 col=9
棋盘格点board[][]=
-1 -1 -1 1 2 1 -1 -1 -1
-1 -1 -1 2 1 2 -1 -1 -1
-1 -1 -1 1 2 1 -1 -1 -1
1 2 1 2 1 2 1 2 1
2 1 2 1 0 1 2 1 2
1 2 1 2 1 2 1 2 1
-1 -1 -1 1 2 1 -1 -1 -1
-1 -1 -1 2 1 2 -1 -1 -1
-1 -1 -1 1 2 1 -1 -1 -1
棋盘样式boardStyle=1
0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 
棋子样式chessman=0表示用●和▲代表双方棋子
额外显示内容displayContent=2
轮到谁下turn=1
如何换下棋方howToChangeTurn=1表示只有一方
行棋方式playMod=1
moveMod=1
moveOkMod=4
是否结束具体规则ifEndMod=7

(2)运行

(3)测试

7 5 5 5 6 7 6 5 6 9 6 7 8 6 6 6 8 4 8 6 9 6 7 6 9 4 9 6 6 6 8 6 9 6 7 6 4 8 6 8 6 8 6 6 6 6 8 6 5 5 7 5 7 4 7 6 8 6 6 6 4 9 6 9 4 7 6 7 6 6 6 8 6 9 6 7 4 6 6 6 6 7 6 5 6 4 6 6 4 4 6 4 6 3 6 5 6 1 6 3 4 1 6 1 4 2 4 4 5 2 5 4 6 6 6 4 6 4 6 2 6 1 6 3 4 4 6 4 6 3 6 5 3 5 5 5 6 5 4 5 2 4 4 4 4 4 4 6 2 6 2 4 4 6 2 6 1 4 3 4 1 6 3 6

7 5 5 5 6 7 6 5 6 9 6 7 8 6 6 6 8 4 8 6 9 6 7 6 9 4 9 6 6 6 8 6 9 6 7 6 4 8 6 8 6 8 6 6 6 6 8 6 5 5 7 5 7 4 7 6 8 6 6 6 4 9 6 9 4 7 6 7 6 6 6 8 6 9 6 7 4 6 6 6 6 7 6 5 6 4 6 6 6 2 6 4 4 2 6 2 6 1 6 3 4 1 6 1 6 4 6 2 2 6 4 6 2 4 2 6 1 6 3 6 1 4 1 6 4 6 2 6 1 6 3 6 6 1 6 3 4 4 2 4 3 6 3 4 2 4 4 4 4 4 6 4 6 3 6 5 6 6 6 4 4 3 6 3 6 3 6 5 

13,独立钻石棋变种(Hopping dots)

无固定开局,以level8为例

(1)配置

独立钻石棋
row=5 col=5
棋盘格点board[][]=
-1 -1 1 -1 -1
-1 1 1 0 -1
0 0 2 1 0
-1 0 1 0 -1
-1 -1 0 -1 -1
棋盘样式boardStyle =1
0 0 0 0 0 
0 1 0 1 0 
0 0 1 0 0
0 1 0 1 0 
0 0 0 0 0 
棋子样式chessman=0表示用●和▲代表双方棋子
额外显示内容displayContent=2
轮到谁下turn=2
如何换下棋方howToChangeTurn=1表示只有一方
行棋方式playMod=1
moveMod=1
moveOkMod=4
是否结束具体规则ifEndMod=7

(2)运行

(3)测试

3 3 3 5 1 3 3 3 4 3 2 3 2 2 2 4 3 5 1 3

  • 16
    点赞
  • 72
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值