题目
在3X3的棋盘上放置1到8八个数码,每个数码占一格,且有一个空格。这些数码可以在棋盘上移动,移动规则是:与空格相邻的数码可移入空格。
给出初始棋局和目标棋局,用A*算法,给出数码移动序列。
目标状态:
1 2 3
8 4
7 6 5
算法
while(open不空)
{
sort open,升序
n=open中最小的节点
if(n是目标节点)
{
输出结果
break while
}end if
for(n的每个子节点)
{
n在open中,且n比该节点小:
open中的节点修改为n
n在close中,且n比该节点小:
close中节点估值函数=n的估值函数
open表加入n
n不在两个表中:
open表加入n
}end for
}end while
源码
using System;
using System.Collections.Generic;
using System.Linq;
namespace Astar
{
class AS
{
public string map;
public int node, deep, father, f;
public AS(string mp, int ne, int dp, int fa)
{
map = mp;
node = ne;
deep = dp;
father = fa;
f = GetFx(mp, dp);
}
public int GetFx(string map, int deep)
{
char[,] tar = new char[3, 3] { { '1', '2', '3' }, { '8', '0', '4' }, { '7', '6', '5' } };
char[,] now = new char[3, 3] { { map[0], map[1], map[2] }, { map[3], map[4], map[5] }, { map[6], map[7], map[8] } };
int result = deep, flag;
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
{
flag = 0;
for (int m = 0; m < 3; m++)
{
if (flag == 1)
break;
for (int n = 0; n < 3; n++)
{
if (now[i, j] == tar[m, n])
{
result += Math.Abs(i - m) + Math.Abs(j - n);
flag = 1;
break;
}
}
}
}
return result;
}
public void Display()
{
Console.WriteLine("深度¨¨:" + deep + "\t结点号?:" + node + "\t结点:" + map);
}
}
class Program
{
static public string GetRandomStart(Random ran)
{
List<char> c = new List<char>();
for (int i = 0; i < 9; i++)
c.Add((char)('0' + i));
string res = "";
int k;
for (int i = 0; i < 9; i++)
{
k = ran.Next(0, c.Count);
res += c[k];
c.RemoveAt(k);
}
return res;
}
static bool HaveSolution(string t)
{
int sum = 0;
char[] tar = t.ToCharArray();
for (char i = '1'; i < '9'; i++)
{
int temp = t.IndexOf(i);
for (int j = 0; j < temp; j++)
{
if (tar[j] > i)
sum++;
}
}
if (sum % 2 == 0)
return false;
else return true;
}
static void Main(string[] args)
{
List<AS> open = new List<AS>();
List<AS> close = new List<AS>();
Random ran = new Random();
int[,] move = new int[9, 4] {{ 1,3,9,9},{ 0,2,4,9}, { 1,5,9,9 }
,{ 0,4,6,9},{ 1,3,5,7},{ 2,4,8,9}
,{ 3,7,9,9},{ 4,6,8,9},{ 5,7,9,9}};
int nodeNum = 0;
AS target = new AS("123804765", -1, 0, -1);
string temp = GetRandomStart(ran);
while (!HaveSolution(temp))
temp = GetRandomStart(ran);
AS start = new AS(temp, 0, 1, 0);
AS n;
open.Add(start);
while (open.Count != 0)
{
bool InOpen, InClose;
open.Sort((a, b) => a.f.CompareTo(b.f));
n = open[0];
open.RemoveAt(0);
if (n.map == "123804765")
{
AS r;
int pa = n.father;
List<AS> solution = new List<AS>();
solution.Add(n);
while (pa != 0)
{
r = close.First(t => t.node == pa);
solution.Add(r);
pa = r.father;
}
start.Display();
for (int i = solution.Count - 1; i >= 0; i--)
solution[i].Display();
break;
}
int p = n.map.IndexOf('0');
for (int i = 0; i < 4; i++)
{
if (move[p, i] == 9)
continue;
char[] newMap = n.map.ToCharArray();
newMap[p] = newMap[move[p, i]];
newMap[move[p, i]] = '0';
AS newAS = new AS(string.Join("", newMap.Select(x => x.ToString()).ToArray()), ++nodeNum, n.deep + 1, n.node);
InClose = false; InOpen = false;
for (int j = 0; j < open.Count; j++)
{
if (newAS.map == open[j].map)
{
if (newAS.f < open[j].f)
{
open[j].father = newAS.father;
open[j].f = newAS.f;
}
InOpen = true;
break;
}
}
if (!InOpen)
for (int j = 0; j < close.Count; j++)
{
if (newAS.map == close[j].map)
{
if (newAS.f < close[j].f)
{
close[j].f = newAS.f;
open.Add(newAS);
}
InClose = true;
break;
}
}
if ((InOpen == false) && (InClose == false))
{
open.Add(newAS);
}
}
close.Add(n);
}
Console.ReadKey();
}
}
}