diff --git a/ds_project_2020-2021_PartC.pdf b/ds_project_2020-2021_PartC.pdf new file mode 100644 index 0000000..e7db115 Binary files /dev/null and b/ds_project_2020-2021_PartC.pdf differ diff --git a/release/8959_8997_PartB.zip b/release/8959_8997_PartB.zip new file mode 100644 index 0000000..6192c32 Binary files /dev/null and b/release/8959_8997_PartB.zip differ diff --git a/src/host/labyrinth/Board.java b/src/host/labyrinth/Board.java index 4c152ce..0a32035 100644 --- a/src/host/labyrinth/Board.java +++ b/src/host/labyrinth/Board.java @@ -13,7 +13,6 @@ package host.labyrinth; import java.util.ArrayList; -import java.util.Arrays; import java.util.function.IntFunction; /** @@ -35,9 +34,10 @@ class Board { this.S = 0; this.W = 0; tiles = null; - supplies =null; + supplies = null; walls = new ArrayList(); - moves = new ArrayList(); + moves = new int[Const.numOfPlayers][Player.MOVE_DATA_SIZE]; + playerCount =0; } /** @@ -54,7 +54,8 @@ class Board { tiles = new Tile[N*N]; supplies = new Supply[S]; walls = new ArrayList(); - moves = new ArrayList(); + moves = new int[Const.numOfPlayers][Player.MOVE_DATA_SIZE]; + playerCount =0; } /** @@ -72,17 +73,28 @@ class Board { */ Board(Board b) { // Copy primitives - this.N = b.N; - this.S = b.S; - this.W = b.W; - // Clone arrays - this.tiles = b.tiles.clone(); - this.supplies = b.supplies.clone(); + this.N = b.N; + this.S = b.S; + this.W = b.W; + tiles = new Tile[b.tiles.length]; + supplies = new Supply[b.supplies.length]; + walls = new ArrayList(); + moves = new int[Const.numOfPlayers][Player.MOVE_DATA_SIZE]; + playerCount =b.playerCount; + + // clone moves array of array of primitives + for (int i=0 ; ii).toArray(); - ++ii; - } - return ret; + * @return The other player's Id. + */ + int getOpponentId(int playerId) { + return Const.numOfPlayers - (playerId +1); } /** - * Utility function to create player IDs - * @return The generated player id. + * Boards utility to give access to other player moves. + * + * @param playerId The id of player who asks + * @return The moves data of other player */ - int generatePlayerId () { - moves.add(null); - return moves.size() -1; + int[] getOpponentMove (int playerId) { + return moves[getOpponentId(playerId)]; } /** @@ -256,7 +273,8 @@ class Board { * @param playerId The id of the player who update his/her data. */ void updateMove(int[] m, int playerId) { - moves.set(playerId, Arrays.stream(m).boxed().toArray(Integer[]::new)); + //moves.set(playerId, Arrays.stream(m).boxed().toArray(Integer[]::new)); + moves[playerId] = m; } /** @} */ @@ -295,7 +313,7 @@ class Board { * see also here * @return Reference to inner walls array. */ - ArrayList getMoves() { return moves; } + int[][] getMoves() { return moves; } void setN(int N) { this.N = N; } void setS(int S) { this.S = S; } @@ -326,7 +344,7 @@ class Board { * @note Use with care. * Any call to this function will probably add memory for the garbage collector. */ - void setMoves(ArrayList moves) { this.moves =moves; } + void setMoves(int[][] moves) { this.moves =moves; } /** @} */ @@ -633,6 +651,7 @@ class Board { * Array to hold all the walls using the edge representation * required by the closed room preventing algorithm. */ - private ArrayList moves; + private int[][] moves; + private int playerCount; /** @} */ } diff --git a/src/host/labyrinth/Common.java b/src/host/labyrinth/Common.java index 7c4851c..94e1336 100644 --- a/src/host/labyrinth/Common.java +++ b/src/host/labyrinth/Common.java @@ -19,16 +19,23 @@ import java.util.Collections; * Class to hold constant values for entire application */ class Const { + static final int numOfPlayers = 2; static final int maxTileWalls = 2; /**< Number of maximum walls for each tile on the board */ static final int noSupply =-1; /**< Number to indicate the absent of supply */ static final int noOpponent =-1; /**< Number to indicate the absent of supply */ static final int noTileId =-1; /**< Number to indicate wrong tileId */ static final int EOR =-1; /**< Number to indicate the End Of Range */ - static final int moveItems =4; /**< The number of items return by move() */ static final int viewDistance =3; /**< The max distance of the Heuristic player's ability to see */ + static final int noView = viewDistance+1; - static final double opponentFactor =1.0; - static final double supplyFactor =0.65; + /** Parameters to control move evaluation */ + /** @{ */ + static final double opponentFactor = 1.0; /**< opponent distance factor */ + static final double supplyFactor = 0.65; /**< supply distance factor */ + static final double preMoveFactor = 0.65; /**< pre move distances factor */ + static final double postMoveFactor = 0.35; /**< post move distances factor */ + static final int minimaxTreeDepth = 4; /**< The maximum depth of the minimax tree */ + /** @} */ } /** * Application wide object to hold settings like values for the session. @@ -68,13 +75,16 @@ class Direction { static final int RIGHT =3; /**< East direction */ static final int DOWN =5; /**< South direction */ static final int LEFT =7; /**< West direction */ + static final int NONE =8; /**< No direction */ /** * Utility to get the opposite direction. * @param direction Input direction * @return The opposite direction */ - static int opposite (int direction) { return (direction+4)%DirRange.End; } + static int opposite (int direction) { + return (direction != NONE) ? (direction+4)%DirRange.End : NONE; + } static int get (int fromId, int toId) { if (Position.toID(Position.toRow(fromId), Position.toCol(fromId)-1) == toId) @@ -133,6 +143,7 @@ class Position { case Direction.DOWN: this.id = toID(row-1, col); break; case Direction.LEFT: this.id = toID(row, col-1); break; case Direction.RIGHT:this.id = toID(row, col+1); break; + case Direction.NONE: this.id = toID(row, col); break; } } diff --git a/src/host/labyrinth/Game.java b/src/host/labyrinth/Game.java index f12a15c..590557a 100644 --- a/src/host/labyrinth/Game.java +++ b/src/host/labyrinth/Game.java @@ -18,13 +18,14 @@ * all the supplies of the board before Minotaur catches him and before the * game ends. * - * In this 2nd assignment we deal with the creation of a new heuristic player + * In this 3rd assignment we deal with the creation of a new minimax player * who can cheat and manipulate the dice. Documented classes: * - Tile * - Supply * - Board * - Player * - HeuristicPlayer + * - MinMaxPlayer * - Game * * Which are the requested classes. We also provide some extra functionalities in: @@ -156,9 +157,9 @@ public class Game { // Create a game, a board and 2 players. Game game = new Game(); Board board = new Board(Session.boardSize, Session.supplySize); - Player T = new HeuristicPlayer("Theseus", true, board, 0); + Player T = new MinMaxPlayer("Theseus", true, board, 0); Player M = new Player("Minotaur", false, board, Position.toID(Session.boardSize/2, Session.boardSize/2)); - Player players [] = {T, M}; + Player players [] = {M, T}; // Populate data to the board board.createBoard(T.playerTileId(), M.playerTileId()); diff --git a/src/host/labyrinth/HeuristicPlayer.java b/src/host/labyrinth/HeuristicPlayer.java index d7538dd..fab333e 100644 --- a/src/host/labyrinth/HeuristicPlayer.java +++ b/src/host/labyrinth/HeuristicPlayer.java @@ -1,5 +1,5 @@ /** - * @file Player.java + * @file HeuristicPlayer.java * * @author * Anastasia Foti AEM:8959 @@ -29,7 +29,7 @@ class HeuristicPlayer extends Player { * @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) { + public HeuristicPlayer(String name, boolean champion, Board board, int row, int column) throws Exception { super(name, champion, board, row, column); } @@ -40,7 +40,7 @@ class HeuristicPlayer extends Player { * @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) { + public HeuristicPlayer(String name, boolean champion, Board board, int tileId) throws Exception { super(name, champion, board, tileId); } /** @} */ @@ -58,7 +58,7 @@ class HeuristicPlayer extends Player { Position pos = new Position(Position.toRow(currentPos), Position.toCol(currentPos)); for (int i=0 ; board.isWalkable(pos.getId(), direction) && i int[0]: The tileId of the final player's position. *
  • int[1]: The row of the final player's position. *
  • int[2]: The column of the final player's position. - *
  • int[3]: The supplyId in case player picked one (Const.noSupply otherwise). + *
  • int[3]: The dice/direction of the move. * */ @Override int[] move(int id) { // Initialize return array with the current data - int[] ret = new int[Const.moveItems]; - ret[0] = getNextMove(id); - ret[1] = y = Position.toRow(ret[0]); - ret[2] = x = Position.toCol(ret[0]); + 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 && (ret[3] = board.tryPickSupply(ret[0])) != Const.noSupply) { + if (champion && (board.tryPickSupply(ret[MOVE_TILE_ID]) != Const.noSupply)) { ++score; // keep score ++supplyFlag; } - int dir = Direction.get(id, ret[0]); // update direction counters - ++dirCounter[dir]; + ++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= 0 && s < smin) smin = s; if (o >= 0 && o < omin) omin = o; } // update path Integer[] p = { - ret[0], dir, moveFlag, supplyFlag, + 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 }; @@ -197,10 +202,10 @@ class HeuristicPlayer extends Player { else System.out.println(""); // extra prints for heuristic - if (last[8] != Const.noSupply) System.out.println(" supply distance =" + last[8]); - else System.out.println(" supply distance = blind"); - if (last[9] != Const.noOpponent) System.out.println(" opponent distance =" + last[9]); - else System.out.println(" opponent distance = blind"); + 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"); } } diff --git a/src/host/labyrinth/MinMaxPlayer.java b/src/host/labyrinth/MinMaxPlayer.java new file mode 100644 index 0000000..e6c8cf6 --- /dev/null +++ b/src/host/labyrinth/MinMaxPlayer.java @@ -0,0 +1,388 @@ +/** + * @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: + *
      + *
    • int[0]: The tileId of the final player's position. + *
    • int[1]: The row of the final player's position. + *
    • int[2]: The column of the final player's position. + *
    • int[3]: The dice/direction of the move. + *
    + */ + @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; + } + } + + /** @} */ + +} diff --git a/src/host/labyrinth/Node.java b/src/host/labyrinth/Node.java new file mode 100644 index 0000000..55b9a4e --- /dev/null +++ b/src/host/labyrinth/Node.java @@ -0,0 +1,119 @@ +/** + * @file Node.java + * + * @author + * Anastasia Foti AEM:8959 + * + * + * @author + * Christos Choutouridis AEM:8997 + * + */ + +package host.labyrinth; + +import java.util.ArrayList; + +/** + * Node object for minimax tree. + */ +class Node { + + /** @name Constructors */ + /** @{ */ + /** Null initialize constructor */ + Node () { } + /** The main constructor for the Node */ + Node (Node parent, int nodeDepth, int [] nodeMove, Board nodeBoard, double nodeEvaluation) { + this.parent = parent; + this.children = null; + this.nodeDepth = nodeDepth; + this.nodeMove = nodeMove; + this.nodeBoard = nodeBoard; + this.nodeEvaluation = nodeEvaluation; + this.path = null; + } + /** A special constructor for creating a root Node */ + Node (Board nodeBoard) { + this.parent = null; + this.children = null; + this.nodeDepth = 0; + this.nodeMove = new int [4]; + this.nodeBoard = nodeBoard; + this.nodeEvaluation = 0; + this.path = null; + } + /**@} */ + + /** @name Get/Set interface */ + /** @{ */ + /** Get parent */ + Node getParent() { return parent; } + /** get children */ + ArrayList + getChildren() { return children; } + /** get nodeDepth */ + int getNodeDepth() { return nodeDepth; } + /** get nodeMove */ + int[] getNodeMove() { return nodeMove; } + /** get nodeBoard */ + Board getNodeBoard() { return nodeBoard; } + /** get nodeEvluation */ + double getNodeEvaluation (){ return nodeEvaluation; } + /** get path */ + Node getPath() { return path; } + + /** set parent */ + void setParent(Node parent) { this.parent = parent; } + /** set children */ + void setChildren(ArrayList children) { + this.children = children; + } + /** set nodeDepth */ + void setNodeDepth(int nodeDepth) { + this.nodeDepth = nodeDepth; + } + /** set nodeMove */ + void setNodeMove(int[] nodeMove) { + this.nodeMove = nodeMove; + } + /** set nodeBoard */ + void setNodeBoard(Board nodeBoard) { + this.nodeBoard = nodeBoard; + } + /** set nodeEvaluation */ + void setNodeEvaluation(double nodeEvaluation) { + this.nodeEvaluation = nodeEvaluation; + } + /** set path */ + void setPath (Node path) { + this.path = path; + } + + /**@}*/ + + /** @name Public API */ + /** @{ */ + /** + * Add a child to the tree + * @param child The child to add + * @return the status of the operation + */ + boolean addChild (Node child) { + if (children == null) + children = new ArrayList<>(); + return children.add(child); + } + /**@}*/ + + /** @name Data members */ + /** @{ */ + private Node parent; /**< Back reference to parent Node */ + private ArrayList children; /**< Fwd reference to leaf Nodes */ + private int nodeDepth; /**< The Node's depth */ + private int[] nodeMove; /**< The Node's move data [tile, initTile, points, roll]*/ + private Board nodeBoard; /**< Reference to Board's copy of the current node*/ + private double nodeEvaluation; /**< The Node's evaluation result */ + private Node path; /**< The minimax evaluation path */ + /**@}*/ +} diff --git a/src/host/labyrinth/Player.java b/src/host/labyrinth/Player.java index caaeb68..db4cea8 100644 --- a/src/host/labyrinth/Player.java +++ b/src/host/labyrinth/Player.java @@ -19,6 +19,13 @@ import java.util.ArrayList; * This class represents the game's player */ class Player { + /** Helper variables to keep track of the move() return values @see move() */ + static final int MOVE_DATA_SIZE = 4; /**< The move return data array size */ + static final int MOVE_TILE_ID = 0; /**< Index of the tileId information of the move */ + static final int MOVE_ROW = 1; /**< The index of row information */ + static final int MOVE_COLUMN = 2; /**< The index of column information */ + static final int MOVE_DICE = 3; /**< The index of dice information */ + /** @name Constructors */ /** @{ */ @@ -30,7 +37,7 @@ class Player { * @param row The row coordinate of initial player position * @param column The column coordinate of initial player's position */ - Player(String name, boolean champion, Board board, int row, int column) { + Player(String name, boolean champion, Board board, int row, int column) throws Exception { this.playerId = board.generatePlayerId(); this.name = name; this.board = board; @@ -38,7 +45,7 @@ class Player { this.x = column; this.y = row; this.champion = champion; - this.dirCounter= new int[DirRange.End]; // yes we spoil some memory. Java is worst. + this.dirCounter= new int[DirRange.End]; // yes we spoil some memory. Java is the worst. this.path = new ArrayList(); int[] m = { Position.toID(row, column), row, column, Const.noSupply @@ -53,7 +60,7 @@ class Player { * @param board Reference to the board of the game * @param tileId The tileId coordinate of player's initial position */ - Player(String name, boolean champion, Board board, int tileId) { + Player(String name, boolean champion, Board board, int tileId) throws Exception { this.playerId = board.generatePlayerId(); this.name = name; this.board = board; @@ -61,7 +68,7 @@ class Player { this.x = Position.toCol(tileId); this.y = Position.toRow(tileId); this.champion = champion; - this.dirCounter= new int[DirRange.End]; // yes we spoil some memory. Java is worst. + this.dirCounter= new int[DirRange.End]; // yes we spoil some memory. Java is the worst. this.path = new ArrayList(); int[] m = { tileId, Position.toRow(tileId), Position.toCol(tileId), Const.noSupply @@ -87,37 +94,39 @@ class Player { *
  • int[0]: The tileId of the final player's position. *
  • int[1]: The row of the final player's position. *
  • int[2]: The column of the final player's position. - *
  • int[1]: The supplyId in case player picked one (Const.noSupply otherwise). + *
  • int[3]: The dice/direction of the move. * */ int[] move(int id) { // Initialize return array with the current data - int[] ret = new int[Const.moveItems]; - ret[0] = id; - ret[1] = Position.toRow(id); - ret[2] = Position.toCol(id); - ret[3] = Const.noSupply; + int[] ret = new int[MOVE_DATA_SIZE]; + ret[MOVE_TILE_ID] = id; + ret[MOVE_ROW] = Position.toRow(id); + ret[MOVE_COLUMN] = Position.toCol(id); + ret[MOVE_DICE] = Direction.NONE; int supplyFlag =0, moveFlag =0; - int diceDirection = board.dice(); // throw the dice - if (board.isWalkable(id, diceDirection)) { // The result is walkable - moveFlag =1; // mark the successful move - // Get next tile - Position next = new Position(Position.toRow(id), Position.toCol(id), diceDirection); - ret[0] = next.getId(); // Update player's and return data - ret[1] = y = next.getRow(); - ret[2] = x = next.getCol(); - // In case of a champion player, try also to pick a supply - if (champion && (ret[3] = board.tryPickSupply(next.getId())) != Const.noSupply) { - supplyFlag =1; // mark the successful supply pickup - ++score; // keep score - } - ++dirCounter[diceDirection]; // update direction counters - board.updateMove(ret, playerId); + int diceDirection; + do + diceDirection = board.dice(); // throw the dice + while (!board.isWalkable(id, diceDirection)); + moveFlag =1; // mark the successful move + // Get next tile + Position next = new Position(Position.toRow(id), Position.toCol(id), diceDirection); + ret[MOVE_TILE_ID] = next.getId(); // Update move's return data + ret[MOVE_ROW] = y = next.getRow(); + ret[MOVE_COLUMN] = x = next.getCol(); + ret[MOVE_DICE] = diceDirection; + // In case of a champion player, try also to pick a supply + if (champion && (board.tryPickSupply(next.getId()) != Const.noSupply)) { + supplyFlag =1; // mark the successful supply pickup + ++score; // keep score } + ++dirCounter[diceDirection]; // update direction counters + board.updateMove(ret, playerId); // update path Integer[] p = { - ret[0], diceDirection, moveFlag, supplyFlag, + ret[MOVE_TILE_ID], diceDirection, moveFlag, supplyFlag, dirCounter[Direction.UP], dirCounter[Direction.RIGHT], dirCounter[Direction.DOWN], dirCounter[Direction.LEFT], Const.noSupply, Const.noOpponent };