From 9f316e5b4318eacec15e2949f6db64db2f46ecfc Mon Sep 17 00:00:00 2001 From: Urban Modig Date: Tue, 19 Aug 2025 21:17:36 +0200 Subject: [PATCH] Added Scatter-strategy --- .../urmo/game/collision/CollisionChecker.java | 5 +- .../game/collision/GhostCollisionChecker.java | 29 +++++++- .../se/urmo/game/entities/BlinkyStrategy.java | 4 +- .../java/se/urmo/game/entities/Ghost.java | 53 +++++++++++---- .../se/urmo/game/entities/GhostStrategy.java | 4 +- .../java/se/urmo/game/entities/PacMan.java | 15 ++--- .../se/urmo/game/entities/PinkyStrategy.java | 12 ++-- .../urmo/game/entities/ScatterToTopRight.java | 12 ++++ src/main/java/se/urmo/game/map/GameMap.java | 66 +++++++++---------- .../se/urmo/game/state/GameStateManager.java | 6 +- .../java/se/urmo/game/state/GhostManager.java | 40 +++++++++-- .../java/se/urmo/game/state/PlayingState.java | 2 +- .../se/urmo/game/state/ScatterToTopLeft.java | 15 +++++ 13 files changed, 183 insertions(+), 80 deletions(-) create mode 100644 src/main/java/se/urmo/game/entities/ScatterToTopRight.java create mode 100644 src/main/java/se/urmo/game/state/ScatterToTopLeft.java diff --git a/src/main/java/se/urmo/game/collision/CollisionChecker.java b/src/main/java/se/urmo/game/collision/CollisionChecker.java index b223b2b..639ee92 100644 --- a/src/main/java/se/urmo/game/collision/CollisionChecker.java +++ b/src/main/java/se/urmo/game/collision/CollisionChecker.java @@ -2,6 +2,7 @@ package se.urmo.game.collision; import lombok.extern.slf4j.Slf4j; +import se.urmo.game.main.GamePanel; import se.urmo.game.util.Direction; import se.urmo.game.map.GameMap; @@ -44,7 +45,7 @@ public class CollisionChecker { /** * Applies specific rules to movement - * This for instance makes sure the tunnel left/right works. + * This, for instance, makes sure the tunnel left/right works. * * @param dir * @param pos @@ -55,7 +56,7 @@ public class CollisionChecker { public Point normalizePosition(Direction dir, Point pos, int agent_width, int agent_height) { int x = pos.x; int y = pos.y; - int width = map.getWidth(); + int width = GamePanel.SCREEN_WIDTH; int height = map.getHeight(); // tunnel diff --git a/src/main/java/se/urmo/game/collision/GhostCollisionChecker.java b/src/main/java/se/urmo/game/collision/GhostCollisionChecker.java index 18885e9..849dcea 100644 --- a/src/main/java/se/urmo/game/collision/GhostCollisionChecker.java +++ b/src/main/java/se/urmo/game/collision/GhostCollisionChecker.java @@ -2,10 +2,12 @@ package se.urmo.game.collision; import lombok.extern.slf4j.Slf4j; import se.urmo.game.map.GameMap; +import se.urmo.game.map.MapTile; import se.urmo.game.util.Direction; import java.awt.Point; import java.util.List; +import java.util.stream.Stream; @Slf4j public class GhostCollisionChecker { @@ -16,15 +18,38 @@ public class GhostCollisionChecker { } public List calculateDirectionAlternatives(Point position) { - List intersection = map.directionAlternatives(position); + List intersection = directionAlternatives(position); log.info("Possible travel directions: {}", intersection); return intersection; } + public List directionAlternatives(Point position) { + int row = (position.y - GameMap.OFFSET_Y) / GameMap.MAP_TILESIZE; + int col = (position.x - GameMap.OFFSET_X) / GameMap.MAP_TILESIZE; + + record DirectionCheck(int rowOffset, int colOffset, Direction direction) {} + log.debug("At [{}][{}]", row, col); + return Stream.of( + new DirectionCheck(0, 1, Direction.RIGHT), + new DirectionCheck(0, -1, Direction.LEFT), + new DirectionCheck(1, 0, Direction.DOWN), + new DirectionCheck(-1, 0, Direction.UP) + ) + .filter(dc -> { + int r = row + dc.rowOffset; + int c = col + dc.colOffset; + boolean solid = map.isSolid(r, c); + log.debug("[{}][{}] {} is {}", r, c, dc.direction, solid ? "solid" : " not solid"); + return !solid; + }) + .map(DirectionCheck::direction) + .toList(); + } + public Point canMoveTo(Direction dir, Point pos) { // -1 is because else we endup in next tile Point pp = new Point(pos.x + dir.dx * (GameMap.MAP_TILESIZE/2 - 1), pos.y + dir.dy * (GameMap.MAP_TILESIZE/2 -1) ); - return ! map.isSolid(pp.x, pp.y) ? pos : null; + return ! map.isSolid(pp) ? pos : null; } } diff --git a/src/main/java/se/urmo/game/entities/BlinkyStrategy.java b/src/main/java/se/urmo/game/entities/BlinkyStrategy.java index 8eed1f8..5f38846 100644 --- a/src/main/java/se/urmo/game/entities/BlinkyStrategy.java +++ b/src/main/java/se/urmo/game/entities/BlinkyStrategy.java @@ -1,10 +1,12 @@ package se.urmo.game.entities; +import se.urmo.game.map.GameMap; + import java.awt.Point; public class BlinkyStrategy implements GhostStrategy { @Override - public Point chooseTarget(PacMan pacman) { + public Point chooseTarget(PacMan pacman, GameMap map) { return pacman.getTilePosition(); } } diff --git a/src/main/java/se/urmo/game/entities/Ghost.java b/src/main/java/se/urmo/game/entities/Ghost.java index 0ca723b..4634f24 100644 --- a/src/main/java/se/urmo/game/entities/Ghost.java +++ b/src/main/java/se/urmo/game/entities/Ghost.java @@ -11,7 +11,11 @@ import java.awt.Color; import java.awt.Graphics; import java.awt.Point; import java.awt.image.BufferedImage; +import java.util.Arrays; +import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; @Slf4j public class Ghost { @@ -30,22 +34,25 @@ public class Ghost { private boolean moving = true; private int aniTick = 0; private int aniIndex = 0; + private final GhostStrategy scaterStrategy; + private GhostStrategy currentStrategy; private final BufferedImage[] animation; private int movementTick = 0; private Direction direction; private Direction prevDirection; private GhostMode mode; - private GhostStrategy currentStrategy; - public Ghost(GhostCollisionChecker collisionChecker, GhostStrategy strategy, BufferedImage[] animation) { + public Ghost(GhostCollisionChecker collisionChecker, GhostStrategy strategy, GhostStrategy scaterStrategy, BufferedImage[] animation) { this.collisionChecker = collisionChecker; this.chaseStrategy = strategy; - this.currentStrategy = strategy; + this.scaterStrategy = scaterStrategy; this.animation = animation; position = new Point( 13 * GameMap.MAP_TILESIZE + (GameMap.MAP_TILESIZE / 2) + GameMap.OFFSET_X, 4 * GameMap.MAP_TILESIZE + (GameMap.MAP_TILESIZE / 2) + GameMap.OFFSET_Y); + + this.currentStrategy = chaseStrategy; } public void draw(Graphics g) { @@ -62,20 +69,19 @@ public class Ghost { COLLISION_BOX_SIZE, null); } - public void update(PacMan pacman) { + public void update(PacMan pacman, GameMap map) { updateAnimationTick(); - updatePosition(pacman); + updatePosition(pacman, map); } - private void updatePosition(PacMan pacman) { + private void updatePosition(PacMan pacman, GameMap map) { if (movementTick >= GHOST_MOVEMENT_UPDATE_FREQUENCY) { if (isAlligned(position)) { log.info("Evaluating possible directions"); prevDirection = direction; direction = chooseDirection( - collisionChecker.calculateDirectionAlternatives(position), - currentStrategy.chooseTarget(pacman), - prevDirection); + prioritize(collisionChecker.calculateDirectionAlternatives(position)), + currentStrategy.chooseTarget(pacman, map)); log.info("selecting direction {}", direction); } @@ -93,17 +99,36 @@ public class Ghost { } else movementTick++; } + private Map prioritize(List directions) { + return directions.stream() + .filter(d -> d != Direction.NONE) + .collect(Collectors.toMap( + d -> d, + d -> (prevDirection != null && d == prevDirection.opposite()) ? 2 : 1 + )); + + } + private boolean isAlligned(Point pos) { int row = pos.x % GameMap.MAP_TILESIZE; int col = pos.y % GameMap.MAP_TILESIZE; return row == GameMap.MAP_TILESIZE / 2 && col == GameMap.MAP_TILESIZE / 2; } - private Direction chooseDirection(List options, Point target, Direction prevDirection) { - List l = options.stream() - // remove any option to go back - .filter(d -> !(prevDirection != null && d.equals(prevDirection.opposite()))) + private Direction chooseDirection(Map options, Point target) { + + // Find the lowest priority + int lowestPriority = options.values().stream() + .mapToInt(Integer::intValue) + .min() + .orElse(Integer.MAX_VALUE); + + // Return all directions that have this priority + List l = options.entrySet().stream() + .filter(entry -> entry.getValue() == lowestPriority) + .map(Map.Entry::getKey) .toList(); + Direction best = l.getFirst(); double bestDist = Double.MAX_VALUE; @@ -137,7 +162,7 @@ public class Ghost { this.mode = mode; switch (mode) { case CHASE -> currentStrategy = chaseStrategy; - case SCATTER -> currentStrategy = null; + case SCATTER -> currentStrategy = scaterStrategy; case FRIGHTENED -> currentStrategy = null; case EATEN -> currentStrategy = null; } diff --git a/src/main/java/se/urmo/game/entities/GhostStrategy.java b/src/main/java/se/urmo/game/entities/GhostStrategy.java index 90a38ad..b8339fe 100644 --- a/src/main/java/se/urmo/game/entities/GhostStrategy.java +++ b/src/main/java/se/urmo/game/entities/GhostStrategy.java @@ -1,7 +1,9 @@ package se.urmo.game.entities; +import se.urmo.game.map.GameMap; + import java.awt.Point; public interface GhostStrategy { - Point chooseTarget(PacMan pacman); + Point chooseTarget(PacMan pacman, GameMap map); } diff --git a/src/main/java/se/urmo/game/entities/PacMan.java b/src/main/java/se/urmo/game/entities/PacMan.java index 15002f2..c813450 100644 --- a/src/main/java/se/urmo/game/entities/PacMan.java +++ b/src/main/java/se/urmo/game/entities/PacMan.java @@ -18,19 +18,20 @@ import java.util.Arrays; @Slf4j public class PacMan { public static final int PACMAN_SIZE = 32; + public static final int PACMAN_OFFSET = PACMAN_SIZE / 2; private static final int COLLISION_BOX_SIZE = 16; private static final int COLLISION_BOX_OFFSET = (PACMAN_SIZE - COLLISION_BOX_SIZE) / 2; private final Game game; private int aniTick = 0; private int aniIndex = 0; - private static final int ANIMATION_UPDATE_FREQUENCY = 25; + private static final int ANIMATION_UPDATE_FREQUENCY = 10; private int speed = 1; @Setter private boolean moving; private final BufferedImage[][] movmentImages = new BufferedImage[4][4]; private Point position; private static final BufferedImage COLLISION_BOX = MiscUtil.createOutlinedBox(COLLISION_BOX_SIZE, COLLISION_BOX_SIZE, Color.yellow, 2); - private CollisionChecker collisionChecker; + private final CollisionChecker collisionChecker; @Setter @Getter private Direction direction = Direction.NONE; @@ -65,17 +66,16 @@ public class PacMan { .toArray(BufferedImage[]::new); } - public void draw(Graphics g) { g.drawImage( - movmentImages[direction==Direction.NONE?0:direction.ordinal()][aniIndex], - position.x - PACMAN_SIZE / 2, - position.y - PACMAN_SIZE / 2, + movmentImages[direction==Direction.NONE ? 0 : direction.ordinal()][aniIndex], + position.x - PACMAN_OFFSET, + position.y - PACMAN_OFFSET, PACMAN_SIZE, PACMAN_SIZE, null); g.drawImage(COLLISION_BOX, position.x - COLLISION_BOX_OFFSET, position.y - COLLISION_BOX_OFFSET, COLLISION_BOX_SIZE, COLLISION_BOX_SIZE, null); g.setColor(Color.BLUE); - g.fillRect(position.x-1, position.y-1, 3, 3); + //g.fillRect(position.x-1, position.y-1, 3, 3); } public void update() { @@ -98,7 +98,6 @@ public class PacMan { } } - private void updateAnimationTick() { if (moving) { aniTick++; diff --git a/src/main/java/se/urmo/game/entities/PinkyStrategy.java b/src/main/java/se/urmo/game/entities/PinkyStrategy.java index 48aec6a..fdde5c2 100644 --- a/src/main/java/se/urmo/game/entities/PinkyStrategy.java +++ b/src/main/java/se/urmo/game/entities/PinkyStrategy.java @@ -1,21 +1,21 @@ package se.urmo.game.entities; +import se.urmo.game.map.GameMap; import se.urmo.game.util.Direction; import java.awt.Point; public class PinkyStrategy implements GhostStrategy{ @Override - public Point chooseTarget(PacMan pacman) { + public Point chooseTarget(PacMan pacman, GameMap map) { Direction pacmanDir = pacman.getDirection(); Point pacmanPos = pacman.getTilePosition(); return switch (pacmanDir){ - case RIGHT -> new Point(pacmanPos.x + 4 * 16, pacmanPos.y); - case LEFT -> new Point(pacmanPos.x - 4 * 16, pacmanPos.y); - case DOWN -> new Point(pacmanPos.x, pacmanPos.y + 4 * 16); - case UP -> new Point(pacmanPos.x, pacmanPos.y - 4 * 16); + case RIGHT -> new Point(pacmanPos.x + 4 * GameMap.MAP_TILESIZE, pacmanPos.y); + case LEFT -> new Point(pacmanPos.x - 4 * GameMap.MAP_TILESIZE, pacmanPos.y); + case DOWN -> new Point(pacmanPos.x, pacmanPos.y + 4 * GameMap.MAP_TILESIZE); + case UP -> new Point(pacmanPos.x, pacmanPos.y - 4 * GameMap.MAP_TILESIZE); case NONE -> pacmanPos; - default -> throw new IllegalStateException("Illegal direction"); }; } } diff --git a/src/main/java/se/urmo/game/entities/ScatterToTopRight.java b/src/main/java/se/urmo/game/entities/ScatterToTopRight.java new file mode 100644 index 0000000..a569bce --- /dev/null +++ b/src/main/java/se/urmo/game/entities/ScatterToTopRight.java @@ -0,0 +1,12 @@ +package se.urmo.game.entities; + +import se.urmo.game.map.GameMap; + +import java.awt.Point; + +public class ScatterToTopRight implements GhostStrategy{ + @Override + public Point chooseTarget(PacMan pacman, GameMap map) { + return new Point((map.columns() -1) * GameMap.MAP_TILESIZE, 0); + } +} diff --git a/src/main/java/se/urmo/game/map/GameMap.java b/src/main/java/se/urmo/game/map/GameMap.java index 400ee90..d01248e 100644 --- a/src/main/java/se/urmo/game/map/GameMap.java +++ b/src/main/java/se/urmo/game/map/GameMap.java @@ -2,7 +2,6 @@ package se.urmo.game.map; import lombok.extern.slf4j.Slf4j; import se.urmo.game.main.GamePanel; -import se.urmo.game.util.Direction; import se.urmo.game.util.LoadSave; import java.awt.*; @@ -12,7 +11,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.stream.IntStream; -import java.util.stream.Stream; @Slf4j public class GameMap { @@ -127,9 +125,7 @@ public class GameMap { public void draw(Graphics g) { for (int row = 0; row < mapData.length; row++) { for (int col = 0; col < mapData[row].length; col++) { - MapTile tile = mapData[row][col]; - - BufferedImage tileImage = tile.getImage(); + BufferedImage tileImage = mapData[row][col].getImage(); if (tileImage != null) { int x = OFFSET_X + col * MAP_TILESIZE; @@ -144,8 +140,8 @@ public class GameMap { return list.stream().allMatch(p -> isPassable(p.x, p.y)); } public boolean isPassable(int x, int y) { - int row = (y - OFFSET_Y) / MAP_TILESIZE; - int col = (x - OFFSET_X) / MAP_TILESIZE; + int row = getRow(y); + int col = getCol(x); int tileY = (y - OFFSET_Y) % MAP_TILESIZE; int tileX = (x - OFFSET_X) % MAP_TILESIZE; log.trace("Point[x="+x+",y="+y+"] is row="+ row + ", col=" + col + " with reminder x=" +tileX+",y=" +tileY); @@ -156,8 +152,12 @@ public class GameMap { return b; } - public int getWidth() { - return GamePanel.SCREEN_WIDTH; + private static int getCol(int x) { + return (x - OFFSET_X) / MAP_TILESIZE; + } + + private static int getRow(int y) { + return (y - OFFSET_Y) / MAP_TILESIZE; } public int getHeight() { @@ -165,42 +165,36 @@ public class GameMap { } public void removeTileImage(Point destination) { - int row = (destination.y - OFFSET_Y) / MAP_TILESIZE; - int col = (destination.x - OFFSET_X) / MAP_TILESIZE; + int row = getRow(destination); + int col = getCol(destination); MapTile tile = mapData[row][col]; if(tile.getValue() == 0) tile.setImage(null); } - public List directionAlternatives(Point position) { - int row = (position.y - OFFSET_Y) / MAP_TILESIZE; - int col = (position.x - OFFSET_X) / MAP_TILESIZE; - - record DirectionCheck(int rowOffset, int colOffset, Direction direction) {} - log.debug("At [{}][{}]", row, col); - return Stream.of( - new DirectionCheck(0, 1, Direction.RIGHT), - new DirectionCheck(0, -1, Direction.LEFT), - new DirectionCheck(1, 0, Direction.DOWN), - new DirectionCheck(-1, 0, Direction.UP) - ) - .filter(dc -> { - int r = row + dc.rowOffset; - int c = col + dc.colOffset; - MapTile mapTile = mapData[r][c]; - boolean solid = mapTile.isSolid(); - log.debug("[{}][{}] {} is {} ({})", r, c, dc.direction, solid ? "solid" : " not solid", mapTile.getValue()); - return !solid; - }) - .map(DirectionCheck::direction) - .toList(); + private static int getCol(Point point) { + return getCol(point.x); } - public boolean isSolid(int x, int y) { - int row = (y - OFFSET_Y) / MAP_TILESIZE; - int col = (x - OFFSET_X) / MAP_TILESIZE; + private static int getRow(Point point) { + return getRow(point.y); + } + + public boolean isSolid(Point pos) { + int row = getRow(pos); + int col = getCol(pos); + return isSolid(row,col); + } + + + public boolean isSolid(int row, int col) { + if (col >= columns() || col < 0 ) return true; MapTile mapTile = mapData[row][col]; boolean solid = mapTile.isSolid(); log.debug("[{}][{}] is {} ({})", row, col, solid ? "solid" : " not solid", mapTile.getValue()); return solid; } + + public int columns() { + return (GamePanel.SCREEN_WIDTH - 2 * OFFSET_X) / MAP_TILESIZE; + } } diff --git a/src/main/java/se/urmo/game/state/GameStateManager.java b/src/main/java/se/urmo/game/state/GameStateManager.java index 144ab75..04b07ad 100644 --- a/src/main/java/se/urmo/game/state/GameStateManager.java +++ b/src/main/java/se/urmo/game/state/GameStateManager.java @@ -1,5 +1,6 @@ package se.urmo.game.state; +import lombok.Getter; import se.urmo.game.main.Game; import java.awt.*; @@ -9,6 +10,7 @@ import java.util.Map; public class GameStateManager { private final Game game; private Map states = new HashMap<>(); + @Getter private GameState currentState; public GameStateManager(Game game) { @@ -28,8 +30,4 @@ public class GameStateManager { public void render(Graphics2D g) { currentState.render(g); } - - public GameState getCurrentState() { - return currentState; - } } diff --git a/src/main/java/se/urmo/game/state/GhostManager.java b/src/main/java/se/urmo/game/state/GhostManager.java index 3816916..aeeda53 100644 --- a/src/main/java/se/urmo/game/state/GhostManager.java +++ b/src/main/java/se/urmo/game/state/GhostManager.java @@ -1,12 +1,15 @@ package se.urmo.game.state; import lombok.Getter; +import lombok.extern.slf4j.Slf4j; import se.urmo.game.collision.GhostCollisionChecker; import se.urmo.game.entities.BlinkyStrategy; import se.urmo.game.entities.Ghost; import se.urmo.game.entities.GhostMode; import se.urmo.game.entities.PacMan; import se.urmo.game.entities.PinkyStrategy; +import se.urmo.game.entities.ScatterToTopRight; +import se.urmo.game.map.GameMap; import se.urmo.game.util.LoadSave; import java.awt.Graphics2D; @@ -14,21 +17,34 @@ import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.List; +@Slf4j public class GhostManager { public static final int SPRITE_SHEET_ROWS = 10; public static final int MAX_SPRITE_FRAMES = 4; @Getter private final List ghosts = new ArrayList<>(); private BufferedImage[][] image; - private GhostMode globalMode = GhostMode.CHASE; + private GhostMode globalMode; + + private long lastModeSwitchTime; + private int phaseIndex = 0; + + // cycle in milliseconds: {scatter, chase, scatter, chase, ...} + private final int[] cycleDurations = { + 7000, 20000, // scatter 7s, chase 20s + 7000, 20000, // scatter 7s, chase 20s + 5000, 20000, // scatter 5s, chase 20s + 5000, Integer.MAX_VALUE // scatter 5s, then chase forever + }; public GhostManager(GhostCollisionChecker ghostCollisionChecker) { loadAnimation(); // Create ghosts with their strategies - //ghosts.add(new Ghost(ghostCollisionChecker, new BlinkyStrategy(),image[0])); - //ghosts.add(new Ghost(ghostCollisionChecker, new PinkyStrategy(), image[1])); + ghosts.add(new Ghost(ghostCollisionChecker, new BlinkyStrategy(),new ScatterToTopLeft(), image[0])); + ghosts.add(new Ghost(ghostCollisionChecker, new PinkyStrategy(),new ScatterToTopRight(), image[1])); //ghosts.add(new Ghost(240, 200, new InkyStrategy(), loader.getSprite("inky"))); //ghosts.add(new Ghost(260, 200, new ClydeStrategy(), loader.getSprite("clyde"))); + setMode(GhostMode.CHASE); } private void loadAnimation() { @@ -44,14 +60,28 @@ public class GhostManager { public void setMode(GhostMode mode) { this.globalMode = mode; + log.debug("Mode changed to {}", globalMode); for (Ghost g : ghosts) { g.setMode(mode); } } - public void update(PacMan pacman) { + public void update(PacMan pacman, GameMap map) { + long now = System.currentTimeMillis(); + if (phaseIndex < cycleDurations.length) { + int duration = cycleDurations[phaseIndex]; + if (now - lastModeSwitchTime >= duration) { + phaseIndex++; + if (phaseIndex < cycleDurations.length) { + GhostMode newMode = (phaseIndex % 2 == 0) ? GhostMode.SCATTER : GhostMode.CHASE; + setMode(newMode); + } + lastModeSwitchTime = now; + } + } + for (Ghost g : ghosts) { - g.update(pacman); + g.update(pacman, map); } } diff --git a/src/main/java/se/urmo/game/state/PlayingState.java b/src/main/java/se/urmo/game/state/PlayingState.java index ee0390c..8cda9fe 100644 --- a/src/main/java/se/urmo/game/state/PlayingState.java +++ b/src/main/java/se/urmo/game/state/PlayingState.java @@ -32,7 +32,7 @@ public class PlayingState implements GameState { @Override public void update() { pacman.update(); - ghostManager.update(pacman); + ghostManager.update(pacman, map); } @Override diff --git a/src/main/java/se/urmo/game/state/ScatterToTopLeft.java b/src/main/java/se/urmo/game/state/ScatterToTopLeft.java new file mode 100644 index 0000000..a090b1f --- /dev/null +++ b/src/main/java/se/urmo/game/state/ScatterToTopLeft.java @@ -0,0 +1,15 @@ +package se.urmo.game.state; + +import se.urmo.game.entities.GhostStrategy; +import se.urmo.game.entities.PacMan; +import se.urmo.game.map.GameMap; + +import java.awt.Point; + +public class ScatterToTopLeft implements GhostStrategy { + + @Override + public Point chooseTarget(PacMan pacman, GameMap map) { + return new Point(1, 0); + } +}