master
jokingww 4 years ago
parent d65fdcc0df
commit 44d9d432d9

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="test"/>
<classpathentry exported="true" kind="lib" path="D:/Study/2021春/人工智能/algs4.jar" sourcepath="D:/Study/2021春/人工智能/algs4.jar"/>
<classpathentry exported="true" kind="lib" path="D:/Study/2021春/人工智能/junit-jupiter-api-5.4.2.jar"/>
<classpathentry kind="output" path="out/production/SearchFramework1.0.1"/>
</classpath>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<option name="BUILD_PROCESS_HEAP_SIZE" value="44096" />
</component>
</project>

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>SearchFramework1.0.1</name>
<comment/>
<projects/>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments/>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<component inherit-compiler-output="true" inheritJdk="true">
<output-test url="file://$MODULE_DIR$/out/test/SearchFramework1.0.1"/>
<exclude-output/>
<contentEntry url="file://$MODULE_DIR$">
<testFolder url="file://$MODULE_DIR$/test"/>
</contentEntry>
<lib name="algs4.jar" scope="COMPILE">
<srcroot url="jar://$MODULE_DIR$/../../../algs4.jar!/"/>
</lib>
</component>

@ -11,18 +11,18 @@
<orderEntry type="module-library" exported="">
<library>
<CLASSES>
<root url="jar://$MODULE_DIR$/../../algs4.jar!/" />
<root url="jar://$MODULE_DIR$/../../../algs4.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$MODULE_DIR$/../../algs4.jar!/" />
<root url="jar://$MODULE_DIR$/../../../algs4.jar!/" />
</SOURCES>
</library>
</orderEntry>
<orderEntry type="module-library" exported="">
<library>
<CLASSES>
<root url="jar://$MODULE_DIR$/../../junit-jupiter-api-5.4.2.jar!/" />
<root url="jar://$MODULE_DIR$/../../../junit-jupiter-api-5.4.2.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<eclipse-userlibraries />

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1,3 @@
3 6 4 7 8 5 0 3 2 1 1 2 3 4 5 6 7 8 0
4 4 6 15 13 12 9 10 2 8 0 7 3 14 5 1 11 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0
4 15 14 13 12 11 10 9 8 7 6 5 4 3 1 2 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0

