/** * @file Tile.java * * @author Christos Choutouridis AEM:8997 * @email cchoutou@ece.auth.gr */ package net.hoo2.auth.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 (x,y) * * @param x The x coordinate to place the Tile * @param y The y 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 */ protected Tile(int x, int y, boolean up, boolean down, boolean left, boolean right) { // Boundary checks assert (x >= 0 && x< Defaults.boardSize) : "X coordinate must be in the range [0, Defaults.boardSize)"; assert (x >= 0 && x< Defaults.boardSize) : "Y coordinate must be in the range [0, Defaults.boardSize)"; // Initialization this.tileId = Position.toID(x, y); this.x =x; this.y =y; 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 */ protected Tile(int id, boolean up, boolean down, boolean left, boolean right) { // Boundary check assert (id >= 0 && id <= Position.toID(Defaults.boardSize-1, Defaults.boardSize-1)) : "TileId must be in the range of [0, Defaults.boardSize^2)"; // Initialization this.tileId = id; this.x =Position.toX(id); this.y =Position.toY(id); this.up = up; this.down = down; this.left = left; this.right = right; } /** * A deep copy constructor. */ protected 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 */ protected Position position () { return new Position (x, y); } /** * Set the position of the tile from a (x, y) pair * @param x The x coordinate of the tile * @param y The y 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 */ protected Position position (int x, int y) { // Boundary checks assert (x >= 0 && x< Defaults.boardSize) : "X coordinate must be in the range [0, Defaults.boardSize)"; assert (x >= 0 && x< Defaults.boardSize) : "Y coordinate must be in the range [0, Defaults.boardSize)"; Position p = new Position (x, y); this.x = x; this.y = y; 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 */ protected int position (int tileId) { // Boundary check assert (tileId >= 0 && tileId <= Position.toID(Defaults.boardSize-1, Defaults.boardSize-1)) : "TileId must be in the range of [0, Defaults.boardSize^2)"; this.x = Position.toX(tileId); this.y = Position.toY(tileId); this.tileId = tileId; return tileId; } /** @return The tileId */ protected int positionId () { return tileId; } /** * Set the tile's walls * @param up Request for north wall (winter is coming) * @param down Request for south wall * @param left Request for west wall * @param right Request for east wall */ protected void setWalls (boolean up, boolean down, boolean left, boolean right) { assert ( ((up?1:0) + (down?1:0) + (left?1:0) + (right?1:0)) <=2 ) : "A tile can have at most 2 walls"; this.up = up; this.down = down; this.left = left; this.right = right; } /** * Checks if the tile has wall in the requested direction * @param direction The direction to check * @return True if there is a wall */ protected 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; } /** @} */ /** * @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. */ /** @{ */ protected int getTileId () { return tileId; } protected int getX () { return x; } protected int getY () { return y; } protected boolean getUp () { return up; } protected boolean getDown () { return down; } protected boolean getLeft () { return left; } protected boolean getRight () { return right; } protected void setTileId(int tileId) { assert (tileId >= 0 && tileId <= Position.toID(Defaults.boardSize-1, Defaults.boardSize-1)) : "TileId must be in the range of [0, Defaults.boardSize^2)"; this.tileId = tileId; this.x = Position.toX(tileId); this.y = Position.toY(tileId); } protected void setX(int x) { assert (x >= 0 && x< Defaults.boardSize) : "X coordinate must be in the range [0, Defaults.boardSize)"; this.x = x; this.tileId = Position.toID(this.x, this.y); } protected void setY(int y) { assert (y >= 0 && y< Defaults.boardSize) : "X coordinate must be in the range [0, Defaults.boardSize)"; this.y = y; this.tileId = Position.toID(this.x, this.y); } protected void setUp(boolean up) { this.up = up; } protected void setDown(boolean down) { this.down = down; } protected void setRight(boolean right) { this.right = right; } protected 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 of the tile as if the board lies in the 1st quadrant */ private int y; /**< The y coordinate 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 */ }