我正在寻找用Java实现8数码游戏的DFS和BFS代码,给定初始状态。
1 2 3
8 0 4
7 6 5
以及目标状态
2 8 1
0 4 3
7 6 5
我需要打印出从起始状态到目标状态的解决路径(目前还没有做到)
这是我已经有的代码。到目前为止,我只能实现深度优先搜索。目前我的程序所做的是在找到目标状态时输出SUCCESS。然而它从未达到这一点。
有人能告诉我我错在哪里吗?
1 2 3
8 0 4
7 6 5
以及目标状态
2 8 1
0 4 3
7 6 5
我需要打印出从起始状态到目标状态的解决路径(目前还没有做到)
这是我已经有的代码。到目前为止,我只能实现深度优先搜索。目前我的程序所做的是在找到目标状态时输出SUCCESS。然而它从未达到这一点。
有人能告诉我我错在哪里吗?
好的,所以您的程序运行时间比预期长。首先,我们需要确定它是否陷入了无限循环,或者只是运行缓慢。为此,让我们在主循环中添加以下代码,使程序打印其进展情况:
int statesVisited = 0;
while (OPEN.empty() == false && STATE == false) {
statesVisited++;
System.out.println(statesVisited);
while (OPEN.empty() == false && STATE == false) {
statesVisited++;
if (statesVisited % 1000 == 0) {
System.out.println(statesVisited);
}
if (statesVisited % 1000 == 0) {
System.out.println(statesVisited);
System.out.println(OPEN.size());
System.out.println(CLOSED.size());
System.out.println();
}
40000
25947
39999
因此,OPEN包含25000个元素,CLOSED包含近40000个元素。这就解释了为什么处理一个状态会变得越来越慢。因此,我们将选择使用具有更高效的contains操作的数据结构,例如java.util.HashSet
或java.util.LinkedHashSet
(后者是哈希集和链表之间的混合体,允许我们按添加顺序检索元素)。这样做,我们得到:
public static LinkedHashSet<String> OPEN = new LinkedHashSet<String>();
public static HashSet<String> CLOSED = new HashSet<String>();
public static boolean STATE = false;
public static void main(String args[]) {
int statesVisited = 0;
String start = "123804765";
String goal = "281043765";
String X = "";
String temp = "";
OPEN.add(start);
while (OPEN.isEmpty() == false && STATE == false) {
X = OPEN.iterator().next();
OPEN.remove(X);
int pos = X.indexOf('0'); // get position of ZERO or EMPTY SPACE
if (X.equals(goal)) {
System.out.println("SUCCESS");
STATE = true;
} else {
// generate children
CLOSED.add(X);
temp = up(X, pos);
if (!(temp.equals("-1")))
OPEN.add(temp);
temp = left(X, pos);
if (!(temp.equals("-1")))
OPEN.add(temp);
temp = down(X, pos);
if (!(temp.equals("-1")))
OPEN.add(temp);
temp = right(X, pos);
if (!(temp.equals("-1")))
OPEN.add(temp);
}
}
}
/*
* MOVEMENT UP
*/
public static String up(String s, int p) {
String str = s;
if (!(p < 3)) {
char a = str.charAt(p - 3);
String newS = str.substring(0, p) + a + str.substring(p + 1);
str = newS.substring(0, (p - 3)) + '0' + newS.substring(p - 2);
}
// Eliminates child of X if its on OPEN or CLOSED
if (!OPEN.contains(str) && CLOSED.contains(str) == false)
return str;
else
return "-1";
}
/*
* MOVEMENT DOWN
*/
public static String down(String s, int p) {
String str = s;
if (!(p > 5)) {
char a = str.charAt(p + 3);
String newS = str.substring(0, p) + a + str.substring(p + 1);
str = newS.substring(0, (p + 3)) + '0' + newS.substring(p + 4);
}
// Eliminates child of X if its on OPEN or CLOSED
if (!OPEN.contains(str) && CLOSED.contains(str) == false)
return str;
else
return "-1";
}
/*
* MOVEMENT LEFT
*/
public static String left(String s, int p) {
String str = s;
if (p != 0 && p != 3 && p != 7) {
char a = str.charAt(p - 1);
String newS = str.substring(0, p) + a + str.substring(p + 1);
str = newS.substring(0, (p - 1)) + '0' + newS.substring(p);
}
// Eliminates child of X if its on OPEN or CLOSED
if (!OPEN.contains(str) && CLOSED.contains(str) == false)
return str;
else
return "-1";
}
/*
* MOVEMENT RIGHT
*/
public static String right(String s, int p) {
String str = s;
if (p != 2 && p != 5 && p != 8) {
char a = str.charAt(p + 1);
String newS = str.substring(0, p) + a + str.substring(p + 1);
str = newS.substring(0, (p + 1)) + '0' + newS.substring(p + 2);
}
// Eliminates child of X if its on OPEN or CLOSED
if (!OPEN.contains(str) && CLOSED.contains(str) == false)
return str;
else
return "-1";
}
public static void print(String s) {
System.out.println(s.substring(0, 3));
System.out.println(s.substring(3, 6));
System.out.println(s.substring(6, 9));
System.out.println();
}
这将快速打印出 "SUCCESS"。
ProblemBuilder
类:SearchProblem p =
ProblemBuilder.create()
.initialState(Arrays.asList(5,4,0,7,2,6,8,1,3))
.defineProblemWithExplicitActions()
.useActionFunction(new ActionFunction<Action, List<Integer>>() {
@Override
public Iterable<Action> actionsFor(List<Integer> state) {
// Here we compute the valid movements for the state
return validMovementsFor(state);
}
}).useTransitionFunction(new ActionStateTransitionFunction<Action, List<Integer>>() {
@Override
public List<Integer> apply(Action action, List<Integer> state) {
// Here we compute the state that results from doing an action A to the current state
return applyActionToState(action, state);
}
}).useCostFunction(new CostFunction<Action, List<Integer>, Double>() {
@Override
public Double evaluate(Transition<Action, List<Integer>> transition) {
// Every movement has the same cost, 1
return 1d;
}
}).build();
System.out.println(Hipster.createDijkstra(p).search(Arrays.asList(0,1,2,3,4,5,6,7,8)));
public class Taquin {
private byte[][] state = new byte[3][3];
public Taquin(String s) { ... }
public List<Taquin> successors() { ... }
public boolean isSolvable(Taquin goal) { ... }
//Necessary to use the Set !////////////
public int hashCode() { ... }
public boolean equals(Object o) { ... }
public String toString() { ...state }
////////////////////////////////////////
public void solve(Taquin goal) {
if (isSolvable(goal)) {
Deque<Taquin> open = new ArrayDeque<>();
Set<Taquin> closed = new HashSet<>();
closed.add(this);
open.add(this);
Taquin current = this;
//if isSolvable is correct you should never encounter open.isEmpty() but for safety, test it
while (!current.equals(goal) && !open.isEmpty()) {
current = open.pop();
System.out.println(current);
for (Taquin succ : current.successors())
//we only add to the open list the elements which were never "seen"
if (closed.add(succ))
open.add(succ);
}
System.out.println("Success");
} else
System.out.println("No solution");
}
}