Implemented heuristic

This commit is contained in:
Niklas Birk 2019-04-02 23:07:54 +02:00
parent d4e54493c7
commit 9e51fc8c69
7 changed files with 135 additions and 26 deletions

View File

@ -28,10 +28,10 @@ public class EightPuzzleNode extends Node<int[][]>
{ {
final var successors = new ArrayList<Node<int[][]>>(); final var successors = new ArrayList<Node<int[][]>>();
final var emptyPosition = Objects.requireNonNull(detectEmptyPosition()); final var emptyPosition = Objects.requireNonNull(detectEmptyPosition());
final int x = emptyPosition.getX(); final var x = emptyPosition.getX();
final int y = emptyPosition.getY(); final var y = emptyPosition.getY();
for (final Direction dir : Direction.values()) for (final var dir : Direction.values())
{ {
final var newState = copyOfState(); final var newState = copyOfState();
@ -50,7 +50,6 @@ public class EightPuzzleNode extends Node<int[][]>
{ {
successors.add(successor); successors.add(successor);
} }
} }
catch (final ArrayIndexOutOfBoundsException ignored) catch (final ArrayIndexOutOfBoundsException ignored)
{ {
@ -63,9 +62,9 @@ public class EightPuzzleNode extends Node<int[][]>
@Override @Override
public String toString() public String toString()
{ {
final StringBuilder builder = new StringBuilder(); final var builder = new StringBuilder();
for (final int[] row : super.value) for (final var row : super.value)
{ {
builder.append(Arrays.toString(row)).append("\n"); builder.append(Arrays.toString(row)).append("\n");
} }
@ -80,9 +79,9 @@ public class EightPuzzleNode extends Node<int[][]>
return false; return false;
} }
for (int row = 0; row < super.value.length; row++) for (var row = 0; row < super.value.length; row++)
{ {
for (int col = 0; col < super.value[row].length; col++) for (var col = 0; col < super.value[row].length; col++)
{ {
if (super.value[row][col] != node.value[row][col]) if (super.value[row][col] != node.value[row][col])
{ {
@ -96,9 +95,9 @@ public class EightPuzzleNode extends Node<int[][]>
private IntPair detectEmptyPosition() private IntPair detectEmptyPosition()
{ {
for (int row = 0; row < super.value.length; row++) for (var row = 0; row < super.value.length; row++)
{ {
for (int col = 0; col < super.value[row].length; col++) for (var col = 0; col < super.value[row].length; col++)
{ {
if (super.value[row][col] == 0) if (super.value[row][col] == 0)
{ {
@ -114,7 +113,7 @@ public class EightPuzzleNode extends Node<int[][]>
{ {
final var copy = new int[3][3]; final var copy = new int[3][3];
for (int y = 0; y < copy.length; y++) for (var y = 0; y < copy.length; y++)
{ {
System.arraycopy(super.value[y], 0, copy[y], 0, copy.length); System.arraycopy(super.value[y], 0, copy[y], 0, copy.length);
} }
@ -124,15 +123,9 @@ public class EightPuzzleNode extends Node<int[][]>
private EightPuzzleNode swapStateField(final int[][] newState, final IntPair emptyPos, final IntPair posToSwap) private EightPuzzleNode swapStateField(final int[][] newState, final IntPair emptyPos, final IntPair posToSwap)
{ {
final int posToSwapX = posToSwap.getX(); final var tmp = newState[posToSwap.getY()][posToSwap.getX()];
final int postToSwapY = posToSwap.getY(); newState[posToSwap.getY()][posToSwap.getX()] = newState[emptyPos.getY()][emptyPos.getX()];
final int emptyX = emptyPos.getX(); newState[emptyPos.getY()][emptyPos.getX()] = tmp;
final int emptyY = emptyPos.getY();
final int tmp;
tmp = newState[postToSwapY][posToSwapX];
newState[postToSwapY][posToSwapX] = newState[emptyY][emptyX];
newState[emptyY][emptyX] = tmp;
return new EightPuzzleNode(newState, this); return new EightPuzzleNode(newState, this);
} }
@ -162,6 +155,5 @@ public class EightPuzzleNode extends Node<int[][]>
private enum Direction private enum Direction
{ {
TOP, RIGHT, DOWN, LEFT TOP, RIGHT, DOWN, LEFT
} }
} }

View File

@ -1,6 +1,9 @@
package search; package search;
import search.heuristic.Heuristic;
import java.util.List; import java.util.List;
import java.util.Objects;
public abstract class Node<T> public abstract class Node<T>
{ {
@ -14,7 +17,7 @@ public abstract class Node<T>
protected Node(final T value, final Node<T> parent) protected Node(final T value, final Node<T> parent)
{ {
this.value = value; this.value = Objects.requireNonNull(value);
this.parent = parent; this.parent = parent;
} }
@ -28,6 +31,6 @@ public abstract class Node<T>
return this.parent; return this.parent;
} }
public abstract boolean isTargetReached(Node<T> target); public abstract boolean isTargetReached(final Node<T> target);
public abstract List<Node<T>> generateSuccessors(); public abstract List<Node<T>> generateSuccessors();
} }

View File

@ -1,5 +1,39 @@
package search.heuristic; package search.heuristic;
public class AStar import search.Node;
import java.util.Comparator;
import java.util.PriorityQueue;
public class AStar<T>
{ {
private final Heuristic<T> heuristicFunction;
public AStar(final Heuristic<T> heuristicFunction)
{
this.heuristicFunction = heuristicFunction;
}
public Node<T> heuristicSearch(final Node<T> start, final Node<T> target)
{
final var nodes = new PriorityQueue<Node<T>>(Comparator.comparingInt(node -> heuristicFunction.heuristic(node, target)));
nodes.add(start);
while (true)
{
if (nodes.isEmpty())
{
return null;
}
final var node = nodes.poll();
if (node.isTargetReached(target))
{
return node;
}
nodes.addAll(node.generateSuccessors());
}
}
} }

View File

@ -0,0 +1,8 @@
package search.heuristic;
import search.Node;
public interface Heuristic<T>
{
int heuristic(Node<T> node, Node<T> target);
}

View File

@ -11,7 +11,7 @@ public class BreadthFirstSearch
{ {
final var newNodes = new ArrayList<Node<T>>(); final var newNodes = new ArrayList<Node<T>>();
for (final Node<T> node : nodes) for (final var node : nodes)
{ {
if (node.isTargetReached(target)) if (node.isTargetReached(target))
{ {

View File

@ -6,7 +6,7 @@ public class IterativeDeepening
{ {
public <T> Node<T> iterativeDeepening(final Node<T> node, final Node<T> target) public <T> Node<T> iterativeDeepening(final Node<T> node, final Node<T> target)
{ {
int lowBarrier = 0; var lowBarrier = 0;
Node<T> resultNode; Node<T> resultNode;

View File

@ -1,8 +1,80 @@
package search.heuristic; package search.heuristic;
import org.junit.jupiter.api.Test;
import search.EightPuzzleNode;
import search.Node;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
import static search.SearchTestUtils.printSolution;
class AStarTest class AStarTest
{ {
@Test
void shouldReturnCorrectTargetCubekNodeHeuristik1()
{
final int[][] state = {
{3, 5, 0},
{1, 2, 6},
{4, 7, 8}
};
final var root = new EightPuzzleNode(state);
final int[][] targetState = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 0}
};
final var expected = new EightPuzzleNode(targetState);
final var actual = new AStar<>(this::h1).heuristicSearch(root, expected);
printSolution(actual);
}
@Test
void shouldReturnCorrectTargetCubekNodeHeuristic2()
{
final int[][] state = {
{2, 0, 4},
{6, 7, 1},
{8, 5, 3}
};
final var root = new EightPuzzleNode(state);
final int[][] targetState = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 0}
};
final var expected = new EightPuzzleNode(targetState);
final var actual = new AStar<>(this::h2).heuristicSearch(root, expected);
printSolution(actual);
}
private int h1(final Node<int[][]> node, final Node<int[][]> target)
{
final var value = node.getValue();
final var targetValue = target.getValue();
var counter = 0;
for (var row = 0; row < value.length; row++)
{
for (var col = 0; col < value[row].length; col++)
{
if (value[row][col] != targetValue[row][col])
{
counter++;
}
}
}
return counter;
}
private int h2(final Node<int[][]> node, final Node<int[][]> target)
{
return 0;
}
} }