/** * @file MinMaxPlayer.java * * @author * Anastasia Foti AEM:8959 * * * @author * Christos Choutouridis AEM:8997 * */ package host.labyrinth; /** * @brief * This class represents the game's minimax player. */ class MinMaxPlayer extends Player { /** @name Constructors */ /** @{ */ /** * Create a new player and put him at the row-column coordinates * @param name The name of the player * @param champion Flag to indicate if a player is a `champion` * @param board Reference to the board of the game * @param row The row coordinate of initial player position * @param column The column coordinate of initial player's position */ public MinMaxPlayer(String name, boolean champion, Board board, int row, int column) throws Exception { super(name, champion, board, row, column); } /** * Create a new player and put him at the row-column coordinates * @param name The name of the player * @param champion Flag to indicate if a player is a `champion` * @param board Reference to the board of the game * @param tileId The tileId coordinate of player's initial position */ public MinMaxPlayer(String name, boolean champion, Board board, int tileId) throws Exception { super(name, champion, board, tileId); } /** @} */ /** @name Board's main application interface */ /** @{ */ /** * Utility to get the distance of a possible supply in some direction * @param currentPos The current position of the player * @param direction The direction to check * @param board Reference to the Board object to use * * @return The distance or Const.noView */ int supplyInDirection(int currentPos, int direction, Board board) { Position pos = new Position(Position.toRow(currentPos), Position.toCol(currentPos)); for (int i=0 ; i<=Const.viewDistance ; ++i) { if (board.hasSupply(pos.getId())) return i; if (board.isWalkable(pos.getId(), direction)) pos = new Position(pos.getRow(), pos.getCol(), direction); else break; } return Const.noView; } /** * Utility to get the distance of a possible opponent in some direction * @param currentPos The current position of the player * @param direction The direction to check * @param board Reference to the Board object to use * * @return The distance or Const.noView */ int opponetInDirection(int currentPos, int direction, Board board) { Position pos = new Position(Position.toRow(currentPos), Position.toCol(currentPos)); int[] opp = board.getOpponentMove(playerId); for (int i=0 ; i<=Const.viewDistance ; ++i) { if (opp[MOVE_TILE_ID] == pos.getId()) return i; if (board.isWalkable(pos.getId(), direction)) pos = new Position(pos.getRow(), pos.getCol(), direction); else break; } return Const.noView; } /** * This is the main move evaluation function. * * @param currentPos The current position of the player (before the move to evaluate) * @param direction The direction (a.k.a. the move) to evaluate * @param board Reference to the Board object to use * @return A signed real number. The higher the output, the higher the evaluation. */ double evaluate (int currentPos, int direction, Board board) { Position next = new Position (Position.toRow(currentPos), Position.toCol(currentPos), direction); int preOpDist = opponetInDirection (currentPos, direction, board); int preSupDist = supplyInDirection(currentPos, direction, board); int postOpDist = opponetInDirection (next.getId(), direction, board); int postSupDist = supplyInDirection(next.getId(), direction, board); return ((preSupDist != Const.noView) ? Const.preMoveFactor *(1.0/(preSupDist+1) * Const.supplyFactor) : 0) - ((preOpDist != Const.noView) ? Const.preMoveFactor *(1.0/(preOpDist+1) * Const.opponentFactor) : 0) + ((postSupDist != Const.noView)? Const.postMoveFactor*(1.0/(preSupDist+1) * Const.supplyFactor) : 0) - ((postOpDist != Const.noView) ? Const.postMoveFactor*(1.0/(preOpDist+1) * Const.opponentFactor) : 0); } /** * Executes the minimax algorithm and return a reference to selected move * @param node The root node to start * @return Reference to the selected move */ Node chooseMinMaxMove(Node node) { node.setNodeEvaluation(maxValue(node)); return node.getPath(); } /** * Selects the best possible move to return * @param currentPos Player's current position to the board * @return The move array * * @note * This function always return a new move. */ int[] getNextMove(int currentPos) { Node root = new Node (board); int [] opp = board.getOpponentMove(playerId); createMySubtree(currentPos, opp[MOVE_TILE_ID], root, root.getNodeDepth()+1); return chooseMinMaxMove(root).getNodeMove(); } /** * MinMaxPlayer's move. * * A player of this kind cheats. He does not throw a dice to get a direction. In contrary he * calculates his next move very carefully. * If the player is a champion then he also picks up a possible supply from the tile. * * @param id The id of the starting tile. * @return An array containing player's final position and possible supply of that position. * The array format is: * */ @Override int[] move(int id) { // Initialize return array with the current data int[] ret = getNextMove(id); y = Position.toRow(ret[MOVE_TILE_ID]); x = Position.toCol(ret[MOVE_TILE_ID]); int supplyFlag =0, moveFlag =1; // In case of a champion player, try also to pick a supply if (champion && (board.tryPickSupply(ret[MOVE_TILE_ID]) != Const.noSupply)) { ++score; // keep score ++supplyFlag; } ++dirCounter[ret[MOVE_DICE]]; // update direction counters board.updateMove(ret, playerId); // Update supply and opponent distance int smin =Const.noView, omin =Const.noView; for (int d = DirRange.Begin ; d n.getNodeEvaluation()) { m = n.getNodeEvaluation(); node.setPath(n); // path propagation } } return m; } } /** @} */ }