diff --git a/src/main/java/inf112/fiasko/roborally/objects/Board.java b/src/main/java/inf112/fiasko/roborally/objects/Board.java index 6c17645..f30c93f 100644 --- a/src/main/java/inf112/fiasko/roborally/objects/Board.java +++ b/src/main/java/inf112/fiasko/roborally/objects/Board.java @@ -316,7 +316,7 @@ public class Board { * @param direction The direction something is going * @return True if a wall would stop its path */ - private boolean moveIsStoppedByWall(Position robotPosition, Position newPosition, Direction direction) { + boolean moveIsStoppedByWall(Position robotPosition, Position newPosition, Direction direction) { return hasWallFacing(robotPosition, direction) || (isValidPosition(newPosition) && hasWallFacing(newPosition, Direction.getReverseDirection(direction))); } diff --git a/src/main/java/inf112/fiasko/roborally/objects/RoboRallyGame.java b/src/main/java/inf112/fiasko/roborally/objects/RoboRallyGame.java index 4ed8329..386aadd 100644 --- a/src/main/java/inf112/fiasko/roborally/objects/RoboRallyGame.java +++ b/src/main/java/inf112/fiasko/roborally/objects/RoboRallyGame.java @@ -9,7 +9,9 @@ import inf112.fiasko.roborally.utility.BoardLoaderUtil; import inf112.fiasko.roborally.utility.DeckLoaderUtil; import java.io.IOException; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.concurrent.TimeUnit; import java.util.function.Predicate; @@ -22,6 +24,8 @@ public class RoboRallyGame implements IDrawableGame { private List> conveyorBelts; private List> fastConveyorBelts; private List playerList; + private List> blacklistedTiles = new ArrayList<>(); + private List> whitelistedTiles = new ArrayList<>(); public RoboRallyGame(boolean debug) { if (debug) { @@ -294,6 +298,7 @@ public class RoboRallyGame implements IDrawableGame { List> conveyorBeltsWithRobotsThatShouldMove = conveyorBeltsThatCanMoveWithoutConflict(conveyorBelts); for (BoardElementContainer conveyorBelt : conveyorBeltsWithRobotsThatShouldMove) { + Direction currentDirection = conveyorBelt.getElement().getDirection(); RobotID robot = gameBoard.getRobotOnPosition(conveyorBelt.getPosition()); Position newPosition = gameBoard.getNewPosition(conveyorBelt.getPosition(), currentDirection); @@ -303,56 +308,157 @@ public class RoboRallyGame implements IDrawableGame { } } + /** + * Finds conveyor belts that can move without conflict + * @param conveyorBelts that should be checked + * @return List of conveyor belts that can move robots without conflict + */ private List> conveyorBeltsThatCanMoveWithoutConflict( List> conveyorBelts) { - List> nonConflictConveyorBelts = new ArrayList<>(); + List> conveyorBeltsWithRobotsOn = new ArrayList<>(); + whitelistedTiles.clear(); + blacklistedTiles.clear(); + for (BoardElementContainer conveyorBelt : conveyorBelts) { if (gameBoard.hasRobotOnPosition(conveyorBelt.getPosition())) { - nonConflictConveyorBelts.add(conveyorBelt); + conveyorBeltsWithRobotsOn.add(conveyorBelt); } } - for (BoardElementContainer conveyorBeltWithRobot : nonConflictConveyorBelts) { - Position conveyorBeltPosition = conveyorBeltWithRobot.getPosition(); - Tile conveyorBeltTile = conveyorBeltWithRobot.getElement(); - Position newPosition = gameBoard.getNewPosition(conveyorBeltPosition, conveyorBeltTile.getDirection()); - Tile nextTile = gameBoard.getTileOnPosition(newPosition); - - Position beyondNextPositionStraight = gameBoard.getNewPosition(newPosition, conveyorBeltTile.getDirection()); - Tile beyondNextTileStraight = gameBoard.getTileOnPosition(beyondNextPositionStraight); - - Position beyondNextPositionLeft = gameBoard.getNewPosition(newPosition, - Direction.getLeftRotatedDirection(conveyorBeltTile.getDirection())); - Tile beyondNextTileLeft = gameBoard.getTileOnPosition(beyondNextPositionLeft); - - Position beyondNextPositionRight = gameBoard.getNewPosition(newPosition, - Direction.getRightRotatedDirection(conveyorBeltTile.getDirection())); - Tile beyondNextTileRight = gameBoard.getTileOnPosition(beyondNextPositionRight); - - - - if (conveyorBeltTile.getDirection() == Direction.getReverseDirection(nextTile.getDirection()) && - nonConflictConveyorBelts.contains(new BoardElementContainer<>(nextTile, newPosition))) { - nonConflictConveyorBelts.remove(conveyorBeltWithRobot); + List> listOfRow = new ArrayList<>(); + for (BoardElementContainer conveyorBeltWithRobot : conveyorBeltsWithRobotsOn) { + if (blacklistedTiles.contains(conveyorBeltWithRobot) || + whitelistedTiles.contains((conveyorBeltWithRobot))) { + continue; } - else if (conveyorBeltTile.getDirection() == Direction.getReverseDirection( - beyondNextTileStraight.getDirection()) && nonConflictConveyorBelts.contains( - new BoardElementContainer<>(beyondNextTileStraight, beyondNextPositionStraight))) { - nonConflictConveyorBelts.remove(conveyorBeltWithRobot); - } - else if (conveyorBeltTile.getDirection() == Direction.getLeftRotatedDirection( - beyondNextTileLeft.getDirection()) && nonConflictConveyorBelts.contains( - new BoardElementContainer<>(beyondNextTileLeft, beyondNextPositionLeft))) { - nonConflictConveyorBelts.remove(conveyorBeltWithRobot); - } - else if (conveyorBeltTile.getDirection() == Direction.getRightRotatedDirection( - beyondNextTileRight.getDirection()) && nonConflictConveyorBelts.contains( - new BoardElementContainer<>(beyondNextTileRight, beyondNextPositionRight))) { - nonConflictConveyorBelts.remove(conveyorBeltWithRobot); + + BoardElementContainer lastInRow = findLastRobotInRow (conveyorBeltWithRobot, conveyorBeltsWithRobotsOn); + + List> results = findFirstRobotInRow(lastInRow, conveyorBeltsWithRobotsOn, + listOfRow); + + for (BoardElementContainer result : results) { + if (!whitelistedTiles.contains(result)) { + whitelistedTiles.add(0, result); + } } } - return nonConflictConveyorBelts; + return whitelistedTiles; + } + + /** + * Recursive function to find all robots in a row that should move, and blacklists those that should not + * @param currentConveyorBelt The current conveyor belt + * @param conveyorBeltsWithRobotsOn List of conveyor belts that have robots on them + * @param listOfRow List of conveyor belts in a row with robots on them + * @return listOfRow + */ + private List> findFirstRobotInRow(BoardElementContainer currentConveyorBelt, + List> conveyorBeltsWithRobotsOn, + List> listOfRow) { + Position nextPosition = gameBoard.getNewPosition(currentConveyorBelt.getPosition(), + currentConveyorBelt.getElement().getDirection()); + Direction nextDirection = gameBoard.getTileOnPosition(nextPosition).getDirection(); + Tile nextTile = gameBoard.getTileOnPosition(nextPosition); + BoardElementContainer nextElementContainer = new BoardElementContainer<>(nextTile, nextPosition); + List> pointingNeighbours = listOfConveyorBeltsWithRobotPointingAtTile(true, + nextElementContainer, conveyorBeltsWithRobotsOn); + + listOfRow.add(currentConveyorBelt); + + if (blacklistedTiles.contains(nextElementContainer)) { + blacklistedTiles.addAll(listOfRow); + listOfRow.clear(); + } else if (currentConveyorBelt.getElement().getDirection() == Direction.getReverseDirection(nextDirection) && + conveyorBeltsWithRobotsOn.contains(nextElementContainer)) { + blacklistedTiles.addAll(listOfRow); + blacklistedTiles.add(nextElementContainer); + listOfRow.clear(); + } else if ((!conveyorBelts.contains(nextElementContainer)) && gameBoard.hasRobotOnPosition(nextPosition)) { + blacklistedTiles.addAll(listOfRow); + listOfRow.clear(); + } else if (gameBoard.moveIsStoppedByWall(currentConveyorBelt.getPosition(), nextPosition, + currentConveyorBelt.getElement().getDirection())) { + blacklistedTiles.addAll(listOfRow); + listOfRow.clear(); + } else if (pointingNeighbours.size() > 0) { + blacklistedTiles.addAll(pointingNeighbours); + blacklistedTiles.addAll(listOfRow); + listOfRow.clear(); + } else if ((conveyorBeltsWithRobotsOn.contains(nextElementContainer))) { + listOfRow = findFirstRobotInRow(nextElementContainer, conveyorBeltsWithRobotsOn, listOfRow); + } + return listOfRow; + } + + /** + * Recursive function that finds the last robot in a row with conveyor belts without conflicts + * @param currentConveyorBelt The current conveyor belt + * @param conveyorBeltsWithRobotsOn List with conveyor belts that have robots on them + * @return The last conveyor belt with a robot without conflict in a row + */ + private BoardElementContainer findLastRobotInRow(BoardElementContainer currentConveyorBelt, + List> conveyorBeltsWithRobotsOn) { + List> listOfConveyorBeltsWithRobotPointingAtTile = + listOfConveyorBeltsWithRobotPointingAtTile(false, currentConveyorBelt, + conveyorBeltsWithRobotsOn); + int sizeOfPointingList = listOfConveyorBeltsWithRobotPointingAtTile.size(); + if (sizeOfPointingList == 0) { + return currentConveyorBelt; + } else if (sizeOfPointingList == 1) { + return findLastRobotInRow(listOfConveyorBeltsWithRobotPointingAtTile.get(0), conveyorBeltsWithRobotsOn); + } else { + blacklistedTiles.addAll(listOfConveyorBeltsWithRobotPointingAtTile); + return currentConveyorBelt; + } + } + + /** + * Finds all neighbouring conveyor belt tiles with robots that are pointing on the current tile + * @param forward True if looking forward, false otherwise + * @param currentTile The current tile + * @param conveyorBeltsWithRobots List with conveyor belts that have robots on them + * @return A list of the neighbouring conveyor belt tiles with robots that are pointing on the current tile + */ + private List> listOfConveyorBeltsWithRobotPointingAtTile(Boolean forward, + BoardElementContainer currentTile, + List> conveyorBeltsWithRobots) { + List> possibleConflictConveyorBelts = new ArrayList<>(); + Tile conveyorBeltTile = currentTile.getElement(); + Position currentPosition = currentTile.getPosition(); + Direction currentDirection; + + if (forward) { + currentDirection = conveyorBeltTile.getDirection(); + } else currentDirection = Direction.getReverseDirection(conveyorBeltTile.getDirection()); + + Position nextPositionStraight = gameBoard.getNewPosition(currentPosition, currentDirection); + Tile nextTileStraight = gameBoard.getTileOnPosition(nextPositionStraight); + Position nextPositionLeft = gameBoard.getNewPosition(currentPosition, + Direction.getLeftRotatedDirection(currentDirection)); + Tile nextTileLeft = gameBoard.getTileOnPosition(nextPositionLeft); + Position nextPositionRight = gameBoard.getNewPosition(currentPosition, + Direction.getRightRotatedDirection(currentDirection)); + Tile nextTileRight = gameBoard.getTileOnPosition(nextPositionRight); + + BoardElementContainer rightOfCurrent = new BoardElementContainer<>(nextTileRight, nextPositionRight); + BoardElementContainer leftOfCurrent = new BoardElementContainer<>(nextTileLeft, nextPositionLeft); + BoardElementContainer inFrontOfCurrent = new BoardElementContainer<>(nextTileStraight, nextPositionStraight); + + if (currentDirection == Direction.getReverseDirection( + nextTileStraight.getDirection()) && conveyorBeltsWithRobots.contains(inFrontOfCurrent)) { + possibleConflictConveyorBelts.add(inFrontOfCurrent); + } + if (currentDirection == Direction.getLeftRotatedDirection( + nextTileLeft.getDirection()) && conveyorBeltsWithRobots.contains(leftOfCurrent)) { + possibleConflictConveyorBelts.add(leftOfCurrent); + } + if (currentDirection == Direction.getRightRotatedDirection( + nextTileRight.getDirection()) && conveyorBeltsWithRobots.contains(rightOfCurrent)) { + possibleConflictConveyorBelts.add(rightOfCurrent); + } + return possibleConflictConveyorBelts; } /**