Average Density: 0.01
  1 package nl.tudelft.jpacman.npc;
  2 
  3 import nl.tudelft.jpacman.board.Direction;
  4 import nl.tudelft.jpacman.board.Square;
  5 import nl.tudelft.jpacman.board.Unit;
  6 import nl.tudelft.jpacman.sprite.Sprite;
  7 
  8 import java.util.ArrayList;
  9 import java.util.List;
 10 import java.util.Map;
 11 import java.util.Optional;
 12 import java.util.Random;
 13 
 14 /**
 15  * A non-player unit.
 16  *
 17  * @author Jeroen Roosen
 18  */
 19 public abstract class Ghost extends Unit {
 20     /**
 21      * The sprite map, one sprite for each direction.
 22      */
 23     private final Map<Direction, Sprite> sprites;
 24 
 25     /**
 26      * The base move interval of the ghost.
 27      */
 28     private final int moveInterval;
 29 
 30     /**
 31      * The random variation added to the {@link #moveInterval}.
 32      */
 33     private final int intervalVariation;
 34 
 35     /**
 36      * Calculates the next move for this unit and returns the direction to move
 37      * in.
 38      * <p>
 39      * Precondition: The NPC occupies a square (hasSquare() holds).
 40      *
 41      * @return The direction to move in, or <code>null</code> if no move could
 42      * be devised.
 43      */
 44     public Direction nextMove() {
 45         return nextAiMove().orElseGet(this::randomMove);
 46     }
 47 
 48     /**
 49      * Tries to calculate a move based on the behaviour of the npc.
 50      *
 51      * @return an optional containing the move or empty if the current state of the game
 52      * makes the ai move impossible
 53      */
 54     public abstract Optional<Direction> nextAiMove();
 55 
 56     /**
 57      * Creates a new ghost.
 58      *
 59      * @param spriteMap         The sprites for every direction.
 60      * @param moveInterval      The base interval of movement.
 61      * @param intervalVariation The variation of the interval.
 62      */
 63     protected Ghost(Map<Direction, Sprite> spriteMap, int moveInterval, int intervalVariation) {
 64         this.sprites = spriteMap;
 65         this.intervalVariation = intervalVariation;
 66         this.moveInterval = moveInterval;
 67     }
 68 
 69     @Override
 70     public Sprite getSprite() {
 71         return sprites.get(getDirection());
 72     }
 73 
 74     /**
 75      * The time that should be taken between moves.
 76      *
 77      * @return The suggested delay between moves in milliseconds.
 78      */
 79     public long getInterval() {
 80         return this.moveInterval + new Random().nextInt(this.intervalVariation);
 81     }
 82 
 83     /**
 84      * Determines a possible move in a random direction.
 85      *
 86      * @return A direction in which the ghost can move, or <code>null</code> if
 87      * the ghost is shut in by inaccessible squares.
 88      */
 89     protected Direction randomMove() {
 90         Square square = getSquare();
 91         List<Direction> directions = new ArrayList<>();
 92         for (Direction direction : Direction.values()) {
 93             if (square.getSquareAt(direction).isAccessibleTo(this)) {
 94                 directions.add(direction);
 95             }
 96         }
 97         if (directions.isEmpty()) {
 98             return null;
 99         }
100         int i = new Random().nextInt(directions.size());
101         return directions.get(i);
102     }
103 }