Oppdaterer brettet med nødvendige metoder for å kunne flytte en robot

Legger til tester for brettet
This commit is contained in:
Kristian Knarvik 2020-02-22 23:27:59 +01:00
parent 248b842536
commit 544e5d9e04
2 changed files with 255 additions and 15 deletions

View File

@ -1,36 +1,211 @@
package inf112.fiasko.roborally.objects;
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;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* This class represents a board
*/
public class Board {
private Grid walls;
private Grid otherObjects;
private ArrayList<Robot> deadRobots = new ArrayList<>();
private ArrayList<Robot> aliveRobots;
private int boardHeight;
private int boardWidth;
private IGrid<Wall> walls;
private IGrid<Tile> tiles;
private Map<RobotID, Robot> robots;
private List<Robot> deadRobots;
/**
* Initializes the board
* @param walls a grid containing all the walls
* @param otherObjects a grid containing all the other Objects like flags and conveyor belts
* @param aliveRobots a list of all the robots that are currently alive
* @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(Grid walls, Grid otherObjects, ArrayList aliveRobots){
this.walls=walls;
this.otherObjects=otherObjects;
this.aliveRobots=aliveRobots;
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.deadRobots = new ArrayList<>();
this.boardWidth = tiles.getWidth();
this.boardHeight = tiles.getHeight();
this.walls = walls;
this.tiles = tiles;
}
/**
* Removes a dead robot from the board over to the dead robot list.
* Gets the height of the board
* @return The height of the board
*/
public int getBoardHeight() {
return boardHeight;
}
/**
* Gets the width of the board
* @return The width of the board
*/
public int getBoardWidth() {
return boardWidth;
}
/**
* Moves all dead robots to their backups and makes them part of the board again
*/
public void respawnRobots() {
//TODO: Account for several robots re-spawning at same backup
for (Robot robot : deadRobots) {
robot.setPosition(robot.getBackupPosition());
robots.put(robot.getRobotId(), robot);
}
deadRobots = new ArrayList<>();
}
/**
* Removes a dead robot from the board over to the dead robot list
* @param robot the dead robot
*/
public void removeDeadRobotFromBoard(Robot robot){
aliveRobots.remove(robot);
public void removeDeadRobotFromBoard(Robot robot) {
robots.remove(robot.getRobotId());
deadRobots.add(robot);
}
/**
* 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.
if (newPosition.getXCoordinate() < 0
|| newPosition.getXCoordinate() >= boardWidth
|| newPosition.getYCoordinate() < 0
|| newPosition.getYCoordinate() >= boardHeight) {
killRobot(robot);
return true;
}
//There is a wall blocking the robot. It can't proceed.
if (hasWallFacing(robotPosition, direction) ||
hasWallFacing(newPosition, Direction.getReverseDirection(direction))) {
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)) {
return false;
}
}
//Some tiles may kill the robot if stepped on.
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);
return true;
}
robot.setPosition(newPosition);
return true;
}
/**
* 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) {
//TODO: Must remove a life from the robot/player
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;
}
switch (wall.getDirection()) {
case NORTH_EAST:
return direction == Direction.NORTH || direction == Direction.EAST;
case NORTH_WEST:
return direction == Direction.NORTH || direction == Direction.WEST;
case SOUTH_WEST:
return direction == Direction.SOUTH || direction == Direction.WEST;
case SOUTH_EAST:
return direction == Direction.SOUTH || direction == Direction.EAST;
}
return wall.getDirection() == direction;
}
/**
* 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) {
//TODO: Make sure we're accounting for the flipped y axis in libgdx
switch (direction) {
case NORTH:
return new Position(oldPosition.getXCoordinate(), oldPosition.getYCoordinate() + 1);
case SOUTH:
return new Position(oldPosition.getXCoordinate(), oldPosition.getYCoordinate() - 1);
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.");
}
}
}

View File

@ -0,0 +1,65 @@
package inf112.fiasko.roborally.objects;
import inf112.fiasko.roborally.element_properties.*;
import org.junit.Before;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class BoardTest {
private Grid<Tile> tileGrid;
private Grid<Wall> wallGrid;
private Position someValidPosition;
private List<Robot> robotList;
private Board board;
@Before
public void setUp() {
tileGrid = new Grid<>(5, 5, new Tile(TileType.TILE, Direction.NORTH));
wallGrid = new Grid<>(5, 5);
someValidPosition = new Position(2, 2);
robotList = new ArrayList<>();
robotList.add(new Robot(RobotID.ROBOT_1, someValidPosition));
wallGrid.setElement(2, 3, new Wall(WallType.WALL_NORMAL, Direction.SOUTH));
wallGrid.setElement(2, 2, new Wall(WallType.WALL_NORMAL, Direction.EAST));
wallGrid.setElement(1, 2, new Wall(WallType.WALL_CORNER, Direction.NORTH_EAST));
board = new Board(tileGrid, wallGrid, robotList);
}
@Test
public void robotCanMove() {
assertTrue(board.moveRobot(RobotID.ROBOT_1, Direction.SOUTH));
}
@Test
public void robotIsStoppedByWallOnSameTile() {
assertFalse(board.moveRobot(RobotID.ROBOT_1, Direction.EAST));
}
@Test
public void robotIsStoppedByWallOnAdjacentTile() {
assertFalse(board.moveRobot(RobotID.ROBOT_1, Direction.NORTH));
}
@Test
public void robotIsStoppedByCornerWall() {
assertFalse(board.moveRobot(RobotID.ROBOT_1, Direction.WEST));
}
@Test (expected = IllegalArgumentException.class)
public void gridsOfDifferentSizeThrowsError() {
IGrid<Wall> wallGrid = new Grid<>(1, 1);
new Board(tileGrid, wallGrid, robotList);
}
@Test (expected = IllegalArgumentException.class)
public void multipleRobotsWithSameIDThrowsError() {
Robot robot = new Robot(RobotID.ROBOT_1, someValidPosition);
robotList.add(robot);
new Board(tileGrid, wallGrid, robotList);
}
}