Merge branch 'master' into master
This commit is contained in:
@@ -33,3 +33,11 @@ spring-openid/src/main/resources/application.properties
|
||||
spring-security-openid/src/main/resources/application.properties
|
||||
|
||||
spring-all/*.log
|
||||
|
||||
*.jar
|
||||
|
||||
SpringDataInjectionDemo/.mvn/wrapper/maven-wrapper.properties
|
||||
|
||||
spring-call-getters-using-reflection/.mvn/wrapper/maven-wrapper.properties
|
||||
|
||||
spring-check-if-a-property-is-null/.mvn/wrapper/maven-wrapper.properties
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
### Relevant articles
|
||||
|
||||
- [Guide to Akka Streams](http://www.baeldung.com/akka-streams)
|
||||
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>parent-modules</artifactId>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>akka-streams</artifactId>
|
||||
<name>akka-streams</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.typesafe.akka</groupId>
|
||||
<artifactId>akka-stream_2.11</artifactId>
|
||||
<version>${akkastreams.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.typesafe.akka</groupId>
|
||||
<artifactId>akka-stream-testkit_2.11</artifactId>
|
||||
<version>${akkastreams.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<properties>
|
||||
<akkastreams.version>2.5.2</akkastreams.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.baeldung.akkastreams;
|
||||
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
|
||||
public class AverageRepository {
|
||||
CompletionStage<Double> save(Double average) {
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
System.out.println("saving average: " + average);
|
||||
return average;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.baeldung.akkastreams;
|
||||
|
||||
|
||||
import akka.Done;
|
||||
import akka.NotUsed;
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.stream.ActorMaterializer;
|
||||
import akka.stream.javadsl.Flow;
|
||||
import akka.stream.javadsl.Keep;
|
||||
import akka.stream.javadsl.Sink;
|
||||
import akka.stream.javadsl.Source;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class DataImporter {
|
||||
private final ActorSystem actorSystem;
|
||||
private final AverageRepository averageRepository = new AverageRepository();
|
||||
|
||||
public DataImporter(ActorSystem actorSystem) {
|
||||
this.actorSystem = actorSystem;
|
||||
|
||||
}
|
||||
|
||||
private List<Integer> parseLine(String line) {
|
||||
String[] fields = line.split(";");
|
||||
return Arrays.stream(fields)
|
||||
.map(Integer::parseInt)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private Flow<String, Integer, NotUsed> parseContent() {
|
||||
return Flow.of(String.class).mapConcat(this::parseLine);
|
||||
}
|
||||
|
||||
private Flow<Integer, Double, NotUsed> computeAverage() {
|
||||
return Flow.of(Integer.class).grouped(2).mapAsyncUnordered(8, integers ->
|
||||
CompletableFuture.supplyAsync(() -> integers
|
||||
.stream()
|
||||
.mapToDouble(v -> v)
|
||||
.average()
|
||||
.orElse(-1.0)));
|
||||
}
|
||||
|
||||
Flow<String, Double, NotUsed> calculateAverage() {
|
||||
return Flow.of(String.class)
|
||||
.via(parseContent())
|
||||
.via(computeAverage());
|
||||
}
|
||||
|
||||
private Sink<Double, CompletionStage<Done>> storeAverages() {
|
||||
return Flow.of(Double.class)
|
||||
.mapAsyncUnordered(4, averageRepository::save)
|
||||
.toMat(Sink.ignore(), Keep.right());
|
||||
}
|
||||
|
||||
|
||||
CompletionStage<Done> calculateAverageForContent(String content) {
|
||||
return Source.single(content)
|
||||
.via(calculateAverage())
|
||||
.runWith(storeAverages(), ActorMaterializer.create(actorSystem))
|
||||
.whenComplete((d, e) -> {
|
||||
if (d != null) {
|
||||
System.out.println("Import finished ");
|
||||
} else {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.baeldung.akkastreams;
|
||||
|
||||
import akka.NotUsed;
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.stream.ActorMaterializer;
|
||||
import akka.stream.javadsl.Flow;
|
||||
import akka.stream.javadsl.Source;
|
||||
import akka.stream.testkit.javadsl.TestSink;
|
||||
import org.junit.Test;
|
||||
|
||||
|
||||
public class DataImporterUnitTest {
|
||||
private final ActorSystem actorSystem = ActorSystem.create();
|
||||
|
||||
@Test
|
||||
public void givenStreamOfIntegers_whenCalculateAverageOfPairs_thenShouldReturnProperResults() {
|
||||
//given
|
||||
Flow<String, Double, NotUsed> tested = new DataImporter(actorSystem).calculateAverage();
|
||||
String input = "1;9;11;0";
|
||||
|
||||
//when
|
||||
Source<Double, NotUsed> flow = Source.single(input).via(tested);
|
||||
|
||||
//then
|
||||
flow
|
||||
.runWith(TestSink.probe(actorSystem), ActorMaterializer.create(actorSystem))
|
||||
.request(4)
|
||||
.expectNextUnordered(5d, 5.5);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenStreamOfIntegers_whenCalculateAverageAndSaveToSink_thenShouldFinishSuccessfully() {
|
||||
//given
|
||||
DataImporter dataImporter = new DataImporter(actorSystem);
|
||||
String input = "10;90;110;10";
|
||||
|
||||
//when
|
||||
dataImporter.calculateAverageForContent(input)
|
||||
.thenAccept(d -> actorSystem.terminate());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.baeldung.automata;
|
||||
package com.baeldung.algorithms.automata;
|
||||
|
||||
/**
|
||||
* Finite state machine.
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.baeldung.automata;
|
||||
package com.baeldung.algorithms.automata;
|
||||
|
||||
/**
|
||||
* Default implementation of a finite state machine.
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.baeldung.automata;
|
||||
package com.baeldung.algorithms.automata;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.baeldung.automata;
|
||||
package com.baeldung.algorithms.automata;
|
||||
|
||||
|
||||
/**
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.baeldung.automata;
|
||||
package com.baeldung.algorithms.automata;
|
||||
|
||||
/**
|
||||
* State. Part of a finite state machine.
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.baeldung.automata;
|
||||
package com.baeldung.algorithms.automata;
|
||||
|
||||
/**
|
||||
* Transition in a finite State machine.
|
||||
@@ -0,0 +1,189 @@
|
||||
package com.baeldung.algorithms.hillclimbing;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Stack;
|
||||
|
||||
public class HillClimbing {
|
||||
public static void main(String[] args) {
|
||||
HillClimbing hillClimbing = new HillClimbing();
|
||||
String blockArr[] = { "B", "C", "D", "A" };
|
||||
Stack<String> startState = hillClimbing.getStackWithValues(blockArr);
|
||||
String goalBlockArr[] = { "A", "B", "C", "D" };
|
||||
Stack<String> goalState = hillClimbing.getStackWithValues(goalBlockArr);
|
||||
try {
|
||||
List<State> solutionSequence = hillClimbing.getRouteWithHillClimbing(startState, goalState);
|
||||
solutionSequence.forEach(HillClimbing::printEachStep);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static void printEachStep(State state) {
|
||||
List<Stack<String>> stackList = state.getState();
|
||||
System.out.println("----------------");
|
||||
stackList.forEach(stack -> {
|
||||
while (!stack.isEmpty()) {
|
||||
System.out.println(stack.pop());
|
||||
}
|
||||
System.out.println(" ");
|
||||
});
|
||||
}
|
||||
|
||||
private Stack<String> getStackWithValues(String[] blocks) {
|
||||
Stack<String> stack = new Stack<>();
|
||||
for (String block : blocks)
|
||||
stack.push(block);
|
||||
return stack;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method prepares path from init state to goal state
|
||||
*/
|
||||
public List<State> getRouteWithHillClimbing(Stack<String> initStateStack, Stack<String> goalStateStack) throws Exception {
|
||||
List<Stack<String>> initStateStackList = new ArrayList<>();
|
||||
initStateStackList.add(initStateStack);
|
||||
int initStateHeuristics = getHeuristicsValue(initStateStackList, goalStateStack);
|
||||
State initState = new State(initStateStackList, initStateHeuristics);
|
||||
|
||||
List<State> resultPath = new ArrayList<>();
|
||||
resultPath.add(new State(initState));
|
||||
|
||||
State currentState = initState;
|
||||
boolean noStateFound = false;
|
||||
while (!currentState.getState()
|
||||
.get(0)
|
||||
.equals(goalStateStack) || noStateFound) {
|
||||
noStateFound = true;
|
||||
State nextState = findNextState(currentState, goalStateStack);
|
||||
if (nextState != null) {
|
||||
noStateFound = false;
|
||||
currentState = nextState;
|
||||
resultPath.add(new State(nextState));
|
||||
}
|
||||
}
|
||||
|
||||
return resultPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method finds new state from current state based on goal and
|
||||
* heuristics
|
||||
*/
|
||||
public State findNextState(State currentState, Stack<String> goalStateStack) {
|
||||
List<Stack<String>> listOfStacks = currentState.getState();
|
||||
int currentStateHeuristics = currentState.getHeuristics();
|
||||
|
||||
return listOfStacks.stream()
|
||||
.map(stack -> {
|
||||
return applyOperationsOnState(listOfStacks, stack, currentStateHeuristics, goalStateStack);
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method applies operations on the current state to get a new state
|
||||
*/
|
||||
public State applyOperationsOnState(List<Stack<String>> listOfStacks, Stack<String> stack, int currentStateHeuristics, Stack<String> goalStateStack) {
|
||||
State tempState;
|
||||
List<Stack<String>> tempStackList = new ArrayList<>(listOfStacks);
|
||||
String block = stack.pop();
|
||||
if (stack.size() == 0)
|
||||
tempStackList.remove(stack);
|
||||
tempState = pushElementToNewStack(tempStackList, block, currentStateHeuristics, goalStateStack);
|
||||
if (tempState == null) {
|
||||
tempState = pushElementToExistingStacks(stack, tempStackList, block, currentStateHeuristics, goalStateStack);
|
||||
}
|
||||
if (tempState == null)
|
||||
stack.push(block);
|
||||
return tempState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Operation to be applied on a state in order to find new states. This
|
||||
* operation pushes an element into a new stack
|
||||
*/
|
||||
private State pushElementToNewStack(List<Stack<String>> currentStackList, String block, int currentStateHeuristics, Stack<String> goalStateStack) {
|
||||
State newState = null;
|
||||
Stack<String> newStack = new Stack<>();
|
||||
newStack.push(block);
|
||||
|
||||
currentStackList.add(newStack);
|
||||
int newStateHeuristics = getHeuristicsValue(currentStackList, goalStateStack);
|
||||
if (newStateHeuristics > currentStateHeuristics) {
|
||||
newState = new State(currentStackList, newStateHeuristics);
|
||||
} else {
|
||||
currentStackList.remove(newStack);
|
||||
}
|
||||
return newState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Operation to be applied on a state in order to find new states. This
|
||||
* operation pushes an element into one of the other stacks to explore new
|
||||
* states
|
||||
*/
|
||||
private State pushElementToExistingStacks(Stack currentStack, List<Stack<String>> currentStackList, String block, int currentStateHeuristics, Stack<String> goalStateStack) {
|
||||
|
||||
Optional<State> newState = currentStackList.stream()
|
||||
.filter(stack -> stack != currentStack)
|
||||
.map(stack -> {
|
||||
return pushElementToStack(stack, block, currentStackList, currentStateHeuristics, goalStateStack);
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.findFirst();
|
||||
|
||||
return newState.orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method pushes a block to the stack and returns new state if its closer to goal
|
||||
*/
|
||||
private State pushElementToStack(Stack stack, String block, List<Stack<String>> currentStackList, int currentStateHeuristics, Stack<String> goalStateStack) {
|
||||
stack.push(block);
|
||||
int newStateHeuristics = getHeuristicsValue(currentStackList, goalStateStack);
|
||||
if (newStateHeuristics > currentStateHeuristics) {
|
||||
return new State(currentStackList, newStateHeuristics);
|
||||
}
|
||||
stack.pop();
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns heuristics value for given state with respect to goal
|
||||
* state
|
||||
*/
|
||||
public int getHeuristicsValue(List<Stack<String>> currentState, Stack<String> goalStateStack) {
|
||||
Integer heuristicValue;
|
||||
heuristicValue = currentState.stream()
|
||||
.mapToInt(stack -> {
|
||||
return getHeuristicsValueForStack(stack, currentState, goalStateStack);
|
||||
})
|
||||
.sum();
|
||||
return heuristicValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns heuristics value for a particular stack
|
||||
*/
|
||||
public int getHeuristicsValueForStack(Stack<String> stack, List<Stack<String>> currentState, Stack<String> goalStateStack) {
|
||||
int stackHeuristics = 0;
|
||||
boolean isPositioneCorrect = true;
|
||||
int goalStartIndex = 0;
|
||||
for (String currentBlock : stack) {
|
||||
if (isPositioneCorrect && currentBlock.equals(goalStateStack.get(goalStartIndex))) {
|
||||
stackHeuristics += goalStartIndex;
|
||||
} else {
|
||||
stackHeuristics -= goalStartIndex;
|
||||
isPositioneCorrect = false;
|
||||
}
|
||||
goalStartIndex++;
|
||||
}
|
||||
return stackHeuristics;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.baeldung.algorithms.hillclimbing;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
public class State {
|
||||
private List<Stack<String>> state;
|
||||
private int heuristics;
|
||||
|
||||
public State(List<Stack<String>> state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
State(List<Stack<String>> state, int heuristics) {
|
||||
this.state = state;
|
||||
this.heuristics = heuristics;
|
||||
}
|
||||
|
||||
State(State state) {
|
||||
if (state != null) {
|
||||
this.state = new ArrayList<>();
|
||||
for (Stack s : state.getState()) {
|
||||
Stack s1;
|
||||
s1 = (Stack) s.clone();
|
||||
this.state.add(s1);
|
||||
}
|
||||
this.heuristics = state.getHeuristics();
|
||||
}
|
||||
}
|
||||
|
||||
public List<Stack<String>> getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public int getHeuristics() {
|
||||
return heuristics;
|
||||
}
|
||||
|
||||
public void setHeuristics(int heuristics) {
|
||||
this.heuristics = heuristics;
|
||||
}
|
||||
}
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
package com.baeldung.algorithms.mcts.montecarlo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.baeldung.algorithms.mcts.tictactoe.Board;
|
||||
import com.baeldung.algorithms.mcts.tree.Node;
|
||||
import com.baeldung.algorithms.mcts.tree.Tree;
|
||||
|
||||
public class MonteCarloTreeSearch {
|
||||
|
||||
private static final int WIN_SCORE = 10;
|
||||
private int level;
|
||||
private int oponent;
|
||||
|
||||
public MonteCarloTreeSearch() {
|
||||
this.level = 3;
|
||||
}
|
||||
|
||||
public int getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public void setLevel(int level) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
private int getMillisForCurrentLevel() {
|
||||
return 2 * (this.level - 1) + 1;
|
||||
}
|
||||
|
||||
public Board findNextMove(Board board, int playerNo) {
|
||||
long start = System.currentTimeMillis();
|
||||
long end = start + 60 * getMillisForCurrentLevel();
|
||||
|
||||
oponent = 3 - playerNo;
|
||||
Tree tree = new Tree();
|
||||
Node rootNode = tree.getRoot();
|
||||
rootNode.getState().setBoard(board);
|
||||
rootNode.getState().setPlayerNo(oponent);
|
||||
|
||||
while (System.currentTimeMillis() < end) {
|
||||
// Phase 1 - Selection
|
||||
Node promisingNode = selectPromisingNode(rootNode);
|
||||
// Phase 2 - Expansion
|
||||
if (promisingNode.getState().getBoard().checkStatus() == Board.IN_PROGRESS)
|
||||
expandNode(promisingNode);
|
||||
|
||||
// Phase 3 - Simulation
|
||||
Node nodeToExplore = promisingNode;
|
||||
if (promisingNode.getChildArray().size() > 0) {
|
||||
nodeToExplore = promisingNode.getRandomChildNode();
|
||||
}
|
||||
int playoutResult = simulateRandomPlayout(nodeToExplore);
|
||||
// Phase 4 - Update
|
||||
backPropogation(nodeToExplore, playoutResult);
|
||||
}
|
||||
|
||||
Node winnerNode = rootNode.getChildWithMaxScore();
|
||||
tree.setRoot(winnerNode);
|
||||
return winnerNode.getState().getBoard();
|
||||
}
|
||||
|
||||
private Node selectPromisingNode(Node rootNode) {
|
||||
Node node = rootNode;
|
||||
while (node.getChildArray().size() != 0) {
|
||||
node = UCT.findBestNodeWithUCT(node);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
private void expandNode(Node node) {
|
||||
List<State> possibleStates = node.getState().getAllPossibleStates();
|
||||
possibleStates.forEach(state -> {
|
||||
Node newNode = new Node(state);
|
||||
newNode.setParent(node);
|
||||
newNode.getState().setPlayerNo(node.getState().getOpponent());
|
||||
node.getChildArray().add(newNode);
|
||||
});
|
||||
}
|
||||
|
||||
private void backPropogation(Node nodeToExplore, int playerNo) {
|
||||
Node tempNode = nodeToExplore;
|
||||
while (tempNode != null) {
|
||||
tempNode.getState().incrementVisit();
|
||||
if (tempNode.getState().getPlayerNo() == playerNo)
|
||||
tempNode.getState().addScore(WIN_SCORE);
|
||||
tempNode = tempNode.getParent();
|
||||
}
|
||||
}
|
||||
|
||||
private int simulateRandomPlayout(Node node) {
|
||||
Node tempNode = new Node(node);
|
||||
State tempState = tempNode.getState();
|
||||
int boardStatus = tempState.getBoard().checkStatus();
|
||||
|
||||
if (boardStatus == oponent) {
|
||||
tempNode.getParent().getState().setWinScore(Integer.MIN_VALUE);
|
||||
return boardStatus;
|
||||
}
|
||||
while (boardStatus == Board.IN_PROGRESS) {
|
||||
tempState.togglePlayer();
|
||||
tempState.randomPlay();
|
||||
boardStatus = tempState.getBoard().checkStatus();
|
||||
}
|
||||
|
||||
return boardStatus;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package com.baeldung.algorithms.mcts.montecarlo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.baeldung.algorithms.mcts.tictactoe.Board;
|
||||
import com.baeldung.algorithms.mcts.tictactoe.Position;
|
||||
|
||||
public class State {
|
||||
private Board board;
|
||||
private int playerNo;
|
||||
private int visitCount;
|
||||
private double winScore;
|
||||
|
||||
public State() {
|
||||
board = new Board();
|
||||
}
|
||||
|
||||
public State(State state) {
|
||||
this.board = new Board(state.getBoard());
|
||||
this.playerNo = state.getPlayerNo();
|
||||
this.visitCount = state.getVisitCount();
|
||||
this.winScore = state.getWinScore();
|
||||
}
|
||||
|
||||
public State(Board board) {
|
||||
this.board = new Board(board);
|
||||
}
|
||||
|
||||
Board getBoard() {
|
||||
return board;
|
||||
}
|
||||
|
||||
void setBoard(Board board) {
|
||||
this.board = board;
|
||||
}
|
||||
|
||||
int getPlayerNo() {
|
||||
return playerNo;
|
||||
}
|
||||
|
||||
void setPlayerNo(int playerNo) {
|
||||
this.playerNo = playerNo;
|
||||
}
|
||||
|
||||
int getOpponent() {
|
||||
return 3 - playerNo;
|
||||
}
|
||||
|
||||
public int getVisitCount() {
|
||||
return visitCount;
|
||||
}
|
||||
|
||||
public void setVisitCount(int visitCount) {
|
||||
this.visitCount = visitCount;
|
||||
}
|
||||
|
||||
double getWinScore() {
|
||||
return winScore;
|
||||
}
|
||||
|
||||
void setWinScore(double winScore) {
|
||||
this.winScore = winScore;
|
||||
}
|
||||
|
||||
public List<State> getAllPossibleStates() {
|
||||
List<State> possibleStates = new ArrayList<>();
|
||||
List<Position> availablePositions = this.board.getEmptyPositions();
|
||||
availablePositions.forEach(p -> {
|
||||
State newState = new State(this.board);
|
||||
newState.setPlayerNo(3 - this.playerNo);
|
||||
newState.getBoard().performMove(newState.getPlayerNo(), p);
|
||||
possibleStates.add(newState);
|
||||
});
|
||||
return possibleStates;
|
||||
}
|
||||
|
||||
void incrementVisit() {
|
||||
this.visitCount++;
|
||||
}
|
||||
|
||||
void addScore(double score) {
|
||||
if (this.winScore != Integer.MIN_VALUE)
|
||||
this.winScore += score;
|
||||
}
|
||||
|
||||
void randomPlay() {
|
||||
List<Position> availablePositions = this.board.getEmptyPositions();
|
||||
int totalPossibilities = availablePositions.size();
|
||||
int selectRandom = (int) (Math.random() * ((totalPossibilities - 1) + 1));
|
||||
this.board.performMove(this.playerNo, availablePositions.get(selectRandom));
|
||||
}
|
||||
|
||||
void togglePlayer() {
|
||||
this.playerNo = 3 - this.playerNo;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.baeldung.algorithms.mcts.montecarlo;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import com.baeldung.algorithms.mcts.tree.Node;
|
||||
|
||||
public class UCT {
|
||||
|
||||
public static double uctValue(int totalVisit, double nodeWinScore, int nodeVisit) {
|
||||
if (nodeVisit == 0) {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
return (nodeWinScore / (double) nodeVisit) + 1.41 * Math.sqrt(Math.log(totalVisit) / (double) nodeVisit);
|
||||
}
|
||||
|
||||
static Node findBestNodeWithUCT(Node node) {
|
||||
int parentVisit = node.getState().getVisitCount();
|
||||
return Collections.max(
|
||||
node.getChildArray(),
|
||||
Comparator.comparing(c -> uctValue(parentVisit, c.getState().getWinScore(), c.getState().getVisitCount())));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
package com.baeldung.algorithms.mcts.tictactoe;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class Board {
|
||||
int[][] boardValues;
|
||||
int totalMoves;
|
||||
|
||||
public static final int DEFAULT_BOARD_SIZE = 3;
|
||||
|
||||
public static final int IN_PROGRESS = -1;
|
||||
public static final int DRAW = 0;
|
||||
public static final int P1 = 1;
|
||||
public static final int P2 = 2;
|
||||
|
||||
public Board() {
|
||||
boardValues = new int[DEFAULT_BOARD_SIZE][DEFAULT_BOARD_SIZE];
|
||||
}
|
||||
|
||||
public Board(int boardSize) {
|
||||
boardValues = new int[boardSize][boardSize];
|
||||
}
|
||||
|
||||
public Board(int[][] boardValues) {
|
||||
this.boardValues = boardValues;
|
||||
}
|
||||
|
||||
public Board(int[][] boardValues, int totalMoves) {
|
||||
this.boardValues = boardValues;
|
||||
this.totalMoves = totalMoves;
|
||||
}
|
||||
|
||||
public Board(Board board) {
|
||||
int boardLength = board.getBoardValues().length;
|
||||
this.boardValues = new int[boardLength][boardLength];
|
||||
int[][] boardValues = board.getBoardValues();
|
||||
int n = boardValues.length;
|
||||
for (int i = 0; i < n; i++) {
|
||||
int m = boardValues[i].length;
|
||||
for (int j = 0; j < m; j++) {
|
||||
this.boardValues[i][j] = boardValues[i][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void performMove(int player, Position p) {
|
||||
this.totalMoves++;
|
||||
boardValues[p.getX()][p.getY()] = player;
|
||||
}
|
||||
|
||||
public int[][] getBoardValues() {
|
||||
return boardValues;
|
||||
}
|
||||
|
||||
public void setBoardValues(int[][] boardValues) {
|
||||
this.boardValues = boardValues;
|
||||
}
|
||||
|
||||
public int checkStatus() {
|
||||
int boardSize = boardValues.length;
|
||||
int maxIndex = boardSize - 1;
|
||||
int[] diag1 = new int[boardSize];
|
||||
int[] diag2 = new int[boardSize];
|
||||
|
||||
for (int i = 0; i < boardSize; i++) {
|
||||
int[] row = boardValues[i];
|
||||
int[] col = new int[boardSize];
|
||||
for (int j = 0; j < boardSize; j++) {
|
||||
col[j] = boardValues[j][i];
|
||||
}
|
||||
|
||||
int checkRowForWin = checkForWin(row);
|
||||
if(checkRowForWin!=0)
|
||||
return checkRowForWin;
|
||||
|
||||
int checkColForWin = checkForWin(col);
|
||||
if(checkColForWin!=0)
|
||||
return checkColForWin;
|
||||
|
||||
diag1[i] = boardValues[i][i];
|
||||
diag2[i] = boardValues[maxIndex - i][i];
|
||||
}
|
||||
|
||||
int checkDia1gForWin = checkForWin(diag1);
|
||||
if(checkDia1gForWin!=0)
|
||||
return checkDia1gForWin;
|
||||
|
||||
int checkDiag2ForWin = checkForWin(diag2);
|
||||
if(checkDiag2ForWin!=0)
|
||||
return checkDiag2ForWin;
|
||||
|
||||
if (getEmptyPositions().size() > 0)
|
||||
return IN_PROGRESS;
|
||||
else
|
||||
return DRAW;
|
||||
}
|
||||
|
||||
private int checkForWin(int[] row) {
|
||||
boolean isEqual = true;
|
||||
int size = row.length;
|
||||
int previous = row[0];
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (previous != row[i]) {
|
||||
isEqual = false;
|
||||
break;
|
||||
}
|
||||
previous = row[i];
|
||||
}
|
||||
if(isEqual)
|
||||
return previous;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void printBoard() {
|
||||
int size = this.boardValues.length;
|
||||
for (int i = 0; i < size; i++) {
|
||||
for (int j = 0; j < size; j++) {
|
||||
System.out.print(boardValues[i][j] + " ");
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
|
||||
public List<Position> getEmptyPositions() {
|
||||
int size = this.boardValues.length;
|
||||
List<Position> emptyPositions = new ArrayList<>();
|
||||
for (int i = 0; i < size; i++) {
|
||||
for (int j = 0; j < size; j++) {
|
||||
if (boardValues[i][j] == 0)
|
||||
emptyPositions.add(new Position(i, j));
|
||||
}
|
||||
}
|
||||
return emptyPositions;
|
||||
}
|
||||
|
||||
public void printStatus() {
|
||||
switch (this.checkStatus()) {
|
||||
case P1:
|
||||
System.out.println("Player 1 wins");
|
||||
break;
|
||||
case P2:
|
||||
System.out.println("Player 2 wins");
|
||||
break;
|
||||
case DRAW:
|
||||
System.out.println("Game Draw");
|
||||
break;
|
||||
case IN_PROGRESS:
|
||||
System.out.println("Game In rogress");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.baeldung.algorithms.mcts.tictactoe;
|
||||
|
||||
public class Position {
|
||||
int x;
|
||||
int y;
|
||||
|
||||
public Position() {
|
||||
}
|
||||
|
||||
public Position(int x, int y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public void setX(int x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
public int getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public void setY(int y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package com.baeldung.algorithms.mcts.tree;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import com.baeldung.algorithms.mcts.montecarlo.State;
|
||||
|
||||
public class Node {
|
||||
State state;
|
||||
Node parent;
|
||||
List<Node> childArray;
|
||||
|
||||
public Node() {
|
||||
this.state = new State();
|
||||
childArray = new ArrayList<>();
|
||||
}
|
||||
|
||||
public Node(State state) {
|
||||
this.state = state;
|
||||
childArray = new ArrayList<>();
|
||||
}
|
||||
|
||||
public Node(State state, Node parent, List<Node> childArray) {
|
||||
this.state = state;
|
||||
this.parent = parent;
|
||||
this.childArray = childArray;
|
||||
}
|
||||
|
||||
public Node(Node node) {
|
||||
this.childArray = new ArrayList<>();
|
||||
this.state = new State(node.getState());
|
||||
if (node.getParent() != null)
|
||||
this.parent = node.getParent();
|
||||
List<Node> childArray = node.getChildArray();
|
||||
for (Node child : childArray) {
|
||||
this.childArray.add(new Node(child));
|
||||
}
|
||||
}
|
||||
|
||||
public State getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(State state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public Node getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
public void setParent(Node parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public List<Node> getChildArray() {
|
||||
return childArray;
|
||||
}
|
||||
|
||||
public void setChildArray(List<Node> childArray) {
|
||||
this.childArray = childArray;
|
||||
}
|
||||
|
||||
public Node getRandomChildNode() {
|
||||
int noOfPossibleMoves = this.childArray.size();
|
||||
int selectRandom = (int) (Math.random() * ((noOfPossibleMoves - 1) + 1));
|
||||
return this.childArray.get(selectRandom);
|
||||
}
|
||||
|
||||
public Node getChildWithMaxScore() {
|
||||
return Collections.max(this.childArray, Comparator.comparing(c -> {
|
||||
return c.getState().getVisitCount();
|
||||
}));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.baeldung.algorithms.mcts.tree;
|
||||
|
||||
public class Tree {
|
||||
Node root;
|
||||
|
||||
public Tree() {
|
||||
root = new Node();
|
||||
}
|
||||
|
||||
public Tree(Node root) {
|
||||
this.root = root;
|
||||
}
|
||||
|
||||
public Node getRoot() {
|
||||
return root;
|
||||
}
|
||||
|
||||
public void setRoot(Node root) {
|
||||
this.root = root;
|
||||
}
|
||||
|
||||
public void addChild(Node parent, Node child) {
|
||||
parent.getChildArray().add(child);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.baeldung.algorithms.minimax;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
class GameOfBones {
|
||||
static List<Integer> getPossibleStates(int noOfBonesInHeap) {
|
||||
return IntStream.rangeClosed(1, 3).boxed()
|
||||
.map(i -> noOfBonesInHeap - i)
|
||||
.filter(newHeapCount -> newHeapCount >= 0)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.baeldung.algorithms.minimax;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
public class MiniMax {
|
||||
private Tree tree;
|
||||
|
||||
public Tree getTree() {
|
||||
return tree;
|
||||
}
|
||||
|
||||
public void constructTree(int noOfBones) {
|
||||
tree = new Tree();
|
||||
Node root = new Node(noOfBones, true);
|
||||
tree.setRoot(root);
|
||||
constructTree(root);
|
||||
}
|
||||
|
||||
private void constructTree(Node node) {
|
||||
List<Integer> listofPossibleHeaps = GameOfBones.getPossibleStates(node.getNoOfBones());
|
||||
boolean isMaxPlayer = !node.isMaxPlayer();
|
||||
listofPossibleHeaps.forEach(n -> {
|
||||
Node newNode = new Node(n, isMaxPlayer);
|
||||
node.addChild(newNode);
|
||||
if (newNode.getNoOfBones() > 0) {
|
||||
constructTree(newNode);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public boolean checkWin() {
|
||||
Node root = tree.getRoot();
|
||||
checkWin(root);
|
||||
return root.getScore() == 1;
|
||||
}
|
||||
|
||||
private void checkWin(Node node) {
|
||||
List<Node> children = node.getChildren();
|
||||
boolean isMaxPlayer = node.isMaxPlayer();
|
||||
children.forEach(child -> {
|
||||
if (child.getNoOfBones() == 0) {
|
||||
child.setScore(isMaxPlayer ? 1 : -1);
|
||||
} else {
|
||||
checkWin(child);
|
||||
}
|
||||
});
|
||||
Node bestChild = findBestChild(isMaxPlayer, children);
|
||||
node.setScore(bestChild.getScore());
|
||||
}
|
||||
|
||||
private Node findBestChild(boolean isMaxPlayer, List<Node> children) {
|
||||
Comparator<Node> byScoreComparator = Comparator.comparing(Node::getScore);
|
||||
|
||||
return children.stream()
|
||||
.max(isMaxPlayer ? byScoreComparator : byScoreComparator.reversed())
|
||||
.orElseThrow(NoSuchElementException::new);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.baeldung.algorithms.minimax;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Node {
|
||||
private int noOfBones;
|
||||
private boolean isMaxPlayer;
|
||||
private int score;
|
||||
private List<Node> children;
|
||||
|
||||
public Node(int noOfBones, boolean isMaxPlayer) {
|
||||
this.noOfBones = noOfBones;
|
||||
this.isMaxPlayer = isMaxPlayer;
|
||||
children = new ArrayList<>();
|
||||
}
|
||||
|
||||
int getNoOfBones() {
|
||||
return noOfBones;
|
||||
}
|
||||
|
||||
boolean isMaxPlayer() {
|
||||
return isMaxPlayer;
|
||||
}
|
||||
|
||||
int getScore() {
|
||||
return score;
|
||||
}
|
||||
|
||||
void setScore(int score) {
|
||||
this.score = score;
|
||||
}
|
||||
|
||||
List<Node> getChildren() {
|
||||
return children;
|
||||
}
|
||||
|
||||
void addChild(Node newNode) {
|
||||
children.add(newNode);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.baeldung.algorithms.minimax;
|
||||
|
||||
public class Tree {
|
||||
private Node root;
|
||||
|
||||
Tree() {
|
||||
}
|
||||
|
||||
Node getRoot() {
|
||||
return root;
|
||||
}
|
||||
|
||||
void setRoot(Node root) {
|
||||
this.root = root;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package algorithms;
|
||||
|
||||
import com.baeldung.algorithms.hillclimbing.HillClimbing;
|
||||
import com.baeldung.algorithms.hillclimbing.State;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class HillClimbingAlgorithmTest {
|
||||
private Stack<String> initStack;
|
||||
private Stack<String> goalStack;
|
||||
|
||||
@Before
|
||||
public void initStacks() {
|
||||
String blockArr[] = { "B", "C", "D", "A" };
|
||||
String goalBlockArr[] = { "A", "B", "C", "D" };
|
||||
initStack = new Stack<>();
|
||||
for (String block : blockArr)
|
||||
initStack.push(block);
|
||||
goalStack = new Stack<>();
|
||||
for (String block : goalBlockArr)
|
||||
goalStack.push(block);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenInitAndGoalState_whenGetPathWithHillClimbing_thenPathFound() {
|
||||
HillClimbing hillClimbing = new HillClimbing();
|
||||
|
||||
List<State> path;
|
||||
try {
|
||||
path = hillClimbing.getRouteWithHillClimbing(initStack, goalStack);
|
||||
assertNotNull(path);
|
||||
assertEquals(path.get(path.size() - 1)
|
||||
.getState()
|
||||
.get(0), goalStack);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenCurrentState_whenFindNextState_thenBetterHeuristics() {
|
||||
HillClimbing hillClimbing = new HillClimbing();
|
||||
List<Stack<String>> initList = new ArrayList<>();
|
||||
initList.add(initStack);
|
||||
State currentState = new State(initList);
|
||||
currentState.setHeuristics(hillClimbing.getHeuristicsValue(initList, goalStack));
|
||||
State nextState = hillClimbing.findNextState(currentState, goalStack);
|
||||
assertTrue(nextState.getHeuristics() > currentState.getHeuristics());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package algorithms;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.baeldung.algorithms.mcts.montecarlo.MonteCarloTreeSearch;
|
||||
import com.baeldung.algorithms.mcts.montecarlo.State;
|
||||
import com.baeldung.algorithms.mcts.montecarlo.UCT;
|
||||
import com.baeldung.algorithms.mcts.tictactoe.Board;
|
||||
import com.baeldung.algorithms.mcts.tictactoe.Position;
|
||||
import com.baeldung.algorithms.mcts.tree.Tree;
|
||||
|
||||
public class MCTSTest {
|
||||
Tree gameTree;
|
||||
MonteCarloTreeSearch mcts;
|
||||
|
||||
@Before
|
||||
public void initGameTree() {
|
||||
gameTree = new Tree();
|
||||
mcts = new MonteCarloTreeSearch();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenStats_whenGetUCTForNode_thenUCTMatchesWithManualData() {
|
||||
double uctValue = 15.79;
|
||||
assertEquals(UCT.uctValue(600, 300, 20), uctValue, 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void giveninitBoardState_whenGetAllPossibleStates_thenNonEmptyList() {
|
||||
State initState = gameTree.getRoot().getState();
|
||||
List<State> possibleStates = initState.getAllPossibleStates();
|
||||
assertTrue(possibleStates.size() > 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenEmptyBoard_whenPerformMove_thenLessAvailablePossitions() {
|
||||
Board board = new Board();
|
||||
int initAvailablePositions = board.getEmptyPositions().size();
|
||||
board.performMove(Board.P1, new Position(1, 1));
|
||||
int availablePositions = board.getEmptyPositions().size();
|
||||
assertTrue(initAvailablePositions > availablePositions);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenEmptyBoard_whenSimulateInterAIPlay_thenGameDraw() {
|
||||
Board board = new Board();
|
||||
|
||||
int player = Board.P1;
|
||||
int totalMoves = Board.DEFAULT_BOARD_SIZE * Board.DEFAULT_BOARD_SIZE;
|
||||
for (int i = 0; i < totalMoves; i++) {
|
||||
board = mcts.findNextMove(board, player);
|
||||
if (board.checkStatus() != -1) {
|
||||
break;
|
||||
}
|
||||
player = 3 - player;
|
||||
}
|
||||
int winStatus = board.checkStatus();
|
||||
assertEquals(winStatus, Board.DRAW);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenEmptyBoard_whenLevel1VsLevel3_thenLevel3WinsOrDraw() {
|
||||
Board board = new Board();
|
||||
MonteCarloTreeSearch mcts1 = new MonteCarloTreeSearch();
|
||||
mcts1.setLevel(1);
|
||||
MonteCarloTreeSearch mcts3 = new MonteCarloTreeSearch();
|
||||
mcts3.setLevel(3);
|
||||
|
||||
int player = Board.P1;
|
||||
int totalMoves = Board.DEFAULT_BOARD_SIZE * Board.DEFAULT_BOARD_SIZE;
|
||||
for (int i = 0; i < totalMoves; i++) {
|
||||
if (player == Board.P1)
|
||||
board = mcts3.findNextMove(board, player);
|
||||
else
|
||||
board = mcts1.findNextMove(board, player);
|
||||
|
||||
if (board.checkStatus() != -1) {
|
||||
break;
|
||||
}
|
||||
player = 3 - player;
|
||||
}
|
||||
int winStatus = board.checkStatus();
|
||||
assertTrue(winStatus == Board.DRAW || winStatus == Board.P1);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package algorithms;
|
||||
|
||||
import com.baeldung.automata.*;
|
||||
import com.baeldung.algorithms.automata.*;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
package algorithms.mcts;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.baeldung.algorithms.mcts.montecarlo.MonteCarloTreeSearch;
|
||||
import com.baeldung.algorithms.mcts.montecarlo.State;
|
||||
import com.baeldung.algorithms.mcts.montecarlo.UCT;
|
||||
import com.baeldung.algorithms.mcts.tictactoe.Board;
|
||||
import com.baeldung.algorithms.mcts.tictactoe.Position;
|
||||
import com.baeldung.algorithms.mcts.tree.Tree;
|
||||
|
||||
public class MCTSTest {
|
||||
private Tree gameTree;
|
||||
private MonteCarloTreeSearch mcts;
|
||||
|
||||
@Before
|
||||
public void initGameTree() {
|
||||
gameTree = new Tree();
|
||||
mcts = new MonteCarloTreeSearch();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenStats_whenGetUCTForNode_thenUCTMatchesWithManualData() {
|
||||
double uctValue = 15.79;
|
||||
assertEquals(UCT.uctValue(600, 300, 20), uctValue, 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void giveninitBoardState_whenGetAllPossibleStates_thenNonEmptyList() {
|
||||
State initState = gameTree.getRoot().getState();
|
||||
List<State> possibleStates = initState.getAllPossibleStates();
|
||||
assertTrue(possibleStates.size() > 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenEmptyBoard_whenPerformMove_thenLessAvailablePossitions() {
|
||||
Board board = new Board();
|
||||
int initAvailablePositions = board.getEmptyPositions().size();
|
||||
board.performMove(Board.P1, new Position(1, 1));
|
||||
int availablePositions = board.getEmptyPositions().size();
|
||||
assertTrue(initAvailablePositions > availablePositions);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenEmptyBoard_whenSimulateInterAIPlay_thenGameDraw() {
|
||||
Board board = new Board();
|
||||
|
||||
int player = Board.P1;
|
||||
int totalMoves = Board.DEFAULT_BOARD_SIZE * Board.DEFAULT_BOARD_SIZE;
|
||||
for (int i = 0; i < totalMoves; i++) {
|
||||
board = mcts.findNextMove(board, player);
|
||||
if (board.checkStatus() != -1) {
|
||||
break;
|
||||
}
|
||||
player = 3 - player;
|
||||
}
|
||||
int winStatus = board.checkStatus();
|
||||
assertEquals(winStatus, Board.DRAW);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenEmptyBoard_whenLevel1VsLevel3_thenLevel3WinsOrDraw() {
|
||||
Board board = new Board();
|
||||
MonteCarloTreeSearch mcts1 = new MonteCarloTreeSearch();
|
||||
mcts1.setLevel(1);
|
||||
MonteCarloTreeSearch mcts3 = new MonteCarloTreeSearch();
|
||||
mcts3.setLevel(3);
|
||||
|
||||
int player = Board.P1;
|
||||
int totalMoves = Board.DEFAULT_BOARD_SIZE * Board.DEFAULT_BOARD_SIZE;
|
||||
for (int i = 0; i < totalMoves; i++) {
|
||||
if (player == Board.P1)
|
||||
board = mcts3.findNextMove(board, player);
|
||||
else
|
||||
board = mcts1.findNextMove(board, player);
|
||||
|
||||
if (board.checkStatus() != -1) {
|
||||
break;
|
||||
}
|
||||
player = 3 - player;
|
||||
}
|
||||
int winStatus = board.checkStatus();
|
||||
assertTrue(winStatus == Board.DRAW || winStatus == Board.P1);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package algorithms.minimax;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import com.baeldung.algorithms.minimax.MiniMax;
|
||||
import com.baeldung.algorithms.minimax.Tree;
|
||||
|
||||
public class MinimaxTest {
|
||||
private Tree gameTree;
|
||||
private MiniMax miniMax;
|
||||
|
||||
@Before
|
||||
public void initMiniMaxUtility() {
|
||||
miniMax = new MiniMax();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenMiniMax_whenConstructTree_thenNotNullTree() {
|
||||
assertNull(gameTree);
|
||||
miniMax.constructTree(6);
|
||||
gameTree = miniMax.getTree();
|
||||
assertNotNull(gameTree);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenMiniMax_whenCheckWin_thenComputeOptimal() {
|
||||
miniMax.constructTree(6);
|
||||
boolean result = miniMax.checkWin();
|
||||
assertTrue(result);
|
||||
miniMax.constructTree(8);
|
||||
result = miniMax.checkWin();
|
||||
assertFalse(result);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user