Merge branch 'master' into master
This commit is contained in:
+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.
|
||||
@@ -5,7 +5,6 @@ import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Stack;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class HillClimbing {
|
||||
public static void main(String[] args) {
|
||||
@@ -22,7 +21,7 @@ public class HillClimbing {
|
||||
}
|
||||
}
|
||||
|
||||
public static void printEachStep(State state) {
|
||||
private static void printEachStep(State state) {
|
||||
List<Stack<String>> stackList = state.getState();
|
||||
System.out.println("----------------");
|
||||
stackList.forEach(stack -> {
|
||||
@@ -33,8 +32,8 @@ public class HillClimbing {
|
||||
});
|
||||
}
|
||||
|
||||
public Stack<String> getStackWithValues(String[] blocks) {
|
||||
Stack<String> stack = new Stack<String>();
|
||||
private Stack<String> getStackWithValues(String[] blocks) {
|
||||
Stack<String> stack = new Stack<>();
|
||||
for (String block : blocks)
|
||||
stack.push(block);
|
||||
return stack;
|
||||
@@ -42,14 +41,9 @@ public class HillClimbing {
|
||||
|
||||
/**
|
||||
* This method prepares path from init state to goal state
|
||||
*
|
||||
* @param initStateStack
|
||||
* @param goalStateStack
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public List<State> getRouteWithHillClimbing(Stack<String> initStateStack, Stack<String> goalStateStack) throws Exception {
|
||||
List<Stack<String>> initStateStackList = new ArrayList<Stack<String>>();
|
||||
List<Stack<String>> initStateStackList = new ArrayList<>();
|
||||
initStateStackList.add(initStateStack);
|
||||
int initStateHeuristics = getHeuristicsValue(initStateStackList, goalStateStack);
|
||||
State initState = new State(initStateStackList, initStateHeuristics);
|
||||
@@ -71,57 +65,51 @@ public class HillClimbing {
|
||||
}
|
||||
}
|
||||
|
||||
if (noStateFound)
|
||||
throw new Exception("No path found");
|
||||
return resultPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method finds new state from current state based on goal and
|
||||
* heuristics
|
||||
*
|
||||
* @param currentState
|
||||
* @param goalStateStack
|
||||
* @return a next state
|
||||
*/
|
||||
public State findNextState(State currentState, Stack<String> goalStateStack) {
|
||||
List<Stack<String>> listOfStacks = currentState.getState();
|
||||
int currentStateHeuristics = currentState.getHeuristics();
|
||||
|
||||
Optional<State> newState = listOfStacks.stream()
|
||||
return listOfStacks.stream()
|
||||
.map(stack -> {
|
||||
State tempState = null;
|
||||
List<Stack<String>> tempStackList = new ArrayList<Stack<String>>(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;
|
||||
return applyOperationsOnState(listOfStacks, stack, currentStateHeuristics, goalStateStack);
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.findFirst();
|
||||
|
||||
return newState.orElse(null);
|
||||
.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
|
||||
*
|
||||
* @param currentStackList
|
||||
* @param block
|
||||
* @param currentStateHeuristics
|
||||
* @param goalStateStack
|
||||
* @return a new state
|
||||
*/
|
||||
private State pushElementToNewStack(List<Stack<String>> currentStackList, String block, int currentStateHeuristics, Stack<String> goalStateStack) {
|
||||
State newState = null;
|
||||
Stack<String> newStack = new Stack<String>();
|
||||
Stack<String> newStack = new Stack<>();
|
||||
newStack.push(block);
|
||||
|
||||
currentStackList.add(newStack);
|
||||
@@ -138,62 +126,64 @@ public class HillClimbing {
|
||||
* 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
|
||||
*
|
||||
* @param stack
|
||||
* @param currentStackList
|
||||
* @param block
|
||||
* @param currentStateHeuristics
|
||||
* @param goalStateStack
|
||||
* @return a new state
|
||||
*/
|
||||
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 -> {
|
||||
stack.push(block);
|
||||
int newStateHeuristics = getHeuristicsValue(currentStackList, goalStateStack);
|
||||
if (newStateHeuristics > currentStateHeuristics) {
|
||||
return new State(currentStackList, newStateHeuristics);
|
||||
}
|
||||
stack.pop();
|
||||
return null;
|
||||
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
|
||||
*
|
||||
* @param currentState
|
||||
* @param goalStateStack
|
||||
* @return
|
||||
*/
|
||||
public int getHeuristicsValue(List<Stack<String>> currentState, Stack<String> goalStateStack) {
|
||||
|
||||
Integer heuristicValue = 0;
|
||||
Integer heuristicValue;
|
||||
heuristicValue = currentState.stream()
|
||||
.mapToInt(stack -> {
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,26 +5,23 @@ import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
public class State {
|
||||
List<Stack<String>> state;
|
||||
int heuristics;
|
||||
|
||||
public State() {
|
||||
}
|
||||
private List<Stack<String>> state;
|
||||
private int heuristics;
|
||||
|
||||
public State(List<Stack<String>> state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public State(List<Stack<String>> state, int heuristics) {
|
||||
State(List<Stack<String>> state, int heuristics) {
|
||||
this.state = state;
|
||||
this.heuristics = heuristics;
|
||||
}
|
||||
|
||||
public State(State state) {
|
||||
State(State state) {
|
||||
if (state != null) {
|
||||
this.state = new ArrayList<Stack<String>>();
|
||||
this.state = new ArrayList<>();
|
||||
for (Stack s : state.getState()) {
|
||||
Stack s1 = new Stack();
|
||||
Stack s1;
|
||||
s1 = (Stack) s.clone();
|
||||
this.state.add(s1);
|
||||
}
|
||||
@@ -36,10 +33,6 @@ public class State {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(List<Stack<String>> state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public int getHeuristics() {
|
||||
return 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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,17 +14,17 @@ import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class HillClimbingAlgorithmTest {
|
||||
Stack<String> initStack;
|
||||
Stack<String> goalStack;
|
||||
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<String>();
|
||||
initStack = new Stack<>();
|
||||
for (String block : blockArr)
|
||||
initStack.push(block);
|
||||
goalStack = new Stack<String>();
|
||||
goalStack = new Stack<>();
|
||||
for (String block : goalBlockArr)
|
||||
goalStack.push(block);
|
||||
}
|
||||
@@ -48,7 +48,7 @@ public class HillClimbingAlgorithmTest {
|
||||
@Test
|
||||
public void givenCurrentState_whenFindNextState_thenBetterHeuristics() {
|
||||
HillClimbing hillClimbing = new HillClimbing();
|
||||
List<Stack<String>> initList = new ArrayList<Stack<String>>();
|
||||
List<Stack<String>> initList = new ArrayList<>();
|
||||
initList.add(initStack);
|
||||
State currentState = new State(initList);
|
||||
currentState.setHeuristics(hillClimbing.getHeuristicsValue(initList, goalStack));
|
||||
|
||||
@@ -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,3 @@
|
||||
### Relevant articles
|
||||
|
||||
- [Introduction to Asciidoctor](http://www.baeldung.com/introduction-to-asciidoctor)
|
||||
@@ -0,0 +1,56 @@
|
||||
<?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>asciidoctor</artifactId>
|
||||
<name>asciidoctor</name>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.asciidoctor</groupId>
|
||||
<artifactId>asciidoctor-maven-plugin</artifactId>
|
||||
<version>1.5.5</version>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.asciidoctor</groupId>
|
||||
<artifactId>asciidoctorj-pdf</artifactId>
|
||||
<version>1.5.0-alpha.15</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>output-pdf</id>
|
||||
<phase>generate-resources</phase>
|
||||
<goals>
|
||||
<goal>process-asciidoc</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<sourceDirectory>src/docs/asciidoc</sourceDirectory>
|
||||
<outputDirectory>target/docs/asciidoc</outputDirectory>
|
||||
<backend>pdf</backend>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.asciidoctor</groupId>
|
||||
<artifactId>asciidoctorj</artifactId>
|
||||
<version>1.5.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.asciidoctor</groupId>
|
||||
<artifactId>asciidoctorj-pdf</artifactId>
|
||||
<version>1.5.0-alpha.11</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,3 @@
|
||||
== Introduction Section
|
||||
|
||||
Hi. I'm a simple test to see if this Maven build is working. If you see me in a nice PDF, then it means everything is [red]#working#.
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.baeldung.asciidoctor;
|
||||
|
||||
import static org.asciidoctor.Asciidoctor.Factory.create;
|
||||
import static org.asciidoctor.OptionsBuilder.options;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.asciidoctor.Asciidoctor;
|
||||
|
||||
public class AsciidoctorDemo {
|
||||
|
||||
private final Asciidoctor asciidoctor;
|
||||
|
||||
AsciidoctorDemo() {
|
||||
asciidoctor = create();
|
||||
}
|
||||
|
||||
public void generatePDFFromString(final String input) {
|
||||
|
||||
final Map<String, Object> options = options().inPlace(true)
|
||||
.backend("pdf")
|
||||
.asMap();
|
||||
|
||||
|
||||
final String outfile = asciidoctor.convertFile(new File("sample.adoc"), options);
|
||||
}
|
||||
|
||||
String generateHTMLFromString(final String input) {
|
||||
return asciidoctor.convert("Hello _Baeldung_!", new HashMap<String, Object>());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.baeldung.asciidoctor;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class AsciidoctorDemoTest {
|
||||
|
||||
@Test
|
||||
public void givenString_whenConverting_thenResultingHTMLCode() {
|
||||
final AsciidoctorDemo asciidoctorDemo = new AsciidoctorDemo();
|
||||
Assert.assertEquals(asciidoctorDemo.generateHTMLFromString("Hello _Baeldung_!"), "<div class=\"paragraph\">\n<p>Hello <em>Baeldung</em>!</p>\n</div>");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.baeldung.java9.time;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class TimeApi {
|
||||
|
||||
public static List<Date> getDatesBetweenUsingJava7(Date startDate, Date endDate) {
|
||||
List<Date> datesInRange = new ArrayList<Date>();
|
||||
Calendar calendar = new GregorianCalendar();
|
||||
calendar.setTime(startDate);
|
||||
|
||||
Calendar endCalendar = new GregorianCalendar();
|
||||
endCalendar.setTime(endDate);
|
||||
|
||||
while (calendar.before(endCalendar)) {
|
||||
Date result = calendar.getTime();
|
||||
datesInRange.add(result);
|
||||
calendar.add(Calendar.DATE, 1);
|
||||
}
|
||||
return datesInRange;
|
||||
}
|
||||
|
||||
public static List<LocalDate> getDatesBetweenUsingJava8(LocalDate startDate, LocalDate endDate) {
|
||||
long numOfDaysBetween = ChronoUnit.DAYS.between(startDate, endDate);
|
||||
return IntStream.iterate(0, i -> i + 1)
|
||||
.limit(numOfDaysBetween)
|
||||
.mapToObj(i -> startDate.plusDays(i))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static List<LocalDate> getDatesBetweenUsingJava9(LocalDate startDate, LocalDate endDate) {
|
||||
return startDate.datesUntil(endDate).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.baeldung.java9.time;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TimeApiTest {
|
||||
|
||||
@Test
|
||||
public void givenGetDatesBetweenWithUsingJava7_WhenStartEndDate_thenDatesList() {
|
||||
Date startDate = Calendar.getInstance().getTime();
|
||||
Calendar endCalendar = Calendar.getInstance();
|
||||
endCalendar.add(Calendar.DATE, 2);
|
||||
Date endDate = endCalendar.getTime();
|
||||
|
||||
List<Date> dates = TimeApi.getDatesBetweenUsingJava7(startDate, endDate);
|
||||
assertEquals(dates.size(), 2);
|
||||
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
Date date1 = calendar.getTime();
|
||||
assertEquals(dates.get(0).getDay(), date1.getDay());
|
||||
assertEquals(dates.get(0).getMonth(), date1.getMonth());
|
||||
assertEquals(dates.get(0).getYear(), date1.getYear());
|
||||
|
||||
calendar.add(Calendar.DATE, 1);
|
||||
Date date2 = calendar.getTime();
|
||||
assertEquals(dates.get(1).getDay(), date2.getDay());
|
||||
assertEquals(dates.get(1).getMonth(), date2.getMonth());
|
||||
assertEquals(dates.get(1).getYear(), date2.getYear());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenGetDatesBetweenWithUsingJava8_WhenStartEndDate_thenDatesList() {
|
||||
LocalDate startDate = LocalDate.now();
|
||||
LocalDate endDate = LocalDate.now().plusDays(2);
|
||||
|
||||
List<LocalDate> dates = TimeApi.getDatesBetweenUsingJava8(startDate, endDate);
|
||||
assertEquals(dates.size(), 2);
|
||||
assertEquals(dates.get(0), LocalDate.now());
|
||||
assertEquals(dates.get(1), LocalDate.now().plusDays(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenGetDatesBetweenWithUsingJava9_WhenStartEndDate_thenDatesList() {
|
||||
LocalDate startDate = LocalDate.now();
|
||||
LocalDate endDate = LocalDate.now().plusDays(2);
|
||||
|
||||
List<LocalDate> dates = TimeApi.getDatesBetweenUsingJava9(startDate, endDate);
|
||||
assertEquals(dates.size(), 2);
|
||||
assertEquals(dates.get(0), LocalDate.now());
|
||||
assertEquals(dates.get(1), LocalDate.now().plusDays(1));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,9 +17,10 @@
|
||||
|
||||
# Files generated by integration tests
|
||||
*.txt
|
||||
backup-pom.xml
|
||||
/bin/
|
||||
/temp
|
||||
|
||||
#IntelliJ specific
|
||||
.idea
|
||||
.idea/
|
||||
*.iml
|
||||
+18
-1
@@ -113,4 +113,21 @@
|
||||
- [Difference Between Wait and Sleep in Java](http://www.baeldung.com/java-wait-and-sleep)
|
||||
- [LongAdder and LongAccumulator in Java](http://www.baeldung.com/java-longadder-and-longaccumulator)
|
||||
- [Using Java MappedByteBuffer](http://www.baeldung.com/java-mapped-byte-buffer)
|
||||
|
||||
- [Dynamic Proxies in Java](http://www.baeldung.com/java-dynamic-proxies)
|
||||
- [How to Copy an Array in Java](http://www.baeldung.com/java-array-copy)
|
||||
- [Introduction to JDBC](http://www.baeldung.com/java-jdbc)
|
||||
- [Guide to CopyOnWriteArrayList](http://www.baeldung.com/java-copy-on-write-arraylist)
|
||||
- [Period and Duration in Java](http://www.baeldung.com/java-period-duration)
|
||||
- [Converting a Stack Trace to a String in Java](http://www.baeldung.com/java-stacktrace-to-string)
|
||||
- [Guide to the Java Phaser](http://www.baeldung.com/java-phaser)
|
||||
- [Count Occurrences of a Char in a String](http://www.baeldung.com/java-count-chars)
|
||||
- [Java Double Brace Initialization](http://www.baeldung.com/java-double-brace-initialization)
|
||||
- [The StackOverflowError in Java](http://www.baeldung.com/java-stack-overflow-error)
|
||||
- [Split a String in Java](http://www.baeldung.com/java-split-string)
|
||||
- [Introduction to Java Serialization](http://www.baeldung.com/java-serialization)
|
||||
- [How to Remove the Last Character of a String?](http://www.baeldung.com/java-remove-last-character-of-string)
|
||||
- [Guide to Synchronized Keyword in Java](http://www.baeldung.com/java-synchronized)
|
||||
- [ClassNotFoundException vs NoClassDefFoundError](http://www.baeldung.com/java-classnotfoundexception-and-noclassdeffounderror)
|
||||
- [Guide to UUID in Java](http://www.baeldung.com/java-uuid)
|
||||
- [How to Get the Last Element of a Stream in Java?](http://www.baeldung.com/java-stream-last-element)
|
||||
- [Guide to Escaping Characters in Java RegExps](http://www.baeldung.com/java-regexp-escape-char)
|
||||
|
||||
+358
-359
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,86 @@
|
||||
package com.baeldung.concurrent.cyclicbarrier;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.BrokenBarrierException;
|
||||
import java.util.concurrent.CyclicBarrier;
|
||||
|
||||
/**
|
||||
* Created by cv on 24/6/17.
|
||||
*/
|
||||
public class CyclicBarrierDemo {
|
||||
|
||||
private CyclicBarrier cyclicBarrier;
|
||||
private List<List<Integer>> partialResults = Collections.synchronizedList(new ArrayList<>());
|
||||
private Random random = new Random();
|
||||
private int NUM_PARTIAL_RESULTS;
|
||||
private int NUM_WORKERS;
|
||||
|
||||
|
||||
public void runSimulation(int numWorkers, int numberOfPartialResults) {
|
||||
NUM_PARTIAL_RESULTS = numberOfPartialResults;
|
||||
NUM_WORKERS = numWorkers;
|
||||
|
||||
cyclicBarrier = new CyclicBarrier(NUM_WORKERS, new AggregatorThread());
|
||||
System.out.println("Spawning " + NUM_WORKERS + " worker threads to compute "
|
||||
+ NUM_PARTIAL_RESULTS + " partial results each");
|
||||
for (int i = 0; i < NUM_WORKERS; i++) {
|
||||
Thread worker = new Thread(new NumberCruncherThread());
|
||||
worker.setName("Thread " + i);
|
||||
worker.start();
|
||||
}
|
||||
}
|
||||
|
||||
class NumberCruncherThread implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
String thisThreadName = Thread.currentThread().getName();
|
||||
List<Integer> partialResult = new ArrayList<>();
|
||||
for (int i = 0; i < NUM_PARTIAL_RESULTS; i++) {
|
||||
Integer num = random.nextInt(10);
|
||||
System.out.println(thisThreadName
|
||||
+ ": Crunching some numbers! Final result - " + num);
|
||||
partialResult.add(num);
|
||||
}
|
||||
partialResults.add(partialResult);
|
||||
try {
|
||||
System.out.println(thisThreadName + " waiting for others to reach barrier.");
|
||||
cyclicBarrier.await();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
} catch (BrokenBarrierException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class AggregatorThread implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
String thisThreadName = Thread.currentThread().getName();
|
||||
System.out.println(thisThreadName + ": Computing final sum of " + NUM_WORKERS
|
||||
+ " workers, having " + NUM_PARTIAL_RESULTS + " results each.");
|
||||
int sum = 0;
|
||||
for (List<Integer> threadResult : partialResults) {
|
||||
System.out.print("Adding ");
|
||||
for (Integer partialResult : threadResult) {
|
||||
System.out.print(partialResult+" ");
|
||||
sum += partialResult;
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
System.out.println(Thread.currentThread().getName() + ": Final result = " + sum);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
CyclicBarrierDemo play = new CyclicBarrierDemo();
|
||||
play.runSimulation(5, 3);
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user