Compare commits
10 Commits
4cfaf3803c
...
e1c93881af
Author | SHA1 | Date | |
---|---|---|---|
e1c93881af | |||
3c43233d96 | |||
e4fcb06949 | |||
81b5fd2ffb | |||
ca2efaa1fb | |||
ea317267de | |||
f9a4040946 | |||
1842ade5c0 | |||
24c9e0b247 | |||
d0adbf0acb |
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
/ki_rwu_java.iml
|
||||||
|
/.idea/
|
||||||
|
/lib/
|
||||||
|
/out/
|
3
README.md
Normal file
3
README.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# KI_RWU
|
||||||
|
|
||||||
|
This is a repository containing basic AI algorithms taught in the AI lecture at _Hochschule Ravensburg-Weingarten_.
|
0
resources/app1.data
Normal file → Executable file
0
resources/app1.data
Normal file → Executable file
0
resources/app1.test
Normal file → Executable file
0
resources/app1.test
Normal file → Executable file
0
src/machine_learning/DataClass.java
Normal file → Executable file
0
src/machine_learning/DataClass.java
Normal file → Executable file
0
src/machine_learning/MachineLearning.java
Normal file → Executable file
0
src/machine_learning/MachineLearning.java
Normal file → Executable file
23
src/machine_learning/Vector.java
Normal file → Executable file
23
src/machine_learning/Vector.java
Normal file → Executable file
@ -34,7 +34,7 @@ public class Vector
|
|||||||
|
|
||||||
public Vector add(Vector b)
|
public Vector add(Vector b)
|
||||||
{
|
{
|
||||||
if (this.dimension() != b.dimension()) throw new IllegalArgumentException("Dimensions must be equals.");
|
checkEqualDimensions(b);
|
||||||
return new Vector(IntStream.range(0,
|
return new Vector(IntStream.range(0,
|
||||||
this.dimension())
|
this.dimension())
|
||||||
.mapToObj(i -> this.get(i) + b.get(i))
|
.mapToObj(i -> this.get(i) + b.get(i))
|
||||||
@ -45,7 +45,7 @@ public class Vector
|
|||||||
|
|
||||||
public Vector subtract(Vector b)
|
public Vector subtract(Vector b)
|
||||||
{
|
{
|
||||||
if (this.dimension() != b.dimension()) throw new IllegalArgumentException("Dimensions must be equals.");
|
checkEqualDimensions(b);
|
||||||
return new Vector(IntStream.range(0,
|
return new Vector(IntStream.range(0,
|
||||||
this.dimension())
|
this.dimension())
|
||||||
.mapToObj(i -> this.get(i) - b.get(i))
|
.mapToObj(i -> this.get(i) - b.get(i))
|
||||||
@ -55,7 +55,7 @@ public class Vector
|
|||||||
|
|
||||||
public double scalar(Vector b)
|
public double scalar(Vector b)
|
||||||
{
|
{
|
||||||
if (this.dimension() != b.dimension()) throw new IllegalArgumentException("Dimensions must be equals.");
|
checkEqualDimensions(b);
|
||||||
return IntStream.range(0,
|
return IntStream.range(0,
|
||||||
this.dimension())
|
this.dimension())
|
||||||
.mapToDouble(i -> this.get(i) * b.get(i))
|
.mapToDouble(i -> this.get(i) * b.get(i))
|
||||||
@ -80,14 +80,9 @@ public class Vector
|
|||||||
|
|
||||||
public Vector divide(double div)
|
public Vector divide(double div)
|
||||||
{
|
{
|
||||||
var divided = new ArrayList<Double>();
|
return new Vector(IntStream.range(0, this.dimension())
|
||||||
|
.mapToObj(i -> this.values.get(i) / div)
|
||||||
for (int i = 0; i < this.dimension(); i++)
|
.collect(Collectors.toCollection(ArrayList::new)));
|
||||||
{
|
|
||||||
divided.add(this.values.get(i) / div);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Vector(divided);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public double get(int index)
|
public double get(int index)
|
||||||
@ -133,4 +128,10 @@ public class Vector
|
|||||||
{
|
{
|
||||||
return this.values.toString();
|
return this.values.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkEqualDimensions(Vector b)
|
||||||
|
{
|
||||||
|
if (this.dimension() != b.dimension())
|
||||||
|
throw new IllegalArgumentException("Dimensions must be equal");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
0
src/machine_learning/nearest_neighbour/CrossValidation.java
Normal file → Executable file
0
src/machine_learning/nearest_neighbour/CrossValidation.java
Normal file → Executable file
2
src/machine_learning/nearest_neighbour/Distance.java → src/machine_learning/nearest_neighbour/DistanceFunction.java
Normal file → Executable file
2
src/machine_learning/nearest_neighbour/Distance.java → src/machine_learning/nearest_neighbour/DistanceFunction.java
Normal file → Executable file
@ -2,7 +2,7 @@ package machine_learning.nearest_neighbour;
|
|||||||
|
|
||||||
import machine_learning.Vector;
|
import machine_learning.Vector;
|
||||||
|
|
||||||
public interface Distance
|
public interface DistanceFunction
|
||||||
{
|
{
|
||||||
double distance(Vector a, Vector b);
|
double distance(Vector a, Vector b);
|
||||||
}
|
}
|
12
src/machine_learning/nearest_neighbour/KNearestNeighbour.java
Normal file → Executable file
12
src/machine_learning/nearest_neighbour/KNearestNeighbour.java
Normal file → Executable file
@ -15,18 +15,18 @@ public class KNearestNeighbour implements MachineLearning
|
|||||||
private List<Vector> positives;
|
private List<Vector> positives;
|
||||||
private List<Vector> negatives;
|
private List<Vector> negatives;
|
||||||
|
|
||||||
private final Distance distance;
|
private final DistanceFunction distanceFunction;
|
||||||
|
|
||||||
private final int k;
|
private final int k;
|
||||||
|
|
||||||
public KNearestNeighbour(Distance distance)
|
public KNearestNeighbour(DistanceFunction distanceFunction)
|
||||||
{
|
{
|
||||||
this(distance, 1);
|
this(distanceFunction, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public KNearestNeighbour(Distance distance, int k)
|
public KNearestNeighbour(DistanceFunction distanceFunction, int k)
|
||||||
{
|
{
|
||||||
this.distance = distance;
|
this.distanceFunction = distanceFunction;
|
||||||
this.k = k;
|
this.k = k;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,7 +67,7 @@ public class KNearestNeighbour implements MachineLearning
|
|||||||
private List<Vector> nearestNeighbours(List<Vector> vectors, Vector vector)
|
private List<Vector> nearestNeighbours(List<Vector> vectors, Vector vector)
|
||||||
{
|
{
|
||||||
return vectors.parallelStream()
|
return vectors.parallelStream()
|
||||||
.map(v -> Map.entry(this.distance.distance(v, vector), v))
|
.map(v -> Map.entry(this.distanceFunction.distance(v, vector), v))
|
||||||
.sorted((e1, e2) -> e1.getKey() >= e2.getKey() ? (e1.getKey().equals(e2.getKey()) ? 0 : 1) : -1)
|
.sorted((e1, e2) -> e1.getKey() >= e2.getKey() ? (e1.getKey().equals(e2.getKey()) ? 0 : 1) : -1)
|
||||||
.map(Map.Entry::getValue)
|
.map(Map.Entry::getValue)
|
||||||
.collect(Collectors.toList())
|
.collect(Collectors.toList())
|
||||||
|
0
src/machine_learning/perceptron/Perceptron.java
Normal file → Executable file
0
src/machine_learning/perceptron/Perceptron.java
Normal file → Executable file
93
src/search/ChessKnightNode.java
Executable file
93
src/search/ChessKnightNode.java
Executable file
@ -0,0 +1,93 @@
|
|||||||
|
package search;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For a Kata on codewars.com.
|
||||||
|
* How many moves need a knight (Springer) to get from a given start to a given end on the chessboard,
|
||||||
|
* e.g. a3 -> b5, the knight needs 1 move;
|
||||||
|
* a1 -> f1, the knight needs 3 moves
|
||||||
|
*/
|
||||||
|
public class ChessKnightNode extends Node<ChessKnightNode.KnightPair> {
|
||||||
|
public ChessKnightNode(final KnightPair state) {
|
||||||
|
super(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ChessKnightNode(final KnightPair value, final Node<KnightPair> parent, final int heuristicCosts) {
|
||||||
|
super(value, parent, heuristicCosts);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTargetReached(final Node<KnightPair> target) {
|
||||||
|
return this.valueEquals(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Node<KnightPair>> generateSuccessors() {
|
||||||
|
final var successors = new ArrayList<Node<KnightPair>>();
|
||||||
|
|
||||||
|
for (final var dir : ChessDirections.values()) {
|
||||||
|
try {
|
||||||
|
final char newCol = (char) (super.value.col() + dir.getColChange());
|
||||||
|
final char newRow = (char) (super.value.row() + dir.getRowChange());
|
||||||
|
|
||||||
|
final var newState = new KnightPair(newCol, newRow);
|
||||||
|
|
||||||
|
final var successor = new ChessKnightNode(newState, this, super.heuristicCosts + 1);
|
||||||
|
|
||||||
|
if (!successor.valueEquals(this) && !successor.valueEquals(super.getParent())) {
|
||||||
|
successors.add(successor);
|
||||||
|
}
|
||||||
|
} catch (final ChessKnightException ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return successors;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean valueEquals(final Node<KnightPair> node) {
|
||||||
|
return node != null && super.value.equals(node.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "%c%c".formatted(super.value.col, super.value.row);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected record KnightPair(char col, char row) {
|
||||||
|
public KnightPair {
|
||||||
|
if (col < 'a' || col > 'h') throw new ChessKnightException("Row out of bounds at index %c".formatted(col));
|
||||||
|
if (row < '1' || row > '8') throw new ChessKnightException("Column out of bounds at index %c".formatted(row));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected enum ChessDirections {
|
||||||
|
TOP_LEFT(-1, 2), TOP_RIGHT(1, 2),
|
||||||
|
RIGHT_TOP(2, 1), RIGHT_BOTTOM(2, -1),
|
||||||
|
DOWN_RIGHT(1 ,-2), DOWN_LEFT(-1,-2),
|
||||||
|
LEFT_BOTTOM(-2,-1), LEFT_TOP(-2,1);
|
||||||
|
|
||||||
|
public final int colChange;
|
||||||
|
public final int rowChange;
|
||||||
|
|
||||||
|
ChessDirections( final int colChange, final int rowChange) {
|
||||||
|
this.colChange = colChange;
|
||||||
|
this.rowChange = rowChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getColChange() {
|
||||||
|
return colChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRowChange() {
|
||||||
|
return rowChange;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static class ChessKnightException extends IndexOutOfBoundsException {
|
||||||
|
public ChessKnightException(final String s) {
|
||||||
|
super(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
0
src/search/Direction.java
Normal file → Executable file
0
src/search/Direction.java
Normal file → Executable file
0
src/search/EightPuzzleNode.java
Normal file → Executable file
0
src/search/EightPuzzleNode.java
Normal file → Executable file
0
src/search/IntPair.java
Normal file → Executable file
0
src/search/IntPair.java
Normal file → Executable file
0
src/search/LabyrinthineNode.java
Normal file → Executable file
0
src/search/LabyrinthineNode.java
Normal file → Executable file
0
src/search/Node.java
Normal file → Executable file
0
src/search/Node.java
Normal file → Executable file
0
src/search/heuristic/AStar.java
Normal file → Executable file
0
src/search/heuristic/AStar.java
Normal file → Executable file
0
src/search/heuristic/HeuristicEstimationFunction.java
Normal file → Executable file
0
src/search/heuristic/HeuristicEstimationFunction.java
Normal file → Executable file
0
src/search/uninformed/breadthfirstsearch/BreadthFirstSearch.java
Normal file → Executable file
0
src/search/uninformed/breadthfirstsearch/BreadthFirstSearch.java
Normal file → Executable file
0
src/search/uninformed/depthfirstsearch/DepthFirstSearch.java
Normal file → Executable file
0
src/search/uninformed/depthfirstsearch/DepthFirstSearch.java
Normal file → Executable file
0
src/search/uninformed/iterativedeepening/IterativeDeepening.java
Normal file → Executable file
0
src/search/uninformed/iterativedeepening/IterativeDeepening.java
Normal file → Executable file
0
test/machine_learning/VectorTest.java
Normal file → Executable file
0
test/machine_learning/VectorTest.java
Normal file → Executable file
13
test/machine_learning/nearest_neighbour/KNearestNeighbourTest.java
Normal file → Executable file
13
test/machine_learning/nearest_neighbour/KNearestNeighbourTest.java
Normal file → Executable file
@ -3,6 +3,7 @@ package machine_learning.nearest_neighbour;
|
|||||||
import machine_learning.DataClass;
|
import machine_learning.DataClass;
|
||||||
import machine_learning.Vector;
|
import machine_learning.Vector;
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
import org.junit.jupiter.api.Disabled;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.TestInstance;
|
import org.junit.jupiter.api.TestInstance;
|
||||||
import org.opentest4j.AssertionFailedError;
|
import org.opentest4j.AssertionFailedError;
|
||||||
@ -22,8 +23,9 @@ import static org.junit.jupiter.api.Assertions.*;
|
|||||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||||
class KNearestNeighbourTest
|
class KNearestNeighbourTest
|
||||||
{
|
{
|
||||||
List<Vector> positives;
|
private List<Vector> positives;
|
||||||
List<Vector> negatives;
|
private List<Vector> negatives;
|
||||||
|
private DistanceFunction distanceFunction;
|
||||||
|
|
||||||
@BeforeAll
|
@BeforeAll
|
||||||
void initLearnData()
|
void initLearnData()
|
||||||
@ -41,12 +43,14 @@ class KNearestNeighbourTest
|
|||||||
new Vector(8d, 2d),
|
new Vector(8d, 2d),
|
||||||
new Vector(9d, 0d))
|
new Vector(9d, 0d))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.distanceFunction = (a, b) -> Math.abs(a.get(0) - b.get(0)) + Math.abs(a.get(1) - b.get(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldReturnCorrectClassForVectorWithKEquals3()
|
public void shouldReturnCorrectClassForVectorWithKEquals3()
|
||||||
{
|
{
|
||||||
var kNearestNeighbour = new KNearestNeighbour((a ,b) -> Math.abs(a.get(0) - b.get(0)) + Math.abs(a.get(1) - b.get(1)), 3);
|
var kNearestNeighbour = new KNearestNeighbour(this.distanceFunction, 3);
|
||||||
kNearestNeighbour.learn(this.positives, this.negatives);
|
kNearestNeighbour.learn(this.positives, this.negatives);
|
||||||
var vector = new Vector(8, 3.5);
|
var vector = new Vector(8, 3.5);
|
||||||
|
|
||||||
@ -59,7 +63,7 @@ class KNearestNeighbourTest
|
|||||||
@Test
|
@Test
|
||||||
public void shouldReturnCorrectClassForVectorWithKEquals5()
|
public void shouldReturnCorrectClassForVectorWithKEquals5()
|
||||||
{
|
{
|
||||||
var kNearestNeighbour = new KNearestNeighbour((a ,b) -> Math.abs(a.get(0) - b.get(0)) + Math.abs(a.get(1) - b.get(1)), 5);
|
var kNearestNeighbour = new KNearestNeighbour(this.distanceFunction, 5);
|
||||||
kNearestNeighbour.learn(this.positives, this.negatives);
|
kNearestNeighbour.learn(this.positives, this.negatives);
|
||||||
var vector = new Vector(8, 3.5);
|
var vector = new Vector(8, 3.5);
|
||||||
|
|
||||||
@ -110,6 +114,7 @@ class KNearestNeighbourTest
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Disabled("Takes long")
|
||||||
@Test
|
@Test
|
||||||
public void shouldReturnOptimum()
|
public void shouldReturnOptimum()
|
||||||
{
|
{
|
||||||
|
12
test/machine_learning/perceptron/PerceptronTest.java
Normal file → Executable file
12
test/machine_learning/perceptron/PerceptronTest.java
Normal file → Executable file
@ -1,16 +1,12 @@
|
|||||||
package machine_learning.perceptron;
|
package machine_learning.perceptron;
|
||||||
|
|
||||||
import machine_learning.Vector;
|
|
||||||
import machine_learning.DataClass;
|
import machine_learning.DataClass;
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
import machine_learning.Vector;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.*;
|
||||||
import org.junit.jupiter.api.TestInstance;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
|
||||||
|
|
||||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||||
class PerceptronTest
|
class PerceptronTest
|
||||||
{
|
{
|
||||||
@ -48,7 +44,7 @@ class PerceptronTest
|
|||||||
var actualClass = this.perceptron.classify(vector);
|
var actualClass = this.perceptron.classify(vector);
|
||||||
var expectedClass = DataClass.NEGATIVE;
|
var expectedClass = DataClass.NEGATIVE;
|
||||||
|
|
||||||
assertEquals(expectedClass, actualClass);
|
Assertions.assertEquals(expectedClass, actualClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -59,6 +55,6 @@ class PerceptronTest
|
|||||||
var actualClass = this.perceptron.classify(vector);
|
var actualClass = this.perceptron.classify(vector);
|
||||||
var expectedClass = DataClass.POSITIVE;
|
var expectedClass = DataClass.POSITIVE;
|
||||||
|
|
||||||
assertEquals(expectedClass, actualClass);
|
Assertions.assertEquals(expectedClass, actualClass);
|
||||||
}
|
}
|
||||||
}
|
}
|
107
test/search/ChessKnightNodeTest.java
Executable file
107
test/search/ChessKnightNodeTest.java
Executable file
@ -0,0 +1,107 @@
|
|||||||
|
package search;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
public class ChessKnightNodeTest
|
||||||
|
{
|
||||||
|
@Test
|
||||||
|
public void shouldReturnTrueWhenTargetReached()
|
||||||
|
{
|
||||||
|
final var state = new ChessKnightNode.KnightPair('a', '1');
|
||||||
|
|
||||||
|
final var node = new ChessKnightNode(state);
|
||||||
|
final var target = new ChessKnightNode(state);
|
||||||
|
|
||||||
|
Assertions.assertTrue(node.isTargetReached(target));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldReturnFalseWhenTargetNotReached()
|
||||||
|
{
|
||||||
|
final var actualState = new ChessKnightNode.KnightPair('a', '1');
|
||||||
|
|
||||||
|
final var targetState = new ChessKnightNode.KnightPair('h', '8');
|
||||||
|
|
||||||
|
final var node = new ChessKnightNode(actualState);
|
||||||
|
final var target = new ChessKnightNode(targetState);
|
||||||
|
|
||||||
|
Assertions.assertFalse(node.isTargetReached(target));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldReturnNonEmptyListOfSuccessors()
|
||||||
|
{
|
||||||
|
final var state = new ChessKnightNode.KnightPair('a', '1');
|
||||||
|
|
||||||
|
final var node = new ChessKnightNode(state);
|
||||||
|
final var successors = node.generateSuccessors();
|
||||||
|
|
||||||
|
Assertions.assertFalse(successors.isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldReturnCorrectSuccessorsWithMaxPossibleSuccessors()
|
||||||
|
{
|
||||||
|
final var state = new ChessKnightNode.KnightPair('f', '3');
|
||||||
|
|
||||||
|
final var node = new ChessKnightNode(state);
|
||||||
|
final var successors = node.generateSuccessors();
|
||||||
|
|
||||||
|
Assertions.assertEquals(8, successors.size());
|
||||||
|
|
||||||
|
final var newState1 = new ChessKnightNode.KnightPair('e', '5');
|
||||||
|
final var newState2 = new ChessKnightNode.KnightPair('g', '5');
|
||||||
|
final var newState3 = new ChessKnightNode.KnightPair('h', '4');
|
||||||
|
final var newState4 = new ChessKnightNode.KnightPair('h', '2');
|
||||||
|
final var newState5 = new ChessKnightNode.KnightPair('g', '1');
|
||||||
|
final var newState6 = new ChessKnightNode.KnightPair('e', '1');
|
||||||
|
final var newState7 = new ChessKnightNode.KnightPair('d', '2');
|
||||||
|
final var newState8 = new ChessKnightNode.KnightPair('d', '4');
|
||||||
|
|
||||||
|
|
||||||
|
Assertions.assertEquals(newState1, successors.get(0).getValue());
|
||||||
|
Assertions.assertEquals(newState2, successors.get(1).getValue());
|
||||||
|
Assertions.assertEquals(newState3, successors.get(2).getValue());
|
||||||
|
Assertions.assertEquals(newState4, successors.get(3).getValue());
|
||||||
|
Assertions.assertEquals(newState5, successors.get(4).getValue());
|
||||||
|
Assertions.assertEquals(newState6, successors.get(5).getValue());
|
||||||
|
Assertions.assertEquals(newState7, successors.get(6).getValue());
|
||||||
|
Assertions.assertEquals(newState8, successors.get(7).getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldReturnCorrectSuccessorsOnEdge()
|
||||||
|
{
|
||||||
|
final var state = new ChessKnightNode.KnightPair('a', '1');
|
||||||
|
|
||||||
|
final var node = new ChessKnightNode(state);
|
||||||
|
final var successors = node.generateSuccessors();
|
||||||
|
|
||||||
|
Assertions.assertEquals(2, successors.size());
|
||||||
|
|
||||||
|
Assertions.assertThrows(ChessKnightNode.ChessKnightException.class,
|
||||||
|
() -> new ChessKnightNode.KnightPair((char) ('a' - 1), '3'));
|
||||||
|
|
||||||
|
final var newState1 = new ChessKnightNode.KnightPair('b', '3');
|
||||||
|
final var newState2 = new ChessKnightNode.KnightPair('c', '2');
|
||||||
|
|
||||||
|
Assertions.assertThrows(ChessKnightNode.ChessKnightException.class,
|
||||||
|
() -> new ChessKnightNode.KnightPair('c', '0'));
|
||||||
|
|
||||||
|
Assertions.assertThrows(ChessKnightNode.ChessKnightException.class,
|
||||||
|
() -> new ChessKnightNode.KnightPair('c', (char) ('0' - 1)));
|
||||||
|
|
||||||
|
Assertions.assertThrows(ChessKnightNode.ChessKnightException.class,
|
||||||
|
() -> new ChessKnightNode.KnightPair((char) ('a' - 1), (char) ('0' - 1)));
|
||||||
|
|
||||||
|
Assertions.assertThrows(ChessKnightNode.ChessKnightException.class,
|
||||||
|
() -> new ChessKnightNode.KnightPair((char) ('a' - 2), '0'));
|
||||||
|
|
||||||
|
Assertions.assertThrows(ChessKnightNode.ChessKnightException.class,
|
||||||
|
() -> new ChessKnightNode.KnightPair((char) ('a' - 2), '3'));
|
||||||
|
|
||||||
|
Assertions.assertEquals(newState1, successors.get(0).getValue());
|
||||||
|
Assertions.assertEquals(newState2, successors.get(1).getValue());
|
||||||
|
}
|
||||||
|
}
|
51
test/search/ChessKnightTest.java
Executable file
51
test/search/ChessKnightTest.java
Executable file
@ -0,0 +1,51 @@
|
|||||||
|
package search;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import search.uninformed.breadthfirstsearch.BreadthFirstSearch;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static search.SearchTestUtils.countNodes;
|
||||||
|
import static search.SearchTestUtils.printSolution;
|
||||||
|
|
||||||
|
public class ChessKnightTest
|
||||||
|
{
|
||||||
|
@Test
|
||||||
|
public void shouldReturnOne()
|
||||||
|
{
|
||||||
|
final var state = new ChessKnightNode.KnightPair('a', '3');
|
||||||
|
|
||||||
|
final var root = new ChessKnightNode(state);
|
||||||
|
|
||||||
|
final var targetState = new ChessKnightNode.KnightPair('b', '5');
|
||||||
|
final var expected = new ChessKnightNode(targetState);
|
||||||
|
|
||||||
|
final var actual = new BreadthFirstSearch().breadthFirstSearch(List.of(root), expected);
|
||||||
|
|
||||||
|
printSolution(actual);
|
||||||
|
var nodeCount = countNodes(actual);
|
||||||
|
var edgeCount = nodeCount - 1;
|
||||||
|
|
||||||
|
Assertions.assertEquals(1, edgeCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldReturnThree()
|
||||||
|
{
|
||||||
|
final var state = new ChessKnightNode.KnightPair('a', '1');
|
||||||
|
|
||||||
|
final var root = new ChessKnightNode(state);
|
||||||
|
|
||||||
|
final var targetState = new ChessKnightNode.KnightPair('f', '1');
|
||||||
|
final var expected = new ChessKnightNode(targetState);
|
||||||
|
|
||||||
|
final var actual = new BreadthFirstSearch().breadthFirstSearch(List.of(root), expected);
|
||||||
|
|
||||||
|
printSolution(actual);
|
||||||
|
var nodeCount = countNodes(actual);
|
||||||
|
var edgeCount = nodeCount - 1;
|
||||||
|
|
||||||
|
Assertions.assertEquals(3, edgeCount);
|
||||||
|
}
|
||||||
|
}
|
0
test/search/EightPuzzleNodeTest.java
Normal file → Executable file
0
test/search/EightPuzzleNodeTest.java
Normal file → Executable file
77
test/search/GameHelperTest.java
Executable file
77
test/search/GameHelperTest.java
Executable file
@ -0,0 +1,77 @@
|
|||||||
|
package search;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import search.uninformed.iterativedeepening.IterativeDeepening;
|
||||||
|
|
||||||
|
import static search.SearchTestUtils.printSolution;
|
||||||
|
|
||||||
|
public class GameHelperTest
|
||||||
|
{
|
||||||
|
@Test
|
||||||
|
void shouldReturnCorrectTargetDemonologist()
|
||||||
|
{
|
||||||
|
final int[][] state = {
|
||||||
|
{8, 4 ,0},
|
||||||
|
{6, 3, 1},
|
||||||
|
{2, 5, 7}
|
||||||
|
};
|
||||||
|
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 IterativeDeepening().iterativeDeepening(root, expected);
|
||||||
|
|
||||||
|
printSolution(actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldReturnCorrectTargetWartales()
|
||||||
|
{
|
||||||
|
final int[][] state = {
|
||||||
|
{1, 8, 6},
|
||||||
|
{3, 2, 7},
|
||||||
|
{5, 4, 0}
|
||||||
|
};
|
||||||
|
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 IterativeDeepening().iterativeDeepening(root, expected);
|
||||||
|
|
||||||
|
printSolution(actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldReturnCorrectTargetLabyrinthine()
|
||||||
|
{
|
||||||
|
final boolean[][] state = {
|
||||||
|
{true, false, true},
|
||||||
|
{false, true, false},
|
||||||
|
{true, false, true}
|
||||||
|
};
|
||||||
|
|
||||||
|
final var root = new LabyrinthineNode(state);
|
||||||
|
|
||||||
|
final boolean[][] targetState = {
|
||||||
|
{true, true, true},
|
||||||
|
{true, true, true},
|
||||||
|
{true, true, true},
|
||||||
|
};
|
||||||
|
|
||||||
|
final var expected = new LabyrinthineNode(targetState);
|
||||||
|
|
||||||
|
final var actual = new IterativeDeepening().iterativeDeepening(root, expected);
|
||||||
|
|
||||||
|
printSolution(actual);
|
||||||
|
}
|
||||||
|
}
|
0
test/search/LabyrinthineNodeTest.java
Normal file → Executable file
0
test/search/LabyrinthineNodeTest.java
Normal file → Executable file
14
test/search/SearchTestUtils.java
Normal file → Executable file
14
test/search/SearchTestUtils.java
Normal file → Executable file
@ -17,4 +17,18 @@ public class SearchTestUtils
|
|||||||
|
|
||||||
System.out.println("START");
|
System.out.println("START");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <T> int countNodes(final Node<T> targetNode)
|
||||||
|
{
|
||||||
|
var node = targetNode;
|
||||||
|
|
||||||
|
int nodeCount = 0;
|
||||||
|
while (node != null)
|
||||||
|
{
|
||||||
|
nodeCount++;
|
||||||
|
node = node.getParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodeCount;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
0
test/search/heuristic/AStarTest.java
Normal file → Executable file
0
test/search/heuristic/AStarTest.java
Normal file → Executable file
0
test/search/uninformed/breadthfirstsearch/BreadthFirstSearchTest.java
Normal file → Executable file
0
test/search/uninformed/breadthfirstsearch/BreadthFirstSearchTest.java
Normal file → Executable file
0
test/search/uninformed/depthfirstsearch/DepthFirstSearchTest.java
Normal file → Executable file
0
test/search/uninformed/depthfirstsearch/DepthFirstSearchTest.java
Normal file → Executable file
24
test/search/uninformed/iterativedeepening/IterativeDeepeningTest.java
Normal file → Executable file
24
test/search/uninformed/iterativedeepening/IterativeDeepeningTest.java
Normal file → Executable file
@ -51,28 +51,4 @@ class IterativeDeepeningTest
|
|||||||
|
|
||||||
printSolution(actual);
|
printSolution(actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldReturnCorrectTargetLabyrinthine()
|
|
||||||
{
|
|
||||||
final boolean[][] state = {
|
|
||||||
{true, false, true},
|
|
||||||
{false, true, false},
|
|
||||||
{true, false, true}
|
|
||||||
};
|
|
||||||
|
|
||||||
final var root = new LabyrinthineNode(state);
|
|
||||||
|
|
||||||
final boolean[][] targetState = {
|
|
||||||
{true, true, true},
|
|
||||||
{true, true, true},
|
|
||||||
{true, true, true},
|
|
||||||
};
|
|
||||||
|
|
||||||
final var expected = new LabyrinthineNode(targetState);
|
|
||||||
|
|
||||||
final var actual = new IterativeDeepening().iterativeDeepening(root, expected);
|
|
||||||
|
|
||||||
printSolution(actual);
|
|
||||||
}
|
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user