|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270 |
- /**
- * @file HeuristicPlayer.java
- *
- * @author
- * Anastasia Foti AEM:8959
- * <anastaskf@ece.auth.gr>
- *
- * @author
- * Christos Choutouridis AEM:8997
- * <cchoutou@ece.auth.gr>
- */
-
- package host.labyrinth;
-
- /**
- * @brief
- * This class represents the game's player who cheats.
- */
- class HeuristicPlayer 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 HeuristicPlayer(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 HeuristicPlayer(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
- * @return The distance or Const.noSupply
- */
- int supplyInDirection(int currentPos, int direction) {
- Position pos = new Position(Position.toRow(currentPos), Position.toCol(currentPos));
-
- for (int i=0 ; board.isWalkable(pos.getId(), direction) && i<Const.viewDistance ; ++i) {
- pos = new Position(pos.getRow(), pos.getCol(), direction);
- if (board.hasSupply(pos.getId()))
- return i+1;
- }
- return Const.noSupply;
- }
-
- /**
- * 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
- * @return The distance or Const.noOpponent
- */
- int opponetInDirection(int currentPos, int direction) {
- Position pos = new Position(Position.toRow(currentPos), Position.toCol(currentPos));
- int [] opp = board.getOpponentMove(playerId);
-
- for (int i=0 ; board.isWalkable(pos.getId(), direction) && i<Const.viewDistance ; ++i) {
- pos = new Position(pos.getRow(), pos.getCol(), direction);
- if (opp[MOVE_TILE_ID] == pos.getId())
- return i+1;
- }
- return Const.noOpponent;
- }
-
- /**
- * 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
- * @return A signed real number. The higher the output, the higher the evaluation.
- */
- double evaluate (int currentPos, int direction) {
- int opDist = opponetInDirection (currentPos, direction);
- int supDist = supplyInDirection(currentPos, direction);
-
- // saturate
- opDist = (opDist == Const.noOpponent) ? 0: opDist;
- supDist = (supDist == Const.noSupply) ? 0 : supDist;
- return ((supDist != 0)? (1.0/supDist * Const.supplyFactor) : 0)
- - ((opDist != 0) ? (1.0/opDist * Const.opponentFactor) : 0);
- }
-
- /**
- * 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) {
- Range dirs = new Range(DirRange.Begin, DirRange.End, DirRange.Step);
- int N = dirs.size();
- double[] eval = new double[N];
- int [] eval_dir = new int[N];
-
- for (int i =0, dir = dirs.get() ; dir != Const.EOR ; dir = dirs.get(), ++i) {
- if (board.isWalkable(currentPos, dir))
- eval[i] = evaluate(currentPos, dir);
- else
- eval[i] = Double.NEGATIVE_INFINITY;
- eval_dir[i] = dir;
- }
- int dir;
- if (isUnevaluated(eval, N)) {
- ShuffledRange r = new ShuffledRange(DirRange.Begin, DirRange.End, DirRange.Step);
- do
- dir = r.get();
- while (!board.isWalkable(currentPos, dir));
- }
- else {
- dir = directionOfMax (eval, eval_dir, N);
- }
- Position new_pos = new Position( Position.toRow(currentPos), Position.toCol(currentPos), dir );
- int [] ret = {new_pos.getId(), new_pos.getRow(), new_pos.getCol(), dir};
- return ret;
- }
-
- /**
- * HeuristicPlayer'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:
- * <ul>
- * <li> int[0]: The tileId of the final player's position.
- * <li> int[1]: The row of the final player's position.
- * <li> int[2]: The column of the final player's position.
- * <li> int[3]: The dice/direction of the move.
- * </ul>
- */
- @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 =DirRange.End, omin =DirRange.End;
- for (int d = DirRange.Begin ; d<DirRange.End ; d += DirRange.Step) {
- int s = supplyInDirection (ret[MOVE_TILE_ID], d);
- int o = opponetInDirection(ret[MOVE_TILE_ID], d);
- if (s >= 0 && s < smin) smin = s;
- if (o >= 0 && o < omin) omin = o;
- }
- // update path
- Integer[] p = {
- ret[MOVE_TILE_ID], ret[MOVE_DICE], moveFlag, supplyFlag,
- dirCounter[Direction.UP], dirCounter[Direction.RIGHT], dirCounter[Direction.DOWN], dirCounter[Direction.LEFT],
- (smin != DirRange.End)? smin:Const.noSupply, (omin != DirRange.End)? omin:Const.noOpponent
- };
- path.add(p);
- return ret;
- }
-
- /**
- * Prints round information for the player
- */
- void statistics() {
- if (!path.isEmpty()) {
- Integer[] last = path.get(path.size()-1);
- String who = String.format("%12s", name);
- System.out.print(who + ": score[" + score + "]" + ", dice =" + last[1] + ", tileId =" + last[0] + " (" + Position.toRow(last[0]) + ", " + Position.toCol(last[0]) + ")");
- if (last[2] == 0)
- System.out.println(" *Can not move.");
- else if (last[3] != 0)
- System.out.println(" *Found a supply.");
- else
- System.out.println("");
- // extra prints for heuristic
- if (last[8] != Const.noSupply) System.out.println(" supply =" + last[8]);
- else System.out.println(" supply = blind");
- if (last[9] != Const.noOpponent) System.out.println(" opponent =" + last[9]);
- else System.out.println(" opponent = blind");
- }
- }
-
- /**
- * Prints final statistics for the player
- */
- void final_statistics () {
- String who = String.format("%12s", name);
- System.out.println();
- System.out.println(who + ": score[" + score + "]");
- System.out.println(" Moves up: " + dirCounter[Direction.UP]);
- System.out.println(" Moves right: " + dirCounter[Direction.RIGHT]);
- System.out.println(" Moves down: " + dirCounter[Direction.DOWN]);
- System.out.println(" Moves left: " + dirCounter[Direction.LEFT]);
- }
-
- /** @} */
-
- /**
- * A small utility to extract the direction of maximum evaluation result.
- *
- * We search into the \c eval results and find the index of the maximum evaluation.
- * Then we return the direction of \c eval_dir matrix at the same index we found.
- *
- * @param eval Array with evaluation results for each direction
- * @param eval_dir Array with the matching direction to \c eval array
- * @param N The size of both arrays
- * @return The direction of maximum evaluation. If \c eval is empty returns the first item \c eval[0]
- * @note
- * This function should not be called if there is at least one evaluation result in \c eval
- */
- private int directionOfMax (double[] eval, int[] eval_dir, int N) {
- double M = Double.NEGATIVE_INFINITY;
- int M_idx = 0;
- for (int i =0; i < N ; ++i) {
- if (eval[i] > M) {
- M = eval[i];
- M_idx = i;
- }
- }
- return eval_dir[M_idx];
- }
-
- /**
- * A small utility to check if there is at least one evaluation result in the \c eval array
- * @param eval The array to check
- * @param N The size of the array
- * @return True if there is none, false otherwise
- */
- private boolean isUnevaluated (double[] eval, int N) {
- for (int i =0 ; i<N ; ++i)
- if (eval[i] != 0 && eval[i] != Double.NEGATIVE_INFINITY)
- return false;
- return true;
- }
-
- /** @name Class data */
- /** @{ */
-
-
- /** @} */
- }
|