【发布时间】:2018-11-07 18:48:13
【问题描述】:
我使用 A-star 算法和曼哈顿距离制作了一个简单的 15puzzle 游戏。 对于简单的问题,它可以工作,但解决方案不是最佳解决方案。
例如,如果一个动作是:
右->上
我的解决方案是:
右->上->左->下->右->上
如果我有一个很难解决的游戏,它会花费无限的时间并且无法解决问题,我认为是因为这个问题。
为了实现我的游戏,我遵循了 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;
这就是我的曼哈顿距离函数:
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;
如果我的困惑是:
开始 = {1,3,0,4,5,2,7,8,9,6,10,11,13,14,15,12}
我的解决方案是:
[左、下、下、右、下、右、上、左、下、右、上、左、下、右]
我知道使用向量不是一个好的选择,而且我的代码“有点”脏,但我会在解决这个问题后立即清理它!
谢谢大家!
【问题讨论】:
-
我稍后会仔细看看(还没有阅读你的代码)但我记得当我做这个完全相同的难题时:导致它无限循环的一个问题是我正在添加动作将在可用操作中返回父节点,也许就是这样。
-
这是 A* 和 IDDFS 上的 helpful resource,用于解决 15 个谜题。 A* 使用大量内存并且通常会在 15 个谜题上崩溃,因此 IDDFS 或模式数据库是一个很好的解决方案。我建议对这篇文章进行一轮代码清理,以生成带有标记的MCVE,以识别您的问题区域。如果您想消除您提到的循环,您可能需要跟踪所有访问过的位置,而不是只检查长度为 1 的循环。
-
谢谢你!这是大学作业,所以(不幸)我不能使用模式数据库。是的,我会尽快清理我的代码!!