2020-02-22 14:43:24 +01:00
|
|
|
package inf112.fiasko.roborally.objects;
|
2020-02-22 14:40:00 +01:00
|
|
|
|
2020-02-22 23:27:59 +01:00
|
|
|
import inf112.fiasko.roborally.element_properties.Direction;
|
|
|
|
import inf112.fiasko.roborally.element_properties.Position;
|
|
|
|
import inf112.fiasko.roborally.element_properties.RobotID;
|
|
|
|
import inf112.fiasko.roborally.element_properties.TileType;
|
2020-02-22 14:40:00 +01:00
|
|
|
|
|
|
|
import java.util.ArrayList;
|
2020-02-22 23:27:59 +01:00
|
|
|
import java.util.HashMap;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.Map;
|
2020-02-22 14:40:00 +01:00
|
|
|
|
2020-02-22 14:53:10 +01:00
|
|
|
/**
|
|
|
|
* This class represents a board
|
|
|
|
*/
|
2020-02-22 14:40:00 +01:00
|
|
|
public class Board {
|
2020-02-22 23:27:59 +01:00
|
|
|
private int boardHeight;
|
|
|
|
private int boardWidth;
|
|
|
|
private IGrid<Wall> walls;
|
|
|
|
private IGrid<Tile> tiles;
|
|
|
|
private Map<RobotID, Robot> robots;
|
2020-02-22 14:40:00 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Initializes the board
|
2020-02-22 23:27:59 +01:00
|
|
|
* @param tiles A grid containing all tiles
|
|
|
|
* @param walls A grid containing all walls
|
|
|
|
* @param robots A list of all robots in the game
|
|
|
|
*/
|
|
|
|
public Board(IGrid<Tile> tiles, IGrid<Wall> walls, List<Robot> robots) {
|
|
|
|
if (walls.getWidth() != tiles.getWidth() || walls.getHeight() != tiles.getHeight()) {
|
|
|
|
throw new IllegalArgumentException("The grids in the input don't have the same dimensions.");
|
|
|
|
}
|
|
|
|
this.robots = new HashMap<>();
|
|
|
|
for (Robot robot : robots) {
|
|
|
|
if (this.robots.get(robot.getRobotId()) != null) {
|
|
|
|
throw new IllegalArgumentException("There can't be two robots with the same robot id.");
|
|
|
|
}
|
|
|
|
this.robots.put(robot.getRobotId(), robot);
|
|
|
|
}
|
|
|
|
this.boardWidth = tiles.getWidth();
|
|
|
|
this.boardHeight = tiles.getHeight();
|
|
|
|
this.walls = walls;
|
|
|
|
this.tiles = tiles;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets the height of the board
|
|
|
|
* @return The height of the board
|
2020-02-22 14:40:00 +01:00
|
|
|
*/
|
2020-02-22 23:27:59 +01:00
|
|
|
public int getBoardHeight() {
|
|
|
|
return boardHeight;
|
2020-02-22 14:40:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-02-22 23:27:59 +01:00
|
|
|
* Gets the width of the board
|
|
|
|
* @return The width of the board
|
|
|
|
*/
|
|
|
|
public int getBoardWidth() {
|
|
|
|
return boardWidth;
|
|
|
|
}
|
|
|
|
|
2020-02-23 20:26:11 +01:00
|
|
|
/**
|
|
|
|
* Gets all alive robots from the board
|
|
|
|
* @return A list of alive robots
|
|
|
|
*/
|
|
|
|
public List<Robot> getAliveRobots() {
|
|
|
|
return new ArrayList<>(robots.values());
|
|
|
|
}
|
|
|
|
|
2020-02-24 18:07:26 +01:00
|
|
|
/**
|
|
|
|
* Gets all the tiles from the board
|
|
|
|
* @return A list of all tiles on the board
|
|
|
|
*/
|
|
|
|
public List<Tile> getTiles() {
|
|
|
|
return getAllElementsFromGrid(tiles);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets all the walls from the board
|
|
|
|
* @return A list of all the walls on the board
|
|
|
|
*/
|
|
|
|
public List<Wall> getWalls() {
|
|
|
|
return getAllElementsFromGrid(walls);
|
|
|
|
}
|
|
|
|
|
2020-02-22 23:27:59 +01:00
|
|
|
/**
|
|
|
|
* Removes a dead robot from the board over to the dead robot list
|
2020-02-22 14:40:00 +01:00
|
|
|
* @param robot the dead robot
|
|
|
|
*/
|
2020-02-22 23:27:59 +01:00
|
|
|
public void removeDeadRobotFromBoard(Robot robot) {
|
|
|
|
robots.remove(robot.getRobotId());
|
2020-02-22 14:40:00 +01:00
|
|
|
}
|
2020-02-22 23:27:59 +01:00
|
|
|
|
2020-02-23 20:10:28 +01:00
|
|
|
/**
|
|
|
|
* Rotates a robot to the right
|
|
|
|
* @param robotID The id of the robot to rotate
|
|
|
|
*/
|
|
|
|
public void rotateRobotLeft(RobotID robotID) {
|
|
|
|
Robot robot = robots.get(robotID);
|
|
|
|
Direction newDirection = Direction.getLeftRotatedDirection(robot.getFacingDirection());
|
|
|
|
robot.setFacingDirection(newDirection);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Rotates a robot to the left
|
|
|
|
* @param robotID The id of the robot to rotate
|
|
|
|
*/
|
|
|
|
public void rotateRobotRight(RobotID robotID) {
|
|
|
|
Robot robot = robots.get(robotID);
|
|
|
|
Direction newDirection = Direction.getRightRotatedDirection(robot.getFacingDirection());
|
|
|
|
robot.setFacingDirection(newDirection);
|
|
|
|
}
|
|
|
|
|
2020-02-22 23:27:59 +01:00
|
|
|
/**
|
2020-02-25 17:45:39 +01:00
|
|
|
* Moves a robot one unit forward according to the direction it's currently facing
|
|
|
|
* @param robotID The robot to move
|
|
|
|
*/
|
|
|
|
public void moveRobotForward(RobotID robotID) {
|
|
|
|
moveRobot(robotID, robots.get(robotID).getFacingDirection());
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-02-22 23:27:59 +01:00
|
|
|
* Moves a robot one unit in a specified direction
|
|
|
|
* @param robotID ID of the robot to move
|
|
|
|
* @param direction The direction to move the robot
|
|
|
|
* @return True if the robot moved away from its old position
|
|
|
|
*/
|
|
|
|
public boolean moveRobot(RobotID robotID, Direction direction) {
|
|
|
|
Robot robot = robots.get(robotID);
|
|
|
|
Position robotPosition = robot.getPosition();
|
|
|
|
Position newPosition = getNewPosition(robotPosition, direction);
|
|
|
|
//Robot tried to go outside of the map. Kill it.
|
2020-02-23 00:03:20 +01:00
|
|
|
if (killRobotIfGoesOutsideMap(robot, newPosition)) {
|
2020-02-22 23:27:59 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
//There is a wall blocking the robot. It can't proceed.
|
2020-02-23 00:03:20 +01:00
|
|
|
if (robotMoveIsStoppedByWall(robotPosition, newPosition, direction)) {
|
2020-02-22 23:27:59 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
//If another robot is blocking this robot's path, try to shove it.
|
|
|
|
if (hasRobotOnPosition(newPosition)) {
|
|
|
|
RobotID otherRobotID = getRobotOnPosition(newPosition);
|
|
|
|
if (otherRobotID != null && !moveRobot(otherRobotID, direction)) {
|
2020-02-23 20:30:57 +01:00
|
|
|
//The other robot can't be shoved. Give up.
|
2020-02-22 23:27:59 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2020-02-23 00:03:20 +01:00
|
|
|
robot.setPosition(newPosition);
|
2020-02-23 20:30:57 +01:00
|
|
|
//Some tiles may kill the robot if stepped on.
|
|
|
|
killRobotIfStepsOnDangerousTile(robot, newPosition);
|
2020-02-23 00:03:20 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks if a potential robot move would be blocked by a wall
|
|
|
|
* @param robotPosition The current position of the robot
|
|
|
|
* @param newPosition The position the robot is trying to move to
|
|
|
|
* @param direction The direction the robot is going
|
|
|
|
* @return True if a wall would stop its path
|
|
|
|
*/
|
|
|
|
private boolean robotMoveIsStoppedByWall(Position robotPosition, Position newPosition, Direction direction) {
|
|
|
|
return hasWallFacing(robotPosition, direction) ||
|
|
|
|
hasWallFacing(newPosition, Direction.getReverseDirection(direction));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks if the robot is about to step outside of the board, and kills it if it does
|
|
|
|
* @param robot The robot attempting to move
|
|
|
|
* @param newPosition The position the robot is attempting to move to
|
|
|
|
* @return True if the robot was killed for leaving the board
|
|
|
|
*/
|
|
|
|
private boolean killRobotIfGoesOutsideMap(Robot robot, Position newPosition) {
|
|
|
|
if (newPosition.getXCoordinate() < 0
|
|
|
|
|| newPosition.getXCoordinate() >= boardWidth
|
|
|
|
|| newPosition.getYCoordinate() < 0
|
|
|
|
|| newPosition.getYCoordinate() >= boardHeight) {
|
|
|
|
killRobot(robot);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks the tile the robot is about to step on and kills it if the tile is dangerous
|
|
|
|
* @param robot The robot attempting to move
|
|
|
|
* @param newPosition The position the robot is attempting to move to
|
|
|
|
*/
|
2020-02-23 20:30:57 +01:00
|
|
|
private void killRobotIfStepsOnDangerousTile(Robot robot, Position newPosition) {
|
2020-02-22 23:27:59 +01:00
|
|
|
Tile tileRobotStepsOn = tiles.getElement(newPosition.getXCoordinate(), newPosition.getYCoordinate());
|
|
|
|
if (tileRobotStepsOn == null) {
|
|
|
|
throw new IllegalArgumentException("The game board is missing a tile. This should not happen.");
|
|
|
|
}
|
|
|
|
TileType tileTypeRobotStepsOn = tileRobotStepsOn.getTileType();
|
|
|
|
if (tileTypeRobotStepsOn == TileType.HOLE || tileTypeRobotStepsOn == TileType.DEATH_TILE) {
|
|
|
|
killRobot(robot);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Kills the robot
|
|
|
|
*
|
|
|
|
* If the robot steps outside of the board, steps on a hole or takes too much damage, this method should be used to
|
|
|
|
* properly dispose of the robot until the next round.
|
|
|
|
*
|
|
|
|
* @param robot The robot to kill
|
|
|
|
*/
|
|
|
|
private void killRobot(Robot robot) {
|
2020-02-25 15:48:34 +01:00
|
|
|
robot.setAmountOfLives(robot.getAmountOfLives() - 1);
|
2020-02-22 23:27:59 +01:00
|
|
|
removeDeadRobotFromBoard(robot);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a robot id for a robot on a specific position if such a robot exists
|
|
|
|
* @param position The position to check
|
|
|
|
* @return The robot id of the robot on the position or null if there is no robot there
|
|
|
|
*/
|
|
|
|
private RobotID getRobotOnPosition(Position position) {
|
|
|
|
for (RobotID robotID : robots.keySet()) {
|
|
|
|
Robot robot = robots.get(robotID);
|
|
|
|
if (position.equals(robot.getPosition())) {
|
|
|
|
return robotID;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks whether there exists a robot on a specific position
|
|
|
|
* @param position The position to check
|
|
|
|
* @return True if there is a robot on the specified position
|
|
|
|
*/
|
|
|
|
private boolean hasRobotOnPosition(Position position) {
|
|
|
|
return getRobotOnPosition(position) != null;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks whether a position has a wall facing a specific direction
|
|
|
|
* @param position The position to check
|
|
|
|
* @param direction The direction of the wall to check for
|
|
|
|
* @return True if there is a wall on the position facing the input direction
|
|
|
|
*/
|
|
|
|
private boolean hasWallFacing(Position position, Direction direction) {
|
|
|
|
Wall wall = walls.getElement(position.getXCoordinate(), position.getYCoordinate());
|
|
|
|
if (wall == null) {
|
|
|
|
return false;
|
|
|
|
}
|
2020-02-23 20:10:28 +01:00
|
|
|
int wallDirectionId = wall.getDirection().getDirectionID();
|
|
|
|
if (wallDirectionId % 2 == 0) {
|
|
|
|
return (wallDirectionId % 8) + 1 == direction.getDirectionID()
|
|
|
|
|| (((wallDirectionId - 2) + 8) % 8) + 1 == direction.getDirectionID();
|
|
|
|
} else {
|
|
|
|
return wall.getDirection() == direction;
|
2020-02-22 23:27:59 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets the position 1 unit in a specific direction from another position
|
|
|
|
* @param oldPosition The old/current position of the element
|
|
|
|
* @param direction The direction to move the element
|
|
|
|
* @return The new position of the element
|
|
|
|
*/
|
|
|
|
private Position getNewPosition(Position oldPosition, Direction direction) {
|
|
|
|
switch (direction) {
|
|
|
|
case NORTH:
|
|
|
|
return new Position(oldPosition.getXCoordinate(), oldPosition.getYCoordinate() - 1);
|
2020-02-24 22:27:19 +01:00
|
|
|
case SOUTH:
|
|
|
|
return new Position(oldPosition.getXCoordinate(), oldPosition.getYCoordinate() + 1);
|
2020-02-22 23:27:59 +01:00
|
|
|
case EAST:
|
|
|
|
return new Position(oldPosition.getXCoordinate() + 1, oldPosition.getYCoordinate());
|
|
|
|
case WEST:
|
|
|
|
return new Position(oldPosition.getXCoordinate() - 1, oldPosition.getYCoordinate());
|
|
|
|
default:
|
|
|
|
throw new IllegalArgumentException("It's not possible to move in that direction.");
|
|
|
|
}
|
|
|
|
}
|
2020-02-24 18:07:26 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets all elements on a grid
|
|
|
|
* @param grid The grid to get elements from
|
|
|
|
* @param <K> The type of the elements int the grid
|
|
|
|
* @return A list containing all the elements in the grid
|
|
|
|
*/
|
|
|
|
private <K> List<K> getAllElementsFromGrid(IGrid<K> grid) {
|
|
|
|
List<K> elements = new ArrayList<>();
|
2020-02-24 22:27:19 +01:00
|
|
|
for (int y = grid.getHeight() - 1; y >= 0; y--) {
|
|
|
|
for (int x = 0; x < grid.getWidth(); x++) {
|
2020-02-24 18:07:26 +01:00
|
|
|
elements.add(grid.getElement(x, y));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return elements;
|
|
|
|
}
|
2020-02-22 14:40:00 +01:00
|
|
|
}
|