我使用曼哈顿距离的A-star算法制作了一个简单的15益智游戏。 对于简单的问题,它可以工作,但解决方案不是最佳解决方案。
例如,如果运动是:
右->上
我的解决方法是:
右->上->左->下->右->上
如果我有一个很难解决的游戏,那将花费无限的时间并且无法解决任何问题,我想是因为这个问题。
为了实现我的游戏,我遵循了A *算法的维基百科伪代码。 这是我的AStar函数:
public ArrayList<String> solution(Vector<Integer> start){
ArrayList<String> movePath = new ArrayList<String>(); //Path to solution
PriorityQueue<Node> closedQueue = new PriorityQueue<Node>(500,new Comparator<Node>() {
@Override public int compare(Node a,Node b) {
return a.get_fScore() - b.get_fScore();
}
});
Node node = new Node(start,movePath,heuristic);
int cnt =0;
openQueue.add(node);
while(!openQueue.isEmpty() ) {
//Alt if it takes too much time (ToRemove)
if(cnt == (150)*1000) {
ArrayList<String> noResult = new ArrayList<String>();
noResult.add("Timeout");
return noResult;
}
Node bestNode = openQueue.remove(); //Remove best node from openQueue
closedQueue.add(bestNode); //Insert its to closedQueue
cnt++;
if( cnt % 10000 == 0) {
System.out.printf("Analizzo %,d posizioni. Queue Size = %,d\n", cnt, openQueue.size());
}
//Get first step from bestNode and add to movePath
if(!bestNode.isEmptyMoves()) {
String step = bestNode.get_moves().get(0);
movePath.add(step);
}
//Exit Condition
if(bestNode.get_hScore() == 0) {
return bestNode.get_moves();
}
//Looking for childs
Vector<Node> childs = get_nextMoves(bestNode);
for(int i=0; i<childs.size(); i++) {
if(closedQueue.contains(childs.elementAt(i)))
continue;
childs.elementAt(i).set_gScore(bestNode.get_gScore()+1); //Increment level in tree
if(!openQueue.contains(childs.elementAt(i)))
openQueue.add(childs.elementAt(i));
else {
//!Never reached this level!
System.out.println("Here!");
//TODO Copy child from openQueue to closedQueue
}
}
}
return null;
这是我寻找邻居的功能:
public Vector<Node> get_nextMoves(Node act){
Vector<Node> steps = new Vector<Node>();
int position = act.get_valuePos(0);
String lastMove = act.get_lastMove();
//System.out.println(lastMove);
//Right Child
if(position + 1 < 16 && position + 1!=3 && position + 1!=7 && position+1 !=11 && lastMove !="Left") {
int temp_pos[] = copyToArray(act.get_posVect());//Copy array of positions of ACT to a temp_pos array
temp_pos[position] = temp_pos[position+1]; //Switch 0 position with Right position
temp_pos[position+1] = 0;
ArrayList<String> temp_moves = new ArrayList<String>();
for(int i=0; i<act.get_moves().size(); i++) {
temp_moves.add(act.get_moves().get(i)); //Save old steps
}
temp_moves.add("Right");//And add new one
Node child = new Node(temp_pos,temp_moves,act.get_heuristic()); //New Node
steps.addElement(child);//Added to vector
}
//Left Child
if(position - 1 >= 0 && position - 1 != 4 && position - 1 != 8 && position - 1 != 12 && lastMove !="Right") {
int temp_pos[] = copyToArray(act.get_posVect());
temp_pos[position] = temp_pos[position-1];
temp_pos[position-1] = 0;
ArrayList<String> temp_moves = new ArrayList<String>();
for(int i=0; i<act.get_moves().size(); i++) {
temp_moves.add(act.get_moves().get(i));
}
temp_moves.add("Left");
Node child = new Node(temp_pos,temp_moves,act.get_heuristic());
steps.addElement(child);
}
//Up Child
if(position - 4 >= 0 && lastMove !="Down") {
int temp_pos[] = copyToArray(act.get_posVect());
temp_pos[position] = temp_pos[position-4];
temp_pos[position-4] = 0;
ArrayList<String> temp_moves = new ArrayList<String>();
for(int i=0; i<act.get_moves().size(); i++) {
temp_moves.add(act.get_moves().get(i));
}
temp_moves.add("Up");
Node child = new Node(temp_pos,temp_moves,act.get_heuristic());
steps.addElement(child);
}
//Down Child
if(position + 4 < 16 && lastMove !="Up") {
int temp_pos[] = copyToArray(act.get_posVect());
temp_pos[position] = temp_pos[position+4];
temp_pos[position+4] = 0;
ArrayList<String> temp_moves = new ArrayList<String>();
for(int i=0; i<act.get_moves().size(); i++) {
temp_moves.add(act.get_moves().get(i));
}
temp_moves.add("Down");
Node child = new Node(temp_pos,temp_moves,act.get_heuristic());
steps.addElement(child);
}
return steps;
那是我的ManhattanDistance函数:
public int calcolaDist(Vector<Integer> A) {
int result = 0;
Vector<Integer> goal_Mat = initialize_Mat();
for(int i=0; i<16; i++) {
int x_goal = (goal_Mat.indexOf(i))/4;
int y_goal = (goal_Mat.indexOf(i))%4;
int x_def = (A.indexOf(i))/4;
int y_def = (A.indexOf(i))%4;
if(A.elementAt(i) > 0) {
result += Math.abs(x_def - x_goal);
result += Math.abs(y_def - y_goal);
}
}
return result;
如果我的难题是:
start = {1,3,0,4,5,2,7,8,9,6,10,11,13,14,15,12}
我的解决方法是:
[左,下,下,右,下,右,上,左,下,右,上,左,下,右]
我知道使用Vectors不是一个好选择,并且我的代码“有点”肮脏,但是一旦摆脱这个问题,我将立即清理它!
谢谢大家!
答案 0 :(得分:0)
首先,我发现您的代码与OPEN和CLOSED队列有些混淆。 OPEN队列应该是管理节点(PriorityQueue
)优先级的队列。 CLOSED不需要这样做,因为它仅存储访问的节点及其成本(也许您的算法通过HashSet
或HashMap
更改CLOSED会更有效,以避免也将节点排序为CLOSED)。我在您的代码中看不到如何初始化OPEN队列,但这也许是您实现A *的问题。
我在代码中看到的另一个问题是,基于A *的算法需要管理到达已处于“打开/关闭”状态但成本不同的节点的情况。如果您从其他父节点访问一个节点,或者您进入一个循环,则可能会发生这种情况。如果不考虑该算法,该算法将无法正常工作。
问题虽然存在,但是状态空间是有限的,算法应该在某个时候结束。我看到您的实现是用Java实现的。如果您看看具有Hipster4j和an implementation of A*的图书馆an example solving the 8-puzzle,这可能对您有帮助。
希望我的回答有帮助。祝你好运!