/** * @file Tile.java * * @author * Anastasia Foti AEM:8959 * * * @author * Christos Choutouridis AEM:8997 * */ package host.labyrinth; /** * @brief * This class is the representation of the board's tile * * Tiles are arranged on the board in square shape and they're identified by * an ID. This ID is the linear combination of x and y coordinate of the tile. */ class Tile { /** @name Constructors */ /** @{ */ /** * The main constructor of the Tile constructed from (row,column) * * @param row The row coordinate to place the Tile * @param col The column coordinate to place the Tile * @param up The existence of wall north of the tile * @param down The existence of wall south of the tile * @param left The existence of wall left of the tile * @param right The existence of wall right of the tile */ Tile(int row, int col, boolean up, boolean down, boolean left, boolean right) { // Boundary checks assert (row >= 0 && row< Session.boardSize) : "Row coordinate must be in the range [0, Session.boardSize)"; assert (col >= 0 && col< Session.boardSize) : "Column coordinate must be in the range [0, Session.boardSize)"; // Initialization this.tileId = Position.toID(row, col); this.x =col; this.y =row; this.up = up; this.down = down; this.left = left; this.right = right; } /** * The main constructor of the Tile constructed from tileId * * @param id The tileId to place the Tile * @param up The existence of wall north of the tile * @param down The existence of wall south of the tile * @param left The existence of wall left of the tile * @param right The existence of wall right of the tile */ Tile(int id, boolean up, boolean down, boolean left, boolean right) { // Boundary check assert (id >= 0 && id <= Position.toID(Session.boardSize-1, Session.boardSize-1)) : "TileId must be in the range of [0, Session.boardSize^2)"; // Initialization this.tileId = id; this.x =Position.toCol(id); this.y =Position.toRow(id); this.up = up; this.down = down; this.left = left; this.right = right; } /** * A deep copy constructor. */ Tile (Tile t) { this.tileId = t.tileId; this.x = t.x; this.y = t.y; this.up = t.up; this.down = t.down; this.left = t.left; this.right = t.right; // We achieve deep copy as the members are all primitives. } /** @} */ /** @name Supply's main application interface */ /** @{ */ /** * @return the position of the tile as a Position object * @see Position */ Position position () { return new Position (tileId); } /** * Set the position of the tile from a (row, column) pair * @param row The row coordinate of the tile * @param col The column coordinate of the tile * @return the position of the supply as a Position object * @note This function also returns the supplyId to help in chained expressions. * @see Position */ Position position (int row, int col) { // Boundary checks assert (row >= 0 && row< Session.boardSize) : "Row coordinate must be in the range [0, Session.boardSize)"; assert (col >= 0 && col< Session.boardSize) : "Column coordinate must be in the range [0, Session.boardSize)"; Position p = new Position (row, col); this.x = p.getCol(); // =col; this.y = p.getRow(); // =row; this.tileId = p.getId(); return p; } /** * Set the position of the tile from a tileId * @param tileId The tileId position * @return The position of the supply as Position object * @note This function also returns the supplyId to help in chained expressions. * @see Position */ Position position (int tileId) { // Boundary check assert (tileId >= 0 && tileId <= Position.toID(Session.boardSize-1, Session.boardSize-1)) : "TileId must be in the range of [0, Session.boardSize^2)"; Position p = new Position (tileId); this.x = p.getCol(); this.y = p.getRow(); this.tileId = p.getId(); // =tileId; return p; } /** * Sets the tile's wall in the requested direction. * @param direction The direction for the wall. */ void setWall (int direction) { switch (direction) { case Direction.UP: this.up = true; break; case Direction.DOWN: this.down = true; break; case Direction.LEFT: this.left = true; break; case Direction.RIGHT:this.right = true; break; } } /** * Clears the tile's wall in the requested direction. * @param direction The direction for the wall */ void clearWall (int direction) { switch (direction) { case Direction.UP: this.up = false; break; case Direction.DOWN: this.down = false; break; case Direction.LEFT: this.left = false; break; case Direction.RIGHT:this.right = false; break; } } /** * Checks if the tile has wall in the requested direction * @param direction The direction to check * @return True if there is a wall */ boolean hasWall (int direction) { switch (direction) { case Direction.UP: return up; case Direction.RIGHT: return right; case Direction.DOWN: return down; case Direction.LEFT: return left; } return false; } /** * Checks if the tile has walls and return the number of them * @return The number of walls */ int hasWalls () { return ((up?1:0) + (down?1:0) + (left?1:0) + (right?1:0)); } /** * Utility to check if the tile has a supply. * @param supplies Reference to supply array to check. * @return Const.noSupply if there is no supply or the supplyId if succeed. */ int hasSupply (Supply[] supplies) { for (Supply s: supplies) if (s.position().getId() == position().getId()) return s.getSupplyId(); return Const.noSupply; } /** * Utility to find a supply in the supplies array and removes it. * @param supplies Reference to supply array to check * @param supplyId The supplyId to search. */ void pickSupply (Supply[] supplies, int supplyId) { for (Supply s: supplies) if (s.getSupplyId() == supplyId) s.removeSupply(); } /** @} */ /** * @name Accessor/Mutator interface * @note * Please consider not to use mutator interface. Its the abstraction killer :( * We have added a bit of logic however, in order to make it a bit more safe. */ /** @{ */ int getTileId () { return tileId; } int getX () { return x; } int getY () { return y; } boolean getUp () { return up; } boolean getDown () { return down; } boolean getLeft () { return left; } boolean getRight () { return right; } void setTileId(int tileId) { assert (tileId >= 0 && tileId <= Position.toID(Session.boardSize-1, Session.boardSize-1)) : "TileId must be in the range of [0, Session.boardSize^2)"; this.tileId = tileId; this.x = Position.toCol(tileId); this.y = Position.toRow(tileId); } void setX(int x) { assert (x >= 0 && x< Session.boardSize) : "X(column) coordinate must be in the range [0, Session.boardSize)"; this.x = x; this.tileId = Position.toID(this.x, this.y); } void setY(int y) { assert (y >= 0 && y< Session.boardSize) : "Y(row) coordinate must be in the range [0, Session.boardSize)"; this.y = y; this.tileId = Position.toID(this.x, this.y); } void setUp(boolean up) { this.up = up; } void setDown(boolean down) { this.down = down; } void setRight(boolean right) { this.right = right; } void setLeft(boolean left) { this.left = left; } /** @} */ /** @name Class data */ /** @{ */ private int tileId; /**< * The unique identifier of the tile. This is the linear combination of * x and y coordinates of the tile */ private int x; /**< The x coordinate(column) of the tile as if the board lies in the 1st quadrant */ private int y; /**< The y coordinate(row) of the tile as if the board lies in the 1st quadrant */ private boolean up; /**< Indicator of a wall in the north side of the tile */ private boolean down; /**< Indicator of a wall in the south side of the tile */ private boolean left; /**< Indicator of a wall in the left side of the tile */ private boolean right; /**< Indicator of a wall in the right side of the tile */ /** * @warning * We can calculate tileId from (x,y) so having both (x,y) and tile ID is error * prone and not a good practice. Its easy to get them out of sync(code smell). * We implement it just because its in the requirements of the assignment. * @see Supply.supplyTileId */ /** @} */ }