大一结束,为了检验自身实力,专业内的任务是实现华容道最快求解。这里我只针对华容道经典棋局--横刀立马进行分析。
一.棋子设置
华容道棋子 主要有五种:曹操,横将,竖将,小兵,空格。对于移动的方法,有两种:一,移动空格;二,移动棋子。相对于效率来说,移动空格会更快一点,我才用的就是移动空格。至于设置棋盘,可以建立节点存储一个棋盘,棋盘可以有三种形式:二维数组,一维数组,一个long long int的数(使用位运算,一个long long int有64个位,每个棋子用三个位表示);对于新手,使用一维数组会比较好理解,因为一维数组与二维数组差不多,但是二维数组很容易炸,所以不推荐,至于位运算可以在一维的基础上进行改造,方便快捷。
0 马超 | 1曹操 | 2曹操 | 3赵云 |
4 马超 | 5曹操 | 6曹操 | 7赵云 |
8黄忠 | 9关羽 | 10关羽 | 11张飞 |
12黄忠 | 13小兵 | 14小兵 | 15张飞 |
16小兵 | 17空 | 18空 | 19小兵 |
那么在进行移动的时候就会有一点小麻烦,就是在判断是否会超出界限,所以我又定义了两个数组,将一维数组做一个类似二维数组的处理,使其更好理解
class Node
{
public:
char chess[21];//棋盘
int step;//步数统计器
Node *pNext;//回溯指针
Node() {}
Node(char chess[21]) :pNext(nullptr)
{
for (int i = 0; i < 20; i++)
{
this->chess[i] = chess[i];
this->pNext = pNext;
}
}
void dispaly()
{
for (int i = 0; i < 20; i++)
{
cout << chess[i];
if ((i + 1) % 4 == 0)
{
cout << endl;
}
}
}
};
在设置棋子时,可以将将军棋设置为如1,1;2,2;3,3;小兵用6,7,8,9表示,空格用0表示,类似的操作对其他棋子进行规划:
int pos1[20] = { 0,1,2,3,0,1,2,3,0,1,2,3,0,1,2,3,0,1,2,3 };//表示列坐标
int pos2[20] = { 0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4 };//表示横坐标
1 | x | x | 2 |
1 | x | x | 2 |
3 | 5 | 5 | 4 |
3 | 6 | 7 | 4 |
8 | 0 | 0 | 9 |
这样做的话,会缺少一个数字来表示曹操,所以并不太好,但是也可用,后面我将介绍一种剪枝方法,会更好一些。
二.移动
移动方法其实比较好理解,首先需要进入一遍循环,遍历查找到空格位置,然后判断两个空格是否在一起,在一起又分为横向连接及竖向连接。
int x = 0, y = 0; int l = 0;
for (int i = 0; i < 20; i++)
{
if (n.chess[i] == '0')
{
x = y;
y = i;
}
}
if (x + 4 == y)
{
l = 1;//竖联合
}
if (x + 1 == y && pos1[x] != 3)
{
l = 2;//横联合
}
如果相连接,在移动的时候需要将联合空格一起上下左右移动一遍,注意只判断可走情况,例如横空上移,只判断其上方是否为横将或曹操。联合移动完之后再单独针对联合空格中的每一个单空格分别进行上下左右移动。注意:(不管空格是否联合,都要分别移动单空格。 )也就是使用穷举法进行走步,虽然代码长度比走兵长,而且逻辑烦,但是不得不承认的是他的效率确实比较快,在后期位运算至少领先走兵5ms。这个代码是检验能力的一步,所以最好自己尝试实现一遍,毕竟不难。在移动的时候可以使用swap来交换两个位置的值,但是如果要追求效率的话,我建议直接赋值,这样会更快一些。
for (int i = 0; i < 20; i++)
{
if (n.chess[i] == '0')
{
x = y;
y = i;
}
}
if (x + 4 == y)
{
l = 1;//竖联合
}
if (x + 1 == y && pos1[x] != 3)
{
l = 2;//横联合
}
void Move(Node n, queue<Node> &q)
{
if (l == 1)//竖联合
{
if (pos1[x] > 0)//向上
{
if (n.chess[x - 4] == '2')
{
Node *n1 = new Node(n.chess);
n1->chess[x - 4] = '0'; n1->chess[y] = '2';
insertq(n, *n1, q);
}
else if (n.chess[x - 4] == '3')
{
Node *n1 = new Node(n.chess);
n1->chess[x] = '1'; n1->chess[x - 8] = '0';
n1->chess[y] = '3'; n1->chess[x - 4] = '0';
insertq(n, *n1, q);
}
}
if (pos1[x] < 3)//向下
{
if (n.chess[y + 4] == '2')
{
Node *n1 = new Node(n.chess);
n1->chess[x] = '2'; n1->chess[y + 4] = '0';
insertq(n, *n1, q);
}
else if (n.chess[y + 4] == '1')
{
Node *n1 = new Node(n.chess);
n1->chess[y + 4] = '0'; n1->chess[y + 8] = '0';
n1->chess[x] = '1'; n1->chess[y] = '3';
insertq(n, *n1, q);
}
}
if (pos[x] > 0)//向左
{
if (n.chess[x - 1] == '1')
{
Node *n1 = new Node(n.chess);
n1->chess[x - 1] = '0'; n1->chess[y - 1] = '0';
n1->chess[x] = '1'; n1->chess[y] = '3';
insertq(n, *n1, q);
}
else if (n.chess[x - 1] == '6'&&n.chess[y - 1] == '6')
{
Node *n1 = new Node(n.chess);
n1->chess[x - 2] = '0'; n1->chess[y - 2] = '0';
n1->chess[x] = '6'; n1->chess[y] = '6';
insertq(n, *n1, q);
}
if (n.chess[x - 1] == '2')
{
Node *n1 = new Node(n.chess);
n1->chess[y] = '2'; n1->chess[x - 1] = '0';
insertq(n, *n1, q);
}
if (n.chess[y - 1] == '2')
{
Node *n1 = new Node(n.chess);
n1->chess[y - 1] = '0';
n1->chess[x] = '2';
insertq(n, *n1, q);
}
}
if (pos[x] < 3)//向右
{
if (n.chess[x + 1] == '1')
{
Node *n1 = new Node(n.chess);
n1->chess[x + 1] = '0'; n1->chess[y + 1] = '0';
n1->chess[x] = '1'; n1->chess[y] = '3';
insertq(n, *n1, q);
}
else if (n.chess[x + 1] == '6'&&n.chess[y + 1] == '6')
{
Node *n1