diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
index 0b9b0fb..25c2334 100644
--- a/.idea/inspectionProfiles/Project_Default.xml
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -1,6 +1,12 @@
-
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/search/breadthfirstsearch/Main.java b/src/Main.java
similarity index 68%
rename from src/search/breadthfirstsearch/Main.java
rename to src/Main.java
index f74021c..e90a4ee 100644
--- a/src/search/breadthfirstsearch/Main.java
+++ b/src/Main.java
@@ -1,5 +1,3 @@
-package search.breadthfirstsearch;
-
public class Main
{
public static void main(String[] args)
diff --git a/src/search/breadthfirstsearch/EightPuzzleNode.java b/src/search/EightPuzzleNode.java
similarity index 59%
rename from src/search/breadthfirstsearch/EightPuzzleNode.java
rename to src/search/EightPuzzleNode.java
index 1b8fd07..e2ad6c1 100644
--- a/src/search/breadthfirstsearch/EightPuzzleNode.java
+++ b/src/search/EightPuzzleNode.java
@@ -1,4 +1,4 @@
-package search.breadthfirstsearch;
+package search;
import java.util.ArrayList;
import java.util.Arrays;
@@ -21,18 +21,7 @@ public class EightPuzzleNode extends Node
@Override
public boolean isTargetReached(Node target)
{
- for (int row = 0; row < super.value.length; row++)
- {
- for (int col = 0; col < super.value[row].length; col++)
- {
- if (super.value[row][col] != target.value[row][col])
- {
- return false;
- }
- }
- }
-
- return true;
+ return valueEquals(target);
}
@Override
@@ -40,8 +29,8 @@ public class EightPuzzleNode extends Node
{
var successors = new ArrayList>();
var emptyPosition = Objects.requireNonNull(detectEmptyPosition());
- int x = emptyPosition.getRight();
- int y = emptyPosition.getLeft();
+ int x = emptyPosition.getX();
+ int y = emptyPosition.getY();
for (Direction dir : Direction.values())
{
@@ -49,34 +38,20 @@ public class EightPuzzleNode extends Node
try
{
- int tmp;
- switch (dir)
+ var posToSwap = switch (dir) {
+ case TOP -> new IntPair(x, y-1);
+ case RIGHT -> new IntPair(x+1, y);
+ case DOWN -> new IntPair(x, y+1);
+ case LEFT -> new IntPair(x-1, y);
+ };
+
+ var successor = this.swapStateField(newState, emptyPosition, posToSwap);
+
+ if (!successor.valueEquals(this) && !successor.valueEquals(super.getParent()))
{
- case TOP:
- tmp = newState[y-1][x];
- newState[y-1][x] = newState[y][x];
- newState[y][x] = tmp;
- successors.add(new EightPuzzleNode(newState, this));
- break;
- case RIGHT:
- tmp = newState[y][x+1];
- newState[y][x+1] = newState[y][x];
- newState[y][x] = tmp;
- successors.add(new EightPuzzleNode(newState, this));
- break;
- case DOWN:
- tmp = newState[y+1][x];
- newState[y+1][x] = newState[y][x];
- newState[y][x] = tmp;
- successors.add(new EightPuzzleNode(newState, this));
- break;
- case LEFT:
- tmp = newState[y][x-1];
- newState[y][x-1] = newState[y][x];
- newState[y][x] = tmp;
- successors.add(new EightPuzzleNode(newState, this));
- break;
+ successors.add(successor);
}
+
}
catch (ArrayIndexOutOfBoundsException ignored)
{
@@ -87,13 +62,47 @@ public class EightPuzzleNode extends Node
}
@Override
- protected boolean isValidValue(int[][] state)
+ protected boolean isValidParameterValue(int[][] state)
{
var numbers = Arrays.stream(state).flatMapToInt(IntStream::of).toArray();
return numbersAreInAllowedRange(numbers) && numbersAreUnique(numbers);
}
+ @Override
+ public String toString()
+ {
+ StringBuilder builder = new StringBuilder();
+
+ for (int[] row : super.value)
+ {
+ builder.append(Arrays.toString(row)).append("\n");
+ }
+
+ return builder.toString();
+ }
+
+ private boolean valueEquals(Node node)
+ {
+ if (node == null)
+ {
+ return false;
+ }
+
+ for (int row = 0; row < super.value.length; row++)
+ {
+ for (int col = 0; col < super.value[row].length; col++)
+ {
+ if (super.value[row][col] != node.value[row][col])
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
private boolean numbersAreInAllowedRange(int[] numbers)
{
return Arrays.stream(numbers).min().getAsInt() == 0 && Arrays.stream(numbers).max().getAsInt() == 8;
@@ -112,7 +121,7 @@ public class EightPuzzleNode extends Node
{
if (super.value[row][col] == 0)
{
- return new IntPair(row, col);
+ return new IntPair(col, row);
}
}
}
@@ -132,38 +141,39 @@ public class EightPuzzleNode extends Node
return copy;
}
- @Override
- public String toString()
+ private EightPuzzleNode swapStateField(int[][] newState, IntPair emptyPos, IntPair posToSwap)
{
- StringBuilder builder = new StringBuilder("Node:\n");
+ int posToSwapX = posToSwap.getX();
+ int postToSwapY = posToSwap.getY();
+ int emptyX = emptyPos.getX();
+ int emptyY = emptyPos.getY();
+ int tmp;
- for (int[] row : super.value)
- {
- builder.append(Arrays.toString(row)).append("\n");
- }
+ tmp = newState[postToSwapY][posToSwapX];
+ newState[postToSwapY][posToSwapX] = newState[emptyY][emptyX];
+ newState[emptyY][emptyX] = tmp;
- return builder.toString();
+ return new EightPuzzleNode(newState, this);
}
private class IntPair
{
- private final int left;
+ private final int x;
+ private final int y;
- private final int right;
-
- public IntPair(int left, int right)
+ public IntPair(int x, int y)
{
- this.left = left;
- this.right = right;
+ this.x = x;
+ this.y = y;
}
- public int getLeft()
+ public int getX()
{
- return left;
+ return x;
}
- public int getRight()
+ public int getY()
{
- return right;
+ return y;
}
}
diff --git a/src/search/breadthfirstsearch/Node.java b/src/search/Node.java
similarity index 74%
rename from src/search/breadthfirstsearch/Node.java
rename to src/search/Node.java
index 3cc038e..db163a8 100644
--- a/src/search/breadthfirstsearch/Node.java
+++ b/src/search/Node.java
@@ -1,4 +1,4 @@
-package search.breadthfirstsearch;
+package search;
import java.util.List;
@@ -14,7 +14,7 @@ public abstract class Node
protected Node(T value, Node parent)
{
- if (!isValidValue(value))
+ if (!isValidParameterValue(value))
{
throw new IllegalArgumentException("Illegal node value");
}
@@ -33,13 +33,7 @@ public abstract class Node
return this.parent;
}
- @Override
- public String toString()
- {
- return this.value.toString();
- }
-
- protected abstract boolean isValidValue(T value);
+ protected abstract boolean isValidParameterValue(T value);
public abstract boolean isTargetReached(Node target);
public abstract List> generateSuccessors();
}
diff --git a/src/search/breadthfirstsearch/BreadthFirstSearch.java b/src/search/breadthfirstsearch/BreadthFirstSearch.java
index 6438b10..fa8e7a2 100644
--- a/src/search/breadthfirstsearch/BreadthFirstSearch.java
+++ b/src/search/breadthfirstsearch/BreadthFirstSearch.java
@@ -1,5 +1,7 @@
package search.breadthfirstsearch;
+import search.Node;
+
import java.util.ArrayList;
import java.util.List;
diff --git a/src/search/depthfirstsearch/DepthFirstSearch.java b/src/search/depthfirstsearch/DepthFirstSearch.java
new file mode 100644
index 0000000..110eaae
--- /dev/null
+++ b/src/search/depthfirstsearch/DepthFirstSearch.java
@@ -0,0 +1,33 @@
+package search.depthfirstsearch;
+
+import search.Node;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class DepthFirstSearch
+{
+ public Node depthFirstSearch(Node node, Node target)
+ {
+ if (node.isTargetReached(target))
+ {
+ return node;
+ }
+
+ var newNodes = node.generateSuccessors();
+
+ while (!newNodes.isEmpty())
+ {
+ var resultNode = depthFirstSearch(newNodes.get(0), target);
+
+ if (resultNode != null)
+ {
+ return resultNode;
+ }
+
+ newNodes.remove(0);
+ }
+
+ return null;
+ }
+}
diff --git a/test/search/breadthfirstsearch/EightPuzzleNodeTest.java b/test/search/EightPuzzleNodeTest.java
similarity index 98%
rename from test/search/breadthfirstsearch/EightPuzzleNodeTest.java
rename to test/search/EightPuzzleNodeTest.java
index 558bbd0..98bd855 100644
--- a/test/search/breadthfirstsearch/EightPuzzleNodeTest.java
+++ b/test/search/EightPuzzleNodeTest.java
@@ -1,7 +1,8 @@
-package search.breadthfirstsearch;
+package search;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
+import search.EightPuzzleNode;
class EightPuzzleNodeTest
{
diff --git a/test/search/SearchTestUtils.java b/test/search/SearchTestUtils.java
new file mode 100644
index 0000000..1bedc34
--- /dev/null
+++ b/test/search/SearchTestUtils.java
@@ -0,0 +1,20 @@
+package search;
+
+public class SearchTestUtils
+{
+ public static void printSolution(Node targetNode)
+ {
+ var node = targetNode;
+
+ System.out.println("Read from down to top!");
+ System.out.println("END");
+
+ while (node != null)
+ {
+ System.out.println(node);
+ node = node.getParent();
+ }
+
+ System.out.println("START");
+ }
+}
diff --git a/test/search/breadthfirstsearch/BreadthFirstSearchTest.java b/test/search/breadthfirstsearch/BreadthFirstSearchTest.java
index ff8f1c9..d51b2b7 100644
--- a/test/search/breadthfirstsearch/BreadthFirstSearchTest.java
+++ b/test/search/breadthfirstsearch/BreadthFirstSearchTest.java
@@ -1,10 +1,12 @@
package search.breadthfirstsearch;
import org.junit.jupiter.api.Test;
+import search.EightPuzzleNode;
-import java.util.Arrays;
import java.util.List;
+import static search.SearchTestUtils.printSolution;
+
class BreadthFirstSearchTest
{
@Test
@@ -26,12 +28,28 @@ class BreadthFirstSearchTest
var actual = new BreadthFirstSearch().breadthFirstSearch(List.of(root), expected);
- System.out.println("Target: " + Arrays.deepToString(targetState));
- System.out.println("Actual:\n" + actual);
+ printSolution(actual);
}
- private void printSolution(Node targetNode)
+ @Test
+ void shouldReturnCorrectTargetChubekNode()
{
+ int[][] state = {
+ {2, 0, 4},
+ {6, 7, 1},
+ {8, 5, 3}
+ };
+ var root = new EightPuzzleNode(state);
+ int[][] targetState = {
+ {1, 2, 3},
+ {4, 5, 6},
+ {7, 8, 0}
+ };
+ var expected = new EightPuzzleNode(targetState);
+
+ var actual = new BreadthFirstSearch().breadthFirstSearch(List.of(root), expected);
+
+ printSolution(actual);
}
}
\ No newline at end of file
diff --git a/test/search/depthfirstsearch/DepthFirstSearchTest.java b/test/search/depthfirstsearch/DepthFirstSearchTest.java
new file mode 100644
index 0000000..e9732cb
--- /dev/null
+++ b/test/search/depthfirstsearch/DepthFirstSearchTest.java
@@ -0,0 +1,56 @@
+package search.depthfirstsearch;
+
+import org.junit.jupiter.api.Test;
+import search.EightPuzzleNode;
+import search.breadthfirstsearch.BreadthFirstSearch;
+
+import java.util.List;
+
+import static search.SearchTestUtils.printSolution;
+
+class DepthFirstSearchTest
+{
+ @Test
+ void shouldReturnCorrectTarget()
+ {
+ int[][] state = {
+ {1, 2, 3},
+ {4, 5, 6},
+ {7, 0, 8}
+ };
+ var root = new EightPuzzleNode(state);
+
+ int[][] targetState = {
+ {1, 2, 3},
+ {4, 5, 6},
+ {7, 8, 0}
+ };
+ var expected = new EightPuzzleNode(targetState);
+
+ var actual = new DepthFirstSearch().depthFirstSearch(root, expected);
+
+ printSolution(actual);
+ }
+
+// @Test
+// void shouldReturnCorrectTargetChubekNode()
+// {
+// int[][] state = {
+// {2, 0, 4},
+// {6, 7, 1},
+// {8, 5, 3}
+// };
+// var root = new EightPuzzleNode(state);
+//
+// int[][] targetState = {
+// {1, 2, 3},
+// {4, 5, 6},
+// {7, 8, 0}
+// };
+// var expected = new EightPuzzleNode(targetState);
+//
+// var actual = new DepthFirstSearch().depthFirstSearch(root, expected);
+//
+// printSolution(actual);
+// }
+}
\ No newline at end of file