Java 用DFS解8字谜
我正在寻找java代码,这些代码通过给定的初始状态为8字谜游戏实现DFS和BFS:Java 用DFS解8字谜,java,artificial-intelligence,depth-first-search,sliding-tile-puzzle,state-space,Java,Artificial Intelligence,Depth First Search,Sliding Tile Puzzle,State Space,我正在寻找java代码,这些代码通过给定的初始状态为8字谜游戏实现DFS和BFS: 1 2 3 8 0 4 7 6 5 目标状态 2 8 1 0 4 3 7 6 5 我需要打印从初始状态到目标状态的解决方案路径(尚未完成) 这是我的密码。到目前为止,我只能实现DFS。到目前为止,我的程序所做的是,一旦找到目标状态,它就会输出成功。 然而,它从未达到这一点 有人能告诉我我出了什么问题吗?你不应该把已经添加到它的开放堆栈组合中。(另外,ArrayQue更好,Stack是一个旧类,请参见javad
1 2 3
8 0 4
7 6 5
目标状态
2 8 1
0 4 3
7 6 5
我需要打印从初始状态到目标状态的解决方案路径(尚未完成)
这是我的密码。到目前为止,我只能实现DFS。到目前为止,我的程序所做的是,一旦找到目标状态,它就会输出成功。
然而,它从未达到这一点
有人能告诉我我出了什么问题吗?你不应该把已经添加到它的开放堆栈组合中。(另外,ArrayQue更好,Stack是一个旧类,请参见javadoc) 更完整和一致的后进先出堆栈操作集是 由Deque接口及其实现提供,应该 优先于此类使用。例如: Deque stack=new ArrayDeque(); ) 为了避免无数次地探索相同的状态,您必须使用集合作为关闭列表,并验证您试图添加到打开列表中的状态从未添加到关闭列表中 此外,使用byte[]数组(而不是int[]来节省内存)而不是字符串来执行操作可能会更舒服 总而言之,您可以这样构造代码:
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");
}
}
公共类Taquin{
专用字节[][]状态=新字节[3][3];
公共Taquin(字符串s){…}
公共列表继承者(){…}
公共布尔可解(Taquin目标){…}
//必须使用该设置////////////
public int hashCode(){…}
公共布尔等于(对象o){…}
公共字符串toString(){…state}
////////////////////////////////////////
公共无效解决(Taquin目标){
如果(可解(目标)){
Deque open=新的ARRAYDEFUE();
Set closed=新的HashSet();
已关闭。添加(此);
打开。添加(此);
塔昆电流=此;
//如果isSolvable是正确的,您永远不会遇到open.isEmpty(),但为了安全起见,请测试它
而(!current.equals(goal)&&!open.isEmpty()){
current=open.pop();
系统输出打印项次(当前);
for(Taquin成功:current.successivers())
//我们只在开放列表中添加从未“看到”的元素
如果(关闭。添加(成功))
打开。添加(成功);
}
System.out.println(“成功”);
}否则
System.out.println(“无解决方案”);
}
}
这样做的优点是,对于图形中的任何类型的搜索都是通用的。如果您想解决另一个难题,只需修改我没有实现的方法(实际上是节点接口的一部分)。如果您想更改算法(例如,经常用于8字谜的星星),您只需更改求解方法即可。我希望此代码示例将对您有所帮助。好的,因此您的程序花费的时间比预期的要长。首先,我们想知道它是卡在一个无限循环中,还是很慢。为此,让程序通过向主循环添加以下内容来打印其进度:
int statesVisited = 0;
while (OPEN.empty() == false && STATE == false) {
statesVisited++;
System.out.println(statesVisited);
然后我们看到这个程序每秒访问了几千个州。由于我们的处理器每秒执行数十亿条指令,这意味着处理一个状态需要大约一百万条cpu指令。不应该那么高,是吗?那么是什么导致了这一切呢
一般来说,我们现在会使用一个分析器来测量这段时间花在代码的哪一部分上,但是由于程序很短,我们可以先尝试猜测。我的第一个猜测是,打印我们访问的每个州可能会非常昂贵。为了验证这一点,我们只打印第1000个州:
while (OPEN.empty() == false && STATE == false) {
statesVisited++;
if (statesVisited % 1000 == 0) {
System.out.println(statesVisited);
}
我们注意到这一变化,我们注意到前5000个州的访问量低于第二个州,因此印刷业确实意义重大。我们还注意到一些奇怪的事情:虽然前5000个州的访问时间不到一秒钟,但出于某种原因,程序似乎越来越慢。在访问了20000个州后,访问1000个州需要大约一秒钟的时间,而且情况越来越糟。这是出乎意料的,因为处理状态不应该变得越来越昂贵。因此,我们知道我们的循环中的一些操作越来越昂贵。让我们回顾一下我们的代码,以确定它可能是哪个操作
无论集合的大小如何,推送和弹出都需要固定的时间。但您也可以使用Stack.search和LinkedList.contains。这两个操作都需要在整个堆栈或列表上迭代。那么,让我们输出这些集合的大小:
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();
}
public static LinkedHashSet OPEN=new LinkedHashSet();
public static HashSet CLOSED=new HashSet();
公共静态布尔状态=false;
公共静态void main(字符串参数[]){
int statesVisited=0;
字符串start=“123804765”;
字符串目标=“281043765”;
字符串X=“”;
字符串temp=“”;
打开。添加(开始);
while(OPEN.isEmpty()==false&&STATE==false){
X=OPEN.iterator().next();
打开。移除(X);
int pos=X.indexOf('0');//获取零或空空间的位置
如果(X等于(目标)){
System.out.println(“成功”);
状态=真;
}否则{
//生子
已结束。添加(X);
温度=上升(X,位置);
如果(!(温度等于(“-1”))
打开。添加(临时);
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)));