华容道(C++版)

    大一结束,为了检验自身实力,专业内的任务是实现华容道最快求解。这里我只针对华容道经典棋局--横刀立马进行分析。

一.棋子设置

    华容道棋子 主要有五种:曹操,横将,竖将,小兵,空格。对于移动的方法,有两种:一,移动空格;二,移动棋子。相对于效率来说,移动空格会更快一点,我才用的就是移动空格。至于设置棋盘,可以建立节点存储一个棋盘,棋盘可以有三种形式:二维数组,一维数组,一个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 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值