@ -16,7 +16,7 @@ public class SearchRunner {
public static void main(String[] args) {
//从文件中读入问题的实例,寻路问题
In problemInput = new In("resources/pathfinding.txt");
In problemInput = new In("resources/npuzzle.txt");
//生成一个具体的EngineFeederFeederXu引擎饲养员徐老师:)
EngineFeeder feeder = new MyFeeder();
@ -25,35 +25,27 @@ public class SearchRunner {
ArrayList<Problem> problems = feeder.getProblems(problemInput);
//从Feeder获取所使用的搜索引擎 AStar
/*
BestFirstSearch astar = (BestFirstSearch) feeder.getScoreSearcher();
for (Problem problem : problems){
Stopwatch stopwatch = new Stopwatch();
//使用AStar引擎求解问题
Deque<Node> path = astar.search(problem);
//解的可视化
problem.showSolution(path);
//仅打印路径
problem.printPath(path);
System.out.println(astar.expandedNode());
System.out.println(path.size());
System.out.println(stopwatch.elapsedTime());
}
System.out.println("==============================================================");
*/
//BestFirstSearch astar = (BestFirstSearch) feeder.getAStar(HeuristicType.MANHATTAN);
//从Feeder获取所使用的搜索引擎 IDAStar
IDAStarSearch idastar = (IDAStarSearch) feeder.getIdaStar();
//IDAStarSearch idastar = (IDAStarSearch) feeder.getIdaStar();
//从Feeder获取所使用的搜索引擎 IDAStar + DisjointPattern
IDAStarSearch idastar2 = (IDAStarSearch) feeder.getScoreSearcher();
for (Problem problem : problems){
Stopwatch stopwatch = new Stopwatch();
//使用AStar引擎求解问题
Deque<Node> path = idastar.search(problem);
//Deque<Node> path = astar.search(problem);
//使用IDAStar引擎求解问题
//Deque<Node> path = idastar.search(problem);
//使用IDAStar+DisjointPattern引擎求解问题
Deque<Node> path = idastar2.search(problem);
//解的可视化
problem.showSolution(path);
//仅打印路径
//problem.printPath(path);
System.out.println(path.size());
System.out.println(stopwatch.elapsedTime());
//System.out.println(astar.expandedNode());
if (path != null)
System.out.println(path.size());
System.out.println(stopwatch.elapsedTime() + "s");
System.out.println("==============================================================");
}

@ -53,7 +53,7 @@ public final class Node{
public Node childNode(Action action, Predictor predictor, State goal) {
return new Node(state.next(action), this, action,
pathCost + action.stepCost(),
predictor.heuristics(state, goal));
predictor.heuristics(state.next(action), goal));
}
private final State state; // the state in the state space to which the node corresponds

@ -5,7 +5,6 @@ import java.util.*;
import core.problem.Problem;
import core.problem.State;
import core.solver.*;
import g04.problem.npuzzle.PuzzleState;
/**
* final
@ -42,18 +41,17 @@ public final class BestFirstSearch implements Searcher {
//搜索树的根节点
Node root = problem.root(predictor);
this.frontier.add(root);
//int i = 0;
while (true) {
if (frontier.isEmpty())
return null; //失败
Node node = frontier.poll(); //choose the lowest-cost node in frontier
//System.out.println(node.evaluation());
//如果已经到达目标状态,
if (problem.goal(node.getState())) {
return generatePath(node);
}
//将当前结点放入explored表中
explored.add(node.getState());
//System.out.println(i++);
for (Node child : problem.childNodes(node, predictor)) {
// 如果新扩展的节点没有在Explored和Fringe中出现过。
// 因为两个node的状态相同则视为二者相同equals函数
@ -67,6 +65,7 @@ public final class BestFirstSearch implements Searcher {
//而且到达这个节点的新路径肯定不会比旧路径更优
frontier.discardOrReplace(child);
}
//System.out.println("expanded: " + expandedNode());
}
}
}

@ -27,16 +27,16 @@ public class MyFeeder extends EngineFeeder {
while (io.hasNextLine()){
//棋盘大小
int size = io.readInt();
int[][] board = new int[size][size];
int[] board = new int[size * size];
//读入初始状态
for (int i = 0; i < size; i++)
for (int j = 0; j < size; j++)
board[i][j] = io.readInt();
board[i * size + j] = io.readInt();
PuzzleState initState = new PuzzleState(board, size);
//读入目标状态
for (int i = 0; i < size; i++)
for (int j = 0; j < size; j++)
board[i][j] = io.readInt();
board[i * size + j] = io.readInt();
PuzzleState goal = new PuzzleState(board, size);
Puzzle puzzleProblem = new Puzzle(initState, goal, size);
//添加到问题列表
@ -75,10 +75,18 @@ public class MyFeeder extends EngineFeeder {
}
/**
* @return A*
* IDA*
* @return IDA*+DisjointPattern
*/
@Override
public Searcher getScoreSearcher() {
return getAStar(HeuristicType.MANHATTAN);
return new IDAStarSearch(PuzzleState.predictor(HeuristicType.DISJOINT_PATTERN));
//return super.getAStar(HeuristicType.DISJOINT_PATTERN);
}
/**
* @return A*
*/
public Searcher getAStar() {
return super.getAStar(HeuristicType.MANHATTAN);
}
}

@ -4,18 +4,33 @@ import core.problem.Action;
import core.problem.Problem;
import core.problem.State;
import core.solver.Node;
import core.solver.heuristic.Predictor;
import g04.solver.heuristic.DisjointPatternDatabase;
import java.util.ArrayList;
import java.util.Deque;
import java.util.Random;
public class Puzzle extends Problem {
//Zobrist哈希随机值
public static int[][][] Zobrist;
//目标状态到默认状态的曼哈顿距离(默认状态为按顺序放置位将牌,空格最后)
public static int[][][] goalmanhattan;
public static DisjointPatternDatabase puzzle3;
public static DisjointPatternDatabase puzzle4;
static {
puzzle3 = new DisjointPatternDatabase(3, 2,4);
//puzzle3.read("resources/db3.txt");
puzzle3.load(44);
puzzle3.read2("resources/db3(1).txt", 0, 4);
puzzle3.read2("resources/db3(2).txt", 1, 4);
//puzzle4 = new DisjointPatternDatabase(4, 2,8);
//puzzle4.read("resources/db4_78.txt");
puzzle4 = new DisjointPatternDatabase(4, 3,6);
//puzzle4.read2("resources/db4_6(1).txt", 0, 6);
//puzzle4.read2("resources/db4_6(2).txt", 1, 6);
//puzzle4.read2("resources/db4_3.txt", 2, 3);
puzzle4.load(663);
puzzle4.read2("resources/db4_3(2).txt", 0, 3);
puzzle4.read2("resources/db4_6(3).txt", 1, 6);
puzzle4.read2("resources/db4_6(4).txt", 2, 6);
}
/**
*
@ -25,29 +40,8 @@ public class Puzzle extends Problem {
*/
public Puzzle(State initialState, State goal, int size) {
super(initialState, goal, size);
Random r = new Random();
goalmanhattan = new int[size][size][2];
Zobrist = new int[size][size][size * size];
for(int i = 0; i < size; i++) {
for(int j = 0; j < size; j++) {
goalmanhattan[i][j][0] = (((PuzzleState)goal).getBoardAt(i, j) - 1) / size;;
goalmanhattan[i][j][1] = (((PuzzleState)goal).getBoardAt(i, j) - 1) % size;;;
for(int k = 0; k < size * size; k++) {
Zobrist[i][j][k] = r.nextInt();
}
}
}
}
/**
*
* @param i
* @param j
* @param state
* @return Zobrist
*/
public static int getZobristAt(int i, int j, int state) {
return Zobrist[i][j][state];
//PuzzleState.init(size, (PuzzleState) goal);
//loadDisjointPattern();
}
/**
@ -56,6 +50,7 @@ public class Puzzle extends Problem {
*/
@Override
public boolean solvable() {
PuzzleState.init(size, (PuzzleState)goal);
return ((PuzzleState)initialState).parity() == ((PuzzleState)goal).parity();
}
@ -109,27 +104,28 @@ public class Puzzle extends Problem {
for (Node node : path) {
PuzzleAction puzzleAction = (PuzzleAction) node.getAction();
puzzleAction.draw();
PuzzleState puzzleState = (PuzzleState) node.getState();
puzzleState.draw();
PuzzleState PuzzleState = (PuzzleState) node.getState();
PuzzleState.draw();
}
System.out.println();
}
/*
public final Iterable<? extends Node> childs(Node parent) {
ArrayList<Node> nodes = new ArrayList<>();
//父结点的状态
State parentState = parent.getState();
PuzzleState parentState = (PuzzleState) parent.getState();
//对于parentState上所有可能的action但有的不可行
//parentState.draw();
for (Action action : parentState.actions()){
//如果父结点状态下的动作是可行的
if (applicable(parentState, action)){
//得到后继状态
State state = parentState.next(action);
PuzzleState state = (PuzzleState)parentState.next(action);
state.setHash(nextHash(parentState, state));
//计算路径长度 = 父结点路径长度 + 进入后继状态所采取的动作的代价
int pathCost = parent.getPathCost() + stepCost(state, action);
//根据曼哈顿距离特性,只需要计算被移动的位将牌改变的曼哈顿距离
int heuristics = parent.getHeuristic() - nextManhattan((PuzzleState)parentState, (PuzzleState)state);
int heuristics = parent.getHeuristic() - nextManhattan(parentState, state);
//生成子结点
Node child = new Node(state, parent, action, pathCost, heuristics);
nodes.add(child);
@ -138,18 +134,19 @@ public class Puzzle extends Problem {
return nodes;
}
/**
*
* @param parent
* @param child
* @return
*/
public int nextManhattan(PuzzleState parent, PuzzleState child) {
//被移动的位将牌对应数字
int n = parent.getBoardAt(child.getBlank(0), child.getBlank(1));
int x = (n - 1) / size;
int y = (n - 1) % size;
return Math.abs(goalmanhattan[x][y][0] - child.getBlank(0)) + Math.abs(goalmanhattan[x][y][1] - child.getBlank(1))
- Math.abs(goalmanhattan[x][y][0] - parent.getBlank(0)) - Math.abs(goalmanhattan[x][y][1] - parent.getBlank(1));
public void loadDisjointPattern() {
switch (size) {
case 3:
disjoint_pattern = new DisjointPatternDatabase(3, 4);
disjoint_pattern.readFile("resources/db3.txt");
break;
case 4:
disjoint_pattern = new DisjointPatternDatabase(4, 5);
disjoint_pattern.readFile("resources/db4.txt");
break;
default:
break;
}
}
*/
}

@ -6,7 +6,7 @@ public class PuzzleAction extends Action {
/*
*
* 0: Up, 1: Right, 2: Down, 3: Right
* 0: Right, 1: Down, 2: Left, 3: Up
*/
private final int dir;
// 移动方向

@ -0,0 +1,43 @@
package g04.problem.npuzzle;
public class PuzzlePoint {
private int row;
private int col;
private int val;
public PuzzlePoint(int row, int col, int val) {
this.row = row;
this.col = col;
this.val = val;
}
public PuzzlePoint(PuzzlePoint p) {
this.row = p.row;
this.col = p.col;
this.val = p.val;
}
public int getRow() {
return row;
}
public void setRow(int row) {
this.row = row;
}
public int getCol() {
return col;
}
public void setCol(int col) {
this.col = col;
}
public int getVal() {
return val;
}
public void setVal(int val) {
this.val = val;
}
}

@ -7,14 +7,12 @@ import core.problem.Action;
import core.problem.State;
import core.runner.HeuristicType;
import core.solver.heuristic.Predictor;
import xu.problem.pathfinding.Direction;
import xu.problem.pathfinding.Move;
import xu.problem.pathfinding.Position;
import g04.solver.heuristic.DisjointPatternBuilder;
import g04.solver.heuristic.DisjointPatternDatabase;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.Objects;
import java.util.Scanner;
import java.util.Random;
/**
@ -30,20 +28,36 @@ public class PuzzleState extends State {
private final int size;
//该状态每个位置的位将牌数字
private final int[][] board;
private final int[] board;
//空格对应位置
private int[] blank;
//曼哈顿距离
private int manhattan = 0;
//错位将牌
private int misPlaced = 0;
//哈希值
private int hash = 0;
//分组状态数
private int[] stateCode = null;
//zobrist哈希随机值
public static int[][][] zobrist;
//目标状态到默认状态的曼哈顿距离(默认状态为按顺序放置位将牌,空格最后)
public static int[][][] goalManhattan;
//disjointPattern
public static DisjointPatternDatabase db;
/**
*
*/
public PuzzleState(int[][] board, int size) {
public PuzzleState(int[] board, int size) {
this.size = size;
this.board = new int[size][size];
this.board = new int[size * size];
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
this.board[i][j] = board[i][j];
if (board[i][j] == 0)
this.board[i * size + j] = board[i * size + j];
if (board[i * size + j] == 0)
this.blank = new int[]{i, j};
}
}
@ -54,11 +68,14 @@ public class PuzzleState extends State {
*/
public PuzzleState(PuzzleState puzzleState) {
this.size = puzzleState.size;
this.board = new int[size][size];
this.board = puzzleState.board.clone();
this.blank = puzzleState.blank.clone();
/*
this.board = new int[size * size];
for (int i = 0; i < size; i++) {
System.arraycopy(puzzleState.board[i], 0, this.board[i], 0, size);
}
this.blank = new int[]{puzzleState.blank[0], puzzleState.blank[1]};
this.board[i] = puzzleState.board[i].clone();
}*/
}
public int getSize() {
@ -66,17 +83,54 @@ public class PuzzleState extends State {
}
public int getBoardAt(int i, int j) {
return board[i][j];
return board[i * size + j];
}
public int getBoardAt(int i) {
return board[i/size][i%size];
return board[i];
}
public int getBlank(int i) {
return blank[i];
}
public int getBoardAtAnother(PuzzleState s1, PuzzleState s2) {
return s1.getBoardAt(s2.getBlank(0), s2.getBlank(1));
}
/**
* @param i , j , val
* @return Zobrist
*/
public static int getZobristAt(int i, int j, int val) {
return zobrist[i][j][val];
}
public static void init(int size, PuzzleState goal) {
Random r = new Random();
goalManhattan = new int[size][size][2];
zobrist = new int[size][size][size * size];
for(int i = 0; i < size; i++) {
for(int j = 0; j < size; j++) {
goalManhattan[i][j][0] = (goal.board[i * size + j] - 1) / size;
goalManhattan[i][j][1] = (goal.board[i * size + j] - 1) % size;
for(int k = 0; k < size * size; k++) {
zobrist[i][j][k] = r.nextInt();
}
}
}
switch (size) {
case 3:
db = Puzzle.puzzle3;
break;
case 4:
db = Puzzle.puzzle4;
break;
default:
break;
}
}
/**
*
*/
@ -85,7 +139,8 @@ public class PuzzleState extends State {
drawLine();
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
System.out.print("| " + String.valueOf(board[i][j]) + " ");
//System.out.print("| " + String.valueOf(board[i * size + j]) + " ");
System.out.printf("| %2d ", board[i * size + j]);
}
System.out.println("|");
drawLine();
@ -97,7 +152,7 @@ public class PuzzleState extends State {
*/
public void drawLine() {
for (int i = 0; i < size; i++)
System.out.print("+---");
System.out.print("+----");
System.out.println("+");
}
@ -112,8 +167,16 @@ public class PuzzleState extends State {
int[] next = ((PuzzleAction)action).getNext();
nextState.blank[0] += next[0];
nextState.blank[1] += next[1];
nextState.board[this.blank[0]][this.blank[1]] = this.board[nextState.blank[0]][nextState.blank[1]];
nextState.board[nextState.blank[0]][nextState.blank[1]] = 0;
nextState.board[this.blank[0] * size + this.blank[1]] = this.board[nextState.blank[0] * size + nextState.blank[1]];
nextState.board[nextState.blank[0] * size + nextState.blank[1]] = 0;
nextState.hash = nextHash(this, nextState);
nextState.manhattan = this.manhattan - nextManhattan(this, nextState);
nextState.stateCode = this.stateCode.clone();
//int val = (getBoardAtAnother(this, nextState) - 1);
int val = (getBoardAtAnother(this, nextState));
//nextState.stateCode[val / db.n] -= nextStateCode(this, nextState, val);
nextState.stateCode[db.subsets[val]] -= nextStateCode(this, nextState, val);
return nextState;
}
@ -146,12 +209,21 @@ public class PuzzleState extends State {
@Override
public boolean equals(Object obj) {
/*
for (int i = 0; i < size * size - 1; i++) {
if (this.getBoardAt(i) != ((PuzzleState) obj).getBoardAt(i))
return false;
}
return true;
//return this.hashCode() == obj.hashCode();
return true;*/
if (obj == this)
return true;
if (obj instanceof PuzzleState) {
PuzzleState another = (PuzzleState) obj;
//两个Node对象的状态相同则认为是相同的
return this.hashCode() == obj.hashCode();
}
return false;
}
/**
@ -160,29 +232,60 @@ public class PuzzleState extends State {
*/
@Override
public int hashCode() {
if (hash == 0)
hash = getHash();
return hash;
}
private int getHash() {
int hash = 0;
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
hash ^= Puzzle.getZobristAt(i, j, board[i][j]);
if (board[i * size + j] != 0) {
hash ^= getZobristAt(i, j, board[i * size + j]);
}
}
}
return hash;
}
private int nextHash(PuzzleState parent, PuzzleState child) {
int hash = parent.hashCode();
hash ^= getZobristAt(child.getBlank(0), child.getBlank(1), getBoardAtAnother(parent, child));
hash ^= getZobristAt(parent.getBlank(0), parent.getBlank(1), getBoardAtAnother(child, parent));
return hash;
}
public Object clone() {
return null;
}
//枚举映射,存放不同类型的启发函数
private static final EnumMap<HeuristicType, Predictor> predictors = new EnumMap<>(HeuristicType.class);
static{
predictors.put(HeuristicType.MISPLACED,
(state, goal) -> ((PuzzleState)state).misPlaced((PuzzleState)goal));
predictors.put(HeuristicType.MANHATTAN,
(state, goal) -> ((PuzzleState)state).manhattan((PuzzleState)goal));
(state, goal) -> ((PuzzleState)state).getManhattan((PuzzleState)goal));
predictors.put(HeuristicType.MISPLACED,
(state, goal) -> ((PuzzleState)state).getMisPlaced((PuzzleState)goal));
predictors.put(HeuristicType.DISJOINT_PATTERN,
(state, goal) -> ((PuzzleState)state).disjointPattern((PuzzleState)goal));
(state, goal) -> ((PuzzleState)state).getDisjointPattern((PuzzleState)goal));
}
public static Predictor predictor(HeuristicType type){
return predictors.get(type);
}
private int getManhattan(PuzzleState goal) {
if (manhattan == 0)
manhattan = manhattan(goal);
return manhattan;
}
private int getMisPlaced(PuzzleState goal) {
if (misPlaced == 0)
misPlaced = misPlaced(goal);
return misPlaced;
}
/**
*
*/
@ -206,10 +309,10 @@ public class PuzzleState extends State {
//第一步,计算当前状态到默认状态曼哈顿距离
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
if (this.board[i][j] == 0)
if (this.board[i * size + j] == 0)
continue;
x = (this.board[i][j] - 1) / size;
y = (this.board[i][j] - 1) % size;
x = (this.board[i * size + j] - 1) / size;
y = (this.board[i * size + j] - 1) % size;
m[x][y][0] = x - i;
m[x][y][1] = y - j;
}
@ -218,10 +321,10 @@ public class PuzzleState extends State {
//结合两步即为当前状态到目标状态曼哈顿距离
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
if (goal.board[i][j] == 0)
if (goal.board[i * size + j] == 0)
continue;
x = (goal.board[i][j] - 1) / size;
y = (goal.board[i][j] - 1) % size;
x = (goal.board[i * size + j] - 1) / size;
y = (goal.board[i * size + j] - 1) % size;
heuristics += Math.abs(m[x][y][0] + i - x) + Math.abs(m[x][y][1] + j - y);
}
}
@ -229,15 +332,75 @@ public class PuzzleState extends State {
}
/**
* Disjoint pattern heuristic
*
* @param parent
* @param child
* @return
*/
private int disjointPattern(PuzzleState goal) {
private int nextManhattan(PuzzleState parent, PuzzleState child) {
//被移动的位将牌对应数字
int n = getBoardAtAnother(parent, child);
int x = (n - 1) / size;
int y = (n - 1) % size;
return Math.abs(goalManhattan[x][y][0] - child.getBlank(0)) + Math.abs(goalManhattan[x][y][1] - child.getBlank(1))
- Math.abs(goalManhattan[x][y][0] - parent.getBlank(0)) - Math.abs(goalManhattan[x][y][1] - parent.getBlank(1));
}
private int nextMispalced(PuzzleState parent, PuzzleState child) {
int row = (getBoardAtAnother(parent, child) - 1) / size;
int col = (getBoardAtAnother(parent, child) - 1) % size;
if (row == child.getBlank(0) && col == child.getBlank(1)) {
return 1;
}
row = (getBoardAtAnother(child, parent) - 1) / size;
col = (getBoardAtAnother(child, parent) - 1) % size;
if (row == parent.getBlank(0) && col == parent.getBlank(1)) {
return -1;
}
return 0;
}
private int getDisjointPattern(PuzzleState goal) {
if (stateCode == null)
stateCode = getStateCode();
return disjointPattern();
}
/**
* Disjoint pattern heuristic
*/
private int disjointPattern() {
int disjointPattern = 0;
for (int i = 0; i < db.classes; i++) {
disjointPattern += db.cost[i][stateCode[i]];
//System.out.println("class = " + i + ", cost = " + db.cost[i][stateCode[i]] + ", stateCode = " + stateCode[i]);
}
return disjointPattern;
}
private int[] getStateCode() {
int[] stateCode = new int[db.classes];
//System.out.println("classes: " + db.classes);
for (int i = 0; i < size * size; i++) {
if (board[i] == 0) continue;
//stateCode[(board[i] - 1) / db.n] += i * (int) Math.pow(size * size, (board[i] - 1) % db.n);
stateCode[db.subsets[board[i]]] += i * Math.pow(size * size, db.positions[board[i]]);
}
return stateCode;
//System.out.println("index = " + i + ", classes = " + ((board[i] - 1) / db.n) +
// ", val = " + i * (int) Math.pow(size * size, (board[i] - 1) % db.n));
}
private int nextStateCode(PuzzleState parent, PuzzleState child, int val) {
//return (child.getBlank(0) * size + child.getBlank(1)) * (int) Math.pow(size * size, val % db.n)
// - (parent.getBlank(0) * size + parent.getBlank(1)) * (int) Math.pow(size * size, val % db.n);
return (child.getBlank(0) * size + child.getBlank(1)) * (int) Math.pow(size * size, db.positions[val])
- (parent.getBlank(0) * size + parent.getBlank(1)) * (int) Math.pow(size * size, db.positions[val]);
}
public static void main(String[] args) {
int[][] a = new int[][]{{8, 13, 0, 6}, {1, 15, 9, 14}, {3, 4, 5, 11}, {7, 2, 10, 12}};
int[][] g = new int[][]{{1, 2, 3}, {4, 5, 6}, {7, 8, 0}};
int[] a = new int[]{8, 13, 0, 6, 1, 15, 9, 14, 3, 4, 5, 11, 7, 2, 10, 12};
int[] g = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 0};
PuzzleState puzzleState = new PuzzleState(a, 4);
int n = 0;
for (int i = 0; i < 4 * 4; i++) {

@ -0,0 +1,141 @@
package g04.problem.npuzzle;
import g04.solver.heuristic.DisjointPatternBuilder;
//NPuzzle的状态的子分组disjointPattern
public class SubPuzzleState {
//最大分组数
private int maxN;
//稀疏点数
private int n;
private int size;
private PuzzlePoint[] points;
private int heuristic = 0;
private int cost = 0;
private SubPuzzleState parent = null;
private static final int[][] next = {
{0, 1}, {1, 0}, {0, -1}, {-1, 0}
};
public SubPuzzleState(int size, int n, int maxN, PuzzlePoint[] points) {
this.n = n;
this.size = size;
this.points = new PuzzlePoint[n];
for (int i = 0; i < n; i++) {
this.points[i] = new PuzzlePoint(points[i]);
}
this.maxN = maxN;
}
public SubPuzzleState(SubPuzzleState state) {
this.n = state.n;
this.size = state.size;
this.points = new PuzzlePoint[n];
for (int i = 0; i < n; i++) {
this.points[i] = new PuzzlePoint(state.points[i]);
}
this.maxN = state.maxN;
}
public void draw() {
for (int i = 0; i < n; i++) {
System.out.print("(" + points[i].getRow() + "," + points[i].getCol() + "," + points[i].getVal() + ") ");
}
System.out.println();
}
public boolean applicable(int i, int dir) {
//移动后是否越界
int row = points[i].getRow() + next[dir][0];
int col = points[i].getCol() + next[dir][1];
if (row < 0 || row >= size || col < 0 || col >= size)
return false;
for (int j = 0; j < n; j++) {
if (points[j].getRow() == row && points[j].getCol() == col) {
return false;
}
}
return true;
}
public int getN() {
return n;
}
public int getHeuristic() {
return heuristic;
}
public int getCost() {
return cost;
}
public SubPuzzleState getParent() {
return parent;
}
public int getNum() {
return (int) Math.pow(size * size, n);
}
@Override
public int hashCode() {
int hash = 0;
for (int i = 0; i < n; i++) {
hash += (points[i].getRow() * size + points[i].getCol()) *
//(int)Math.pow(size * size, (points[i].getVal() - 1) % maxN);
Math.pow(size * size, DisjointPatternBuilder.positions[points[i].getVal()]);
}
return hash;
}
@Override
public boolean equals(Object obj) {
if (obj == this) return true;
if (obj instanceof SubPuzzleState) {
SubPuzzleState another = (SubPuzzleState) obj;
for (int i = 0; i < n; i++) {
if (!this.points[i].equals(another.points[i]))
return false;
}
return true;
}
return false;
}
public SubPuzzleState move(int i, int d) {
SubPuzzleState state = new SubPuzzleState(this);
int x = state.points[i].getRow() + next[d][0];
int y = state.points[i].getCol() + next[d][1];
state.points[i].setRow(x);
state.points[i].setCol(y);
state.cost = this.cost + 1;
state.parent = this;
return state;
}
public int heuristic() {
int heuristic = 0;
for (int i = 0; i < n; i++) {
int row = (points[i].getVal() - 1) / size;
int col = (points[i].getVal() - 1) % size;
heuristic += Math.abs(points[i].getRow() - row) + Math.abs(points[i].getCol() - col);
if (col < size - 1 && points[i].getRow() == row) {
for (int j = 0; j < n; j++) {
if (points[i].getRow() == points[j].getRow() &&
points[i].getCol() == points[j].getCol() - 1 &&
points[i].getVal() > points[j].getVal()) {
heuristic += 2;
}
}
}
}
this.heuristic = heuristic;
return heuristic;
}
}

@ -0,0 +1,316 @@
package g04.solver.heuristic;
import g04.problem.npuzzle.PuzzlePoint;
import g04.problem.npuzzle.SubPuzzleState;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Queue;
public class DisjointPatternBuilder {
private int size;
private int n;
private int classes;
public static int[] positions = {-1, 0, 0, 1, 2, 1, 2, 0, 1, 3, 4, 2, 3, 5, 4, 5};
public static int[] subsets = {-1, 1, 0, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2, 1, 2, 2};
/**
* 4: 1,048,576
* 3: 65,536
*/
private final Queue<SubPuzzleState> stateQueue = new ArrayDeque<SubPuzzleState>();
public DisjointPatternBuilder(int size, int classes, int n) {
this.size = size;
this.classes = classes;
this.n = n;
}
public int[] breadFirstSreach(SubPuzzleState root, int num) {
stateQueue.clear();
stateQueue.add(root);
HashSet<Integer> stateSet = new HashSet<>();
stateSet.add(root.hashCode());
SubPuzzleState state, child;
//记录pathCost
int[] cost = new int[num];
//广度优先搜索
while (!stateQueue.isEmpty()) {
state = stateQueue.poll();
//遍历每个非零元素
for (int i = 0; i < root.getN(); i++) {
//遍历所有方向
for (int d = 0; d < 4; d++) {
if (state.applicable(i, d)) {
child = state.move(i, d);
if (!stateSet.contains(child.hashCode())) {
stateQueue.add(child);
stateSet.add(child.hashCode());
cost[child.hashCode()] = child.getCost();
}
}
}
}
}
System.out.println("Map size = " + stateSet.size());
stateSet.clear();
return cost;
}
/*
public int[][] generateALLStatus(HashMap[] maps) {
int nums = (int) Math.pow(size * size, n);
//System.out.println(nums);
int[][] cost = new int[classes][nums];
for (int i = 0; i < classes; i++) {
//System.out.println(maps[i].size());
for (Object obj: maps[i].values()) {
SubPuzzleState state = (SubPuzzleState)obj;
cost[i][state.hashCode()] = state.getCost();
//test(state, 854910);
}
}
return cost;
}
public int[] generateALLStatus2(HashMap map, int num) {
//System.out.println(nums);
int[] cost = new int[num];
for (Object obj: map.values()) {
SubPuzzleState state = (SubPuzzleState)obj;
cost[state.hashCode()] = state.getCost();
//test(state, 854910);
}
return cost;
}
*/
public void test(SubPuzzleState state, int hash) {
if (state.hashCode() == hash) {
System.out.println("***********************");
state.draw();
System.out.println(state.getCost());
printPath(state);
System.out.println("***********************");
}
}
public void printPath(SubPuzzleState state) {
System.out.println("--------------------");
while (state.getParent() != null) {
state.draw();
System.out.println("⬆");
state = state.getParent();
}
state.draw();
System.out.println("--------------------");
}
/*
public void save(int[][] cost, String filename) {
//创建字符输出流
FileWriter writeFile = null;
try {
File file = new File("resources/" + filename);
//如果该文件不存在,就创建
if(!file.exists()) {
file.createNewFile();
}
writeFile = new FileWriter(file);
for (int[] ints: cost) {
for (int val: ints) {
writeFile.write(val+ "\t");
}
writeFile.write("\n");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if(writeFile != null) {
writeFile.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
*/
public void save(int[] cost, String filename) {
//创建字符输出流
FileWriter writeFile = null;
try {
File file = new File("resources/" + filename);
//如果该文件不存在,就创建
if(!file.exists()) {
file.createNewFile();
}
writeFile = new FileWriter(file);
for (int val: cost) {
writeFile.write(val+ "\t");
}
writeFile.write("\n");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if(writeFile != null) {
writeFile.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void bulidPuzzle3() {
HashMap[] maps = new HashMap[2];
DisjointPatternBuilder dpd = new DisjointPatternBuilder(3, 2,4);
PuzzlePoint[] points = {
new PuzzlePoint(0, 0, 1),
new PuzzlePoint(0, 1, 2),
new PuzzlePoint(0, 2, 3),
new PuzzlePoint(1, 0, 4),
};
SubPuzzleState root = new SubPuzzleState(3, 4, 4, points);
int[] cost = dpd.breadFirstSreach(root, root.getNum());
dpd.save(cost,"db3(1).txt");
PuzzlePoint[] points2 = {
new PuzzlePoint(1, 1, 5),
new PuzzlePoint(1, 2, 6),
new PuzzlePoint(2, 0, 7),
new PuzzlePoint(2, 1, 8),
};
SubPuzzleState root2 = new SubPuzzleState(3, 4, 4, points2);
cost = dpd.breadFirstSreach(root2, root2.getNum());
dpd.save(cost,"db3(2).txt");
System.out.println("===================");
}
public static void bulidPuzzle4() {
HashMap[] maps = new HashMap[3];
DisjointPatternBuilder dpd = new DisjointPatternBuilder(4, 3,5);
PuzzlePoint[] points = {
new PuzzlePoint(0, 0, 1),
new PuzzlePoint(0, 1, 2),
new PuzzlePoint(0, 2, 3),
new PuzzlePoint(0, 3, 4),
new PuzzlePoint(1, 0, 5),
};
PuzzlePoint[] points2 = {
new PuzzlePoint(1, 1, 6),
new PuzzlePoint(1, 2, 7),
new PuzzlePoint(1, 3, 8),
new PuzzlePoint(2, 0, 9),
new PuzzlePoint(2, 1, 10),
};
PuzzlePoint[] points3 = {
new PuzzlePoint(2, 2, 11),
new PuzzlePoint(2, 3, 12),
new PuzzlePoint(3, 0, 13),
new PuzzlePoint(3, 1, 14),
new PuzzlePoint(3, 2, 15),
};
SubPuzzleState root = new SubPuzzleState(4, 5, 5, points);
int[] cost = dpd.breadFirstSreach(root, root.getNum());
dpd.save(cost,"db4(1).txt");
SubPuzzleState root2 = new SubPuzzleState(4, 5, 5, points2);
cost = dpd.breadFirstSreach(root2, root2.getNum());
dpd.save(cost,"db4(2).txt");
SubPuzzleState root3 = new SubPuzzleState(4, 5, 5, points3);
cost = dpd.breadFirstSreach(root3, root3.getNum());
dpd.save(cost,"db4(3).txt");
System.out.println("===================");
}
public static void bulidPuzzle4_663() {
DisjointPatternBuilder dpd = new DisjointPatternBuilder(4, 3,6);
PuzzlePoint[] points = {
new PuzzlePoint(0, 0, 1),
new PuzzlePoint(1, 0, 5),
new PuzzlePoint(1, 1, 6),
new PuzzlePoint(2, 0, 9),
new PuzzlePoint(2, 1, 10),
new PuzzlePoint(3, 0, 13),
};
PuzzlePoint[] points2 = {
new PuzzlePoint(1, 2, 7),
new PuzzlePoint(1, 3, 8),
new PuzzlePoint(2, 2, 11),
new PuzzlePoint(2, 3, 12),
new PuzzlePoint(3, 1, 14),
new PuzzlePoint(3, 2, 15),
};
PuzzlePoint[] points3 = {
new PuzzlePoint(0, 1, 2),
new PuzzlePoint(0, 2, 3),
new PuzzlePoint(0, 3, 4),
};
SubPuzzleState root = new SubPuzzleState(4, 6, 6, points);
int[] cost = dpd.breadFirstSreach(root, root.getNum());
dpd.save(cost,"db4_6(3).txt");
System.out.println("build db4_6(3).txt finish");
System.out.println("===================");
SubPuzzleState root2 = new SubPuzzleState(4, 6, 6, points2);
cost = dpd.breadFirstSreach(root2, root2.getNum());
dpd.save(cost,"db4_6(4).txt");
System.out.println("build db4_6(4).txt finish");
System.out.println("===================");
SubPuzzleState root3 = new SubPuzzleState(4, 3, 6, points3);
cost = dpd.breadFirstSreach(root3, root3.getNum());
dpd.save(cost,"db4_3(2).txt");
System.out.println("build db4_3(2).txt finish");
System.out.println("===================");
System.out.println("===================");
}
/*
public static void bulidPuzzle4_78() {
DisjointPatternBuilder dpd = new DisjointPatternBuilder(4, 2,8);
PuzzlePoint[] points = {
new PuzzlePoint(0, 0, 1),
new PuzzlePoint(0, 1, 2),
new PuzzlePoint(0, 2, 3),
new PuzzlePoint(0, 3, 4),
new PuzzlePoint(1, 0, 5),
new PuzzlePoint(1, 1, 6),
new PuzzlePoint(1, 2, 7),
new PuzzlePoint(1, 3, 8),
};
PuzzlePoint[] points2 = {
new PuzzlePoint(2, 0, 9),
new PuzzlePoint(2, 1, 10),
new PuzzlePoint(2, 2, 11),
new PuzzlePoint(2, 3, 12),
new PuzzlePoint(3, 0, 13),
new PuzzlePoint(3, 1, 14),
new PuzzlePoint(3, 2, 15),
};
SubPuzzleState root = new SubPuzzleState(4, 8, 8, points);
int[] cost = dpd.breadFirstSreach(root, root.getNum());
dpd.save(cost,"db4_8.txt");
System.out.println("build db4_8.txt finish");
SubPuzzleState root2 = new SubPuzzleState(4, 7, 8, points2);
cost = dpd.breadFirstSreach(root2, root2.getNum());
dpd.save(cost,"db4_7.txt");
System.out.println("build db4_7.txt finish");
System.out.println("===================");
}
*/
public static void main(String[] args) {
//bulidPuzzle3();
//bulidPuzzle4();
bulidPuzzle4_663();
}
}

@ -0,0 +1,85 @@
package g04.solver.heuristic;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class DisjointPatternDatabase {
public int n;
public int size;
public int nums;
public int classes;
public int[][] cost;
public int[] positions;
public int[] subsets;
//zobrist哈希随机值
public static int[][][] zobrist;
public void read(String filename) {
cost = new int[classes][nums];
try {
File file = new File(filename);
Scanner scanner = new Scanner(file);
while (scanner.hasNextLine()) {
for (int i = 0; i < cost.length; i++) {
String[] line = scanner.nextLine().split("\t");
for (int j = 0; j < line.length; j++) {
cost[i][j] = Integer.parseInt(line[j]);
}
}
}
//System.out.println(cost.length);
//System.out.println(cost[0].length);
scanner.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
public void read2(String filename, int i, int n) {
int num = (int) Math.pow(size * size, n);
cost[i] = new int[num];
try {
File file = new File(filename);
Scanner scanner = new Scanner(file);
if (scanner.hasNextLine()) {
String[] line = scanner.nextLine().split("\t");
for (int j = 0; j < line.length; j++) {
cost[i][j] = Integer.parseInt(line[j]);
}
}
System.out.println("class-" + i + ", length: "+ cost[i].length);
scanner.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
public DisjointPatternDatabase(int size, int classes, int n) {
this.size = size;
this.classes = classes;
this.n = n;
this.nums = (int) Math.pow(size * size, n);
cost = new int[classes][];
System.out.println("build: " + "size: " + size + ", n: " + n + ", classes: " + classes);
}
public void load(int pattern) {
switch (pattern) {
case 44:
this.positions = new int[]{-1, 0, 1, 2, 3, 0, 1, 2, 3};
this.subsets = new int[]{-1, 0, 0, 0, 0, 1, 1, 1, 1};
break;
case 663:
this.positions = new int[]{-1, 0, 0, 1, 2, 1, 2, 0, 1, 3, 4, 2, 3, 5, 4, 5};
this.subsets = new int[]{-1, 1, 0, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2, 1, 2, 2};
break;
default:
}
}
public static void main(String[] args) {
}
}

@ -5,6 +5,7 @@ import core.solver.Node;
import core.solver.Searcher;
import core.solver.heuristic.Predictor;
import g04.problem.npuzzle.Puzzle;
import g04.problem.npuzzle.PuzzleState;
import java.util.Deque;
import java.util.Stack;
@ -19,6 +20,8 @@ public class IDAStarSearch implements Searcher {
private int newCutoff;
//最大迭代深度
private int maxIteratorDepth = 256;
//统计扩展结点数
private int expanded = 0;
private final Stack<Node> openStack;
private final Stack<Node> closeStack;
@ -31,34 +34,48 @@ public class IDAStarSearch implements Searcher {
@Override
public Deque<Node> search(Problem problem) {
if (!problem.solvable()){
return null;
}
//获取根节点
openStack.clear();
Node root = problem.root(predictor);
cutoff = root.evaluation();
//System.out.println(predictor.heuristics(problem.getInitialState(), problem.getGoal()));
/*
if (1 == 1)
return null;
*/
while (cutoff < maxIteratorDepth) {
openStack.push(root);
newCutoff = cutoff;
//当栈未空时继续,执行带裁剪值的深度优先搜索
expanded = 0;
while (!openStack.empty()) {
expanded++;
Node node = openStack.pop();
//更新裁剪值为未被探索节点中最小的评估值
newCutoff = (newCutoff > cutoff) ? (Math.min(node.evaluation(), newCutoff)) : node.evaluation();
if (problem.goal(node.getState())) {
return generatePath(node);
}
//当小于等于裁剪值时,继续向深处搜索
if (node.evaluation() <= cutoff) {
for (Node child : ((Puzzle)problem).childs(node)) {
//剪枝,防止节点探索回到父节点
for (Node child : problem.childNodes(node, predictor)) {
//剪枝,防止节点探索回到父节点
if (child.evaluation() <= cutoff) {
if (node.getParent() == null || !node.getParent().equals(child)) {
openStack.push(child);
}
} else {
newCutoff = (newCutoff > cutoff) ? (Math.min(child.evaluation(), newCutoff)) : child.evaluation();
}
}
}
//更新裁剪值
cutoff = newCutoff;
//System.out.println(cutoff);
System.out.println("cutoff: " + cutoff);
System.out.println("expanded node: " + expanded);
}
return null;
}

@ -19,11 +19,16 @@ public class MyFrontier extends AbstractFrontier {
*/
PriorityQueue<Node> frontier = new PriorityQueue(new Comparator<Node>(){
public int compare(Node a, Node b){
return evaluator.compare(a, b);
//return evaluator.compare(a, b);
if (a.evaluation() != b.evaluation()) {
return a.evaluation() - b.evaluation();
} else {
return a.getHeuristic() - b.getHeuristic();
}
}
});
//增加Map集合使得节点的查找时间复杂度降低至O(1)
HashMap<Integer, Node> hashMap=new HashMap();
HashMap<Integer, Node> hashMap=new HashMap<Integer, Node>();
/**
*

@ -17,7 +17,7 @@ class PathFeederTest {
EngineFeeder feeder = new FeederXu();
//从文件中读入问题的实例NPuzzle问题
In problemInput = new In("resources/pathfinding.txt");
In problemInput = new In("resources/npuzzle.txt");
//feeder从文件获取所有问题实例
ArrayList<Problem> problems = feeder.getProblems(problemInput);

@ -17,7 +17,7 @@ class PathFindingTest {
EngineFeeder feeder = new FeederXu();
//从文件中读入问题的实例NPuzzle问题
In problemInput = new In("resources/pathfinding.txt");
In problemInput = new In("resources/npuzzle.txt");
//feeder从文件获取所有问题实例
ArrayList<Problem> problems = feeder.getProblems(problemInput);

Loading…
Cancel
Save