Changed several implementation details and added depth-first-search
This commit is contained in:
parent
481b292d17
commit
82e7e618d7
8
.idea/inspectionProfiles/Project_Default.xml
generated
8
.idea/inspectionProfiles/Project_Default.xml
generated
@ -1,6 +1,12 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="OptionalGetWithoutIsPresent" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SuspiciousNameCombination" enabled="false" level="WARNING" enabled_by_default="false">
|
||||
<group names="x,width,left,right" />
|
||||
<group names="y,height,top,bottom" />
|
||||
<ignored>
|
||||
<option name="METHOD_MATCHER_CONFIG" value="java.io.PrintStream,println,java.io.PrintWriter,println,java.lang.System,identityHashCode,java.sql.PreparedStatement,set.*,java.sql.ResultSet,update.*,java.sql.SQLOutput,write.*,java.lang.Integer,compare.*,java.lang.Long,compare.*,java.lang.Short,compare,java.lang.Byte,compare,java.lang.Character,compare,java.lang.Boolean,compare,java.lang.Math,.*,java.lang.StrictMath,.*" />
|
||||
</ignored>
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
@ -1,5 +1,3 @@
|
||||
package search.breadthfirstsearch;
|
||||
|
||||
public class Main
|
||||
{
|
||||
public static void main(String[] args)
|
@ -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<int[][]>
|
||||
@Override
|
||||
public boolean isTargetReached(Node<int[][]> 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<int[][]>
|
||||
{
|
||||
var successors = new ArrayList<Node<int[][]>>();
|
||||
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<int[][]>
|
||||
|
||||
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<int[][]>
|
||||
}
|
||||
|
||||
@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<int[][]> 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<int[][]>
|
||||
{
|
||||
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<int[][]>
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package search.breadthfirstsearch;
|
||||
package search;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -14,7 +14,7 @@ public abstract class Node<T>
|
||||
|
||||
protected Node(T value, Node<T> parent)
|
||||
{
|
||||
if (!isValidValue(value))
|
||||
if (!isValidParameterValue(value))
|
||||
{
|
||||
throw new IllegalArgumentException("Illegal node value");
|
||||
}
|
||||
@ -33,13 +33,7 @@ public abstract class Node<T>
|
||||
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<T> target);
|
||||
public abstract List<Node<T>> generateSuccessors();
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
package search.breadthfirstsearch;
|
||||
|
||||
import search.Node;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
33
src/search/depthfirstsearch/DepthFirstSearch.java
Normal file
33
src/search/depthfirstsearch/DepthFirstSearch.java
Normal file
@ -0,0 +1,33 @@
|
||||
package search.depthfirstsearch;
|
||||
|
||||
import search.Node;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class DepthFirstSearch
|
||||
{
|
||||
public <T> Node<T> depthFirstSearch(Node<T> node, Node<T> 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;
|
||||
}
|
||||
}
|
@ -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
|
||||
{
|
20
test/search/SearchTestUtils.java
Normal file
20
test/search/SearchTestUtils.java
Normal file
@ -0,0 +1,20 @@
|
||||
package search;
|
||||
|
||||
public class SearchTestUtils
|
||||
{
|
||||
public static <T> void printSolution(Node<T> 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");
|
||||
}
|
||||
}
|
@ -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<int[][]> 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);
|
||||
}
|
||||
}
|
56
test/search/depthfirstsearch/DepthFirstSearchTest.java
Normal file
56
test/search/depthfirstsearch/DepthFirstSearchTest.java
Normal file
@ -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);
|
||||
// }
|
||||
}
|
Loading…
Reference in New Issue
Block a user