package uulm.teamname.marvelous.gamelibrary.ai; import uulm.teamname.marvelous.gamelibrary.entities.EntityID; import uulm.teamname.marvelous.gamelibrary.entities.EntityType; import uulm.teamname.marvelous.gamelibrary.gamelogic.GameStateView; import java.util.ArrayList; import java.util.HashMap; class BoardAnalyzer { private final Board origin; private final EntityType player; private final HashMap scoreCache = new HashMap<>(); private final HashMap> actionCache = new HashMap<>(); private Action bestAction = null; public BoardAnalyzer(GameStateView state, EntityID turn) { this.origin = Board.generate(state, turn); this.player = turn.type; } public Action analyze(GameStateView state) { Node tree = new Node(origin, new Action(ActionType.None)); int maxDepth = 2; int depth = 0; long startTime = System.nanoTime(); while(System.nanoTime() - startTime <= 1000 * 1000 * 1000) { expandTree(tree, state); depth++; if(depth > maxDepth) { break; } } alphaBetaMax(tree, Float.MIN_VALUE, Float.MAX_VALUE, true); if(bestAction != null) { return bestAction; } return new Action(ActionType.None); } private Float alphaBetaMax(Node root, Float a, Float b, boolean main) { if(!root.hasChildren()) { return calculateScore(root.board); } Float w = a; for(Node child: root.getChildren()) { Float v; if(child.board.turn.type == child.board.origin) { v = alphaBetaMax(child, a, w, false); }else { v = alphaBetaMin(child, w, b); } if(v > w) { w = v; } if(w >= b) { if(main) { bestAction = child.action; } return w; } if(main) { bestAction = child.action; } } return w; } private Float alphaBetaMin(Node root, Float a, Float b) { if(!root.hasChildren()) { return calculateScore(root.board); } Float w = b; for(Node child: root.getChildren()) { Float v; if(child.board.turn.type == child.board.origin) { v = alphaBetaMax(child, a, w, false); }else { v = alphaBetaMin(child, w, b); } if(v < w) { w = v; } if(w <= a) { return w; } } return w; } private ArrayList getLeaves(Node root) { return getLeaves(root, new ArrayList<>()); } private ArrayList getLeaves(Node root, ArrayList accumulator) { for(Node child: root.getChildren()) { if(child.hasChildren()) { getLeaves(child, accumulator); }else { accumulator.add(child); } } return accumulator; } private void expandTree(Node root, GameStateView state) { if(!root.hasChildren()) { expandNode(root, state); return; } for(Node child: root.getChildren()) { if(child.board.ended) { continue; } if(child.hasChildren()) { expandTree(child, state); }else { expandNode(child, state); } } } private void expandNode(Node origin, GameStateView state) { ArrayList actions = generateActions(origin.board, state); for(Action action: actions) { Board result = origin.board.applyAction(state, action); scoreCache.put(result.hashCode(), result.calculateScore()); origin.addChild(result, action, result.calculateScore()); } } private ArrayList generateActions(Board board, GameStateView state) { int hash = board.hashCode(); if(actionCache.containsKey(hash)) { return actionCache.get(hash); }else { ArrayList result = board.generateActions(state); actionCache.put(hash, result); return result; } } private Float calculateScore(Board board) { int hash = board.hashCode(); if(scoreCache.containsKey(hash)) { return scoreCache.get(hash); }else { Float result = board.calculateScore(); scoreCache.put(hash, result); return result; } } }