diff --git a/lib/Board.cpp b/lib/Board.cpp index e0950e4..c5d8c0f 100644 --- a/lib/Board.cpp +++ b/lib/Board.cpp @@ -60,7 +60,7 @@ static Cell cellAtPosition(GridPosition point) { } bool isWalkableForPacMan(GridPosition point) { - return cellAtPosition(point) != Cell::wall; + return cellAtPosition(point) != Cell::wall && cellAtPosition(point) != Cell::pen; } bool isWalkableForGhost(GridPosition point, GridPosition origin, bool isEyes) { @@ -79,6 +79,26 @@ bool isPortal(GridPosition point, Direction direction) { (cellAtPosition(point) == Cell::right_portal && direction == Direction::RIGHT); } +bool isIntersection(GridPosition point) { + if (!isWalkableForPacMan(point) || cellAtPosition(point) == Cell::left_portal || cellAtPosition(point) == Cell::right_portal) { + return false; + } + + const GridPosition right{ point.x + 1, point.y }; + const bool rightWalkable = isWalkableForPacMan(right); + + const GridPosition left{ point.x - 1, point.y }; + const bool leftWalkable = isWalkableForPacMan(left); + + const GridPosition top{ point.x, point.y - 1 }; + const bool topWalkable = isWalkableForPacMan(top); + + const GridPosition bottom{ point.x, point.y + 1 }; + const bool bottomWalkable = isWalkableForPacMan(bottom); + + return (topWalkable && rightWalkable) || (rightWalkable && bottomWalkable) || (bottomWalkable && leftWalkable) || (leftWalkable && topWalkable); +} + GridPosition teleport(GridPosition point) { size_t right = COLUMNS - 1; size_t left = 0; @@ -124,26 +144,4 @@ std::vector initialSuperPelletPositions() { return positions; } -// AI - -bool isIntersection(GridPosition point) { - if (!isWalkableForPacMan(point) || cellAtPosition(point) == Cell::left_portal || cellAtPosition(point) == Cell::right_portal) { - return false; - } - - const GridPosition right{ point.x + 1, point.y }; - const bool rightWalkable = isWalkableForPacMan(right); - - const GridPosition left{ point.x - 1, point.y }; - const bool leftWalkable = isWalkableForPacMan(left); - - const GridPosition top{ point.x, point.y - 1 }; - const bool topWalkable = isWalkableForPacMan(top); - - const GridPosition bottom{ point.x, point.y + 1 }; - const bool bottomWalkable = isWalkableForPacMan(bottom); - - return (topWalkable && rightWalkable) || (rightWalkable && bottomWalkable) || (bottomWalkable && leftWalkable) || (leftWalkable && topWalkable); -} - } // namespace pacman diff --git a/lib/include/Board.hpp b/lib/include/Board.hpp index 56829c3..ebacf0a 100644 --- a/lib/include/Board.hpp +++ b/lib/include/Board.hpp @@ -12,10 +12,11 @@ bool isWalkableForPacMan(GridPosition point); bool isWalkableForGhost(GridPosition point, GridPosition origin, bool isEyes); bool isInPen(GridPosition point); bool isPortal(GridPosition point, Direction direction); +bool isIntersection(GridPosition point); + GridPosition teleport(GridPosition point); std::vector initialPelletPositions(); - std::vector initialSuperPelletPositions(); inline Position penDoorPosition() { @@ -25,6 +26,4 @@ inline Position initialPacManPosition() { return { 13.5, 23 }; } -bool isIntersection(GridPosition point); - } // namespace pacman diff --git a/test/testBoard.cpp b/test/testBoard.cpp new file mode 100644 index 0000000..c9c6fb5 --- /dev/null +++ b/test/testBoard.cpp @@ -0,0 +1,68 @@ +#include "Board.hpp" +#include + +// These tests assume a static game board. + +TEST_CASE("Is walkable for Pac-Man", "[board]") { + REQUIRE_FALSE(pacman::isWalkableForPacMan(pacman::GridPosition{ 0, 0 })); // wall + REQUIRE_FALSE(pacman::isWalkableForPacMan(pacman::GridPosition{ 27, 0 })); // wall + REQUIRE_FALSE(pacman::isWalkableForPacMan(pacman::GridPosition{ 0, 30 })); // wall + REQUIRE_FALSE(pacman::isWalkableForPacMan(pacman::GridPosition{ 27, 30 })); // wall + REQUIRE_FALSE(pacman::isWalkableForPacMan(pacman::GridPosition{ 11, 13 })); // pen + + REQUIRE(pacman::isWalkableForPacMan(pacman::GridPosition{ 1, 1 })); // pellet + REQUIRE(pacman::isWalkableForPacMan(pacman::GridPosition{ 1, 3 })); // power pellet + REQUIRE(pacman::isWalkableForPacMan(pacman::GridPosition{ 1, 14 })); // nothing + REQUIRE(pacman::isWalkableForPacMan(pacman::GridPosition{ 0, 14 })); // portal left + REQUIRE(pacman::isWalkableForPacMan(pacman::GridPosition{ 27, 14 })); // portal right +} + +TEST_CASE("Is walkable for Ghost", "[board]") { + const pacman::GridPosition pen = pacman::GridPosition{ 11, 13 }; + const pacman::GridPosition outside = pacman::GridPosition{ 1, 1 }; + + // wall check + REQUIRE_FALSE(pacman::isWalkableForGhost(pacman::GridPosition{ 0, 0 }, outside, false)); // wall + REQUIRE_FALSE(pacman::isWalkableForGhost(pacman::GridPosition{ 27, 0 }, outside, false)); // wall + REQUIRE_FALSE(pacman::isWalkableForGhost(pacman::GridPosition{ 0, 30 }, outside, false)); // wall + REQUIRE_FALSE(pacman::isWalkableForGhost(pacman::GridPosition{ 27, 30 }, outside, false)); // wall + + // eyes can walk anywhere except walls + REQUIRE(pacman::isWalkableForGhost(pacman::GridPosition{ 11, 13 }, outside, true)); // pen + REQUIRE(pacman::isWalkableForGhost(pacman::GridPosition{ 1, 1 }, outside, true)); // pellet + REQUIRE(pacman::isWalkableForGhost(pacman::GridPosition{ 1, 3 }, outside, true)); // power pellet + REQUIRE(pacman::isWalkableForGhost(pacman::GridPosition{ 1, 14 }, outside, true)); // nothing + REQUIRE(pacman::isWalkableForGhost(pacman::GridPosition{ 0, 14 }, outside, true)); // portal left + REQUIRE(pacman::isWalkableForGhost(pacman::GridPosition{ 27, 14 }, outside, true)); // portal right + + // can only walk in pen if that is your origin or current location + REQUIRE_FALSE(pacman::isWalkableForGhost(pacman::GridPosition{ 11, 13 }, outside, false)); // in pen, origin outside + REQUIRE(pacman::isWalkableForGhost(pacman::GridPosition{ 1, 1 }, outside, false)); // outside, origin outside + REQUIRE(pacman::isWalkableForGhost(pacman::GridPosition{ 1, 1 }, pen, false)); // outside, origin pen + REQUIRE(pacman::isWalkableForGhost(pacman::GridPosition{ 11, 13 }, pen, false)); // in pen, origin pen +} + +TEST_CASE("Is portal", "[board]") { + const pacman::GridPosition portalRight = pacman::GridPosition{ 27, 14 }; + const pacman::GridPosition portalLeft = pacman::GridPosition{ 0, 14 }; + + REQUIRE(pacman::isPortal(portalRight, pacman::Direction::RIGHT)); // right into right portal + REQUIRE(pacman::isPortal(portalLeft, pacman::Direction::LEFT)); // left into left portal + REQUIRE_FALSE(pacman::isPortal(portalRight, pacman::Direction::LEFT)); // left into right portal + REQUIRE_FALSE(pacman::isPortal(portalLeft, pacman::Direction::RIGHT)); // right into left portal +} + +TEST_CASE("Teleport", "[board]") { + const pacman::GridPosition portalRight = pacman::GridPosition{ 27, 14 }; + const pacman::GridPosition portalLeft = pacman::GridPosition{ 0, 14 }; + + if (pacman::isPortal(portalRight, pacman::Direction::RIGHT)) { + const pacman::GridPosition result = pacman::teleport(portalRight); + REQUIRE(result.x == portalLeft.x); + } + + if (pacman::isPortal(portalLeft, pacman::Direction::LEFT)) { + const pacman::GridPosition result = pacman::teleport(portalLeft); + REQUIRE(result.x == portalRight.x); + } +} \ No newline at end of file