2020-11-28 13:10:25 +00:00
|
|
|
#include "Board.hpp"
|
2020-11-27 13:10:09 +00:00
|
|
|
|
2021-07-05 12:10:01 +00:00
|
|
|
namespace pacman {
|
|
|
|
|
2021-07-08 15:42:24 +00:00
|
|
|
const std::size_t ROWS = 31;
|
|
|
|
const std::size_t COLUMNS = 28;
|
|
|
|
|
|
|
|
enum class Cell {
|
2021-09-16 14:36:57 +00:00
|
|
|
wall = 0,
|
|
|
|
pellet = 1,
|
|
|
|
// nothing = 2,
|
|
|
|
// missing 3,
|
|
|
|
power_pellet = 4,
|
|
|
|
pen = 5,
|
|
|
|
left_portal = 6,
|
|
|
|
right_portal = 7
|
2021-07-08 15:42:24 +00:00
|
|
|
};
|
|
|
|
|
2021-07-05 11:54:54 +00:00
|
|
|
// clang-format off
|
2021-07-08 15:42:24 +00:00
|
|
|
constexpr std::array<std::array<int, COLUMNS>, ROWS> board = {{
|
2021-06-24 11:32:52 +00:00
|
|
|
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7
|
2021-06-16 11:14:47 +00:00
|
|
|
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // 0
|
|
|
|
{ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, // 1
|
|
|
|
{ 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0 }, // 2
|
|
|
|
{ 0, 4, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 4, 0 }, // 3
|
|
|
|
{ 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0 }, // 4
|
|
|
|
{ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, // 5
|
|
|
|
{ 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0 }, // 6
|
|
|
|
{ 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0 }, // 7
|
|
|
|
{ 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0 }, // 8
|
|
|
|
{ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 0, 0, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, // 9
|
|
|
|
{ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 0, 0, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, // 10
|
|
|
|
{ 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, // 11
|
2021-06-24 09:40:49 +00:00
|
|
|
{ 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 5, 5, 0, 0, 0, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, // 12
|
2021-06-25 09:06:50 +00:00
|
|
|
{ 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 5, 5, 5, 5, 5, 5, 0, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, // 13
|
2021-07-08 16:00:39 +00:00
|
|
|
{ 6, 2, 2, 2, 2, 2, 1, 2, 2, 2, 0, 5, 5, 5, 5, 5, 5, 0, 2, 2, 2, 1, 2, 2, 2, 2, 2, 7 }, // 14
|
2021-06-25 09:06:50 +00:00
|
|
|
{ 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 5, 5, 5, 5, 5, 5, 0, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, // 15
|
2021-06-16 11:14:47 +00:00
|
|
|
{ 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, // 16
|
|
|
|
{ 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, // 17
|
|
|
|
{ 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, // 18
|
|
|
|
{ 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, // 19
|
|
|
|
{ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, // 20
|
|
|
|
{ 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0 }, // 21
|
|
|
|
{ 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0 }, // 22
|
|
|
|
{ 0, 4, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 4, 0 }, // 23
|
|
|
|
{ 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0 }, // 24
|
|
|
|
{ 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0 }, // 25
|
|
|
|
{ 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0 }, // 26
|
|
|
|
{ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, // 27
|
|
|
|
{ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, // 28
|
|
|
|
{ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, // 29
|
|
|
|
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // 30
|
2021-07-01 12:33:59 +00:00
|
|
|
}};
|
2021-07-05 11:54:54 +00:00
|
|
|
// clang-format on
|
2020-11-27 13:10:09 +00:00
|
|
|
|
2021-07-08 15:42:24 +00:00
|
|
|
static Cell cellAtPosition(GridPosition point) {
|
2021-09-10 09:24:24 +00:00
|
|
|
if (point.x >= COLUMNS || point.y >= ROWS)
|
2021-07-08 15:42:24 +00:00
|
|
|
return Cell::wall;
|
|
|
|
return Cell(board[point.y][point.x]);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isWalkableForPacMan(GridPosition point) {
|
2021-07-05 11:54:54 +00:00
|
|
|
return cellAtPosition(point) != Cell::wall;
|
2021-06-24 09:40:49 +00:00
|
|
|
}
|
|
|
|
|
2021-07-08 15:42:24 +00:00
|
|
|
bool isWalkableForGhost(GridPosition point, GridPosition origin, bool isEyes) {
|
2021-09-09 08:56:29 +00:00
|
|
|
const Cell cell = cellAtPosition(point);
|
2021-07-05 11:54:54 +00:00
|
|
|
if (cell == Cell::wall)
|
|
|
|
return false;
|
2021-09-09 08:56:29 +00:00
|
|
|
return isEyes || isInPen(origin) || !isInPen(point);
|
2021-06-25 09:06:50 +00:00
|
|
|
}
|
|
|
|
|
2021-07-08 15:42:24 +00:00
|
|
|
bool isInPen(GridPosition point) {
|
2021-07-05 11:54:54 +00:00
|
|
|
return cellAtPosition(point) == Cell::pen;
|
2021-06-25 09:06:50 +00:00
|
|
|
}
|
|
|
|
|
2021-07-08 16:00:39 +00:00
|
|
|
bool isPortal(GridPosition point, Direction direction) {
|
|
|
|
return (cellAtPosition(point) == Cell::left_portal && direction == Direction::LEFT) ||
|
|
|
|
(cellAtPosition(point) == Cell::right_portal && direction == Direction::RIGHT);
|
|
|
|
}
|
|
|
|
|
|
|
|
GridPosition teleport(GridPosition point) {
|
|
|
|
size_t right = COLUMNS - 1;
|
|
|
|
size_t left = 0;
|
|
|
|
if (point.x == left)
|
|
|
|
point.x = right;
|
|
|
|
else if (point.x == right)
|
|
|
|
point.x = left;
|
|
|
|
return point;
|
2020-11-27 13:10:09 +00:00
|
|
|
}
|
|
|
|
|
2021-07-08 15:42:24 +00:00
|
|
|
std::vector<GridPosition> initialPelletPositions() {
|
2021-07-05 09:46:49 +00:00
|
|
|
std::vector<GridPosition> positions;
|
2021-07-16 07:19:10 +00:00
|
|
|
positions.reserve(4); // Reserve space for 4 supper pellets
|
|
|
|
|
2021-07-05 11:54:54 +00:00
|
|
|
for (std::size_t row = 0; row < ROWS; row++) {
|
|
|
|
for (std::size_t column = 0; column < COLUMNS; column++) {
|
2021-07-01 12:33:59 +00:00
|
|
|
if (board[row][column] == int(Cell::pellet))
|
2021-07-06 08:07:35 +00:00
|
|
|
positions.emplace_back(column, row);
|
2020-11-27 13:10:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return positions;
|
|
|
|
}
|
|
|
|
|
2021-07-08 15:42:24 +00:00
|
|
|
std::vector<GridPosition> initialSuperPelletPositions() {
|
2021-07-05 09:46:49 +00:00
|
|
|
std::vector<GridPosition> positions;
|
2021-07-16 07:19:10 +00:00
|
|
|
|
|
|
|
// To avoid having to resize the vector too many times, we can
|
|
|
|
// presemptively reserve space for elements.
|
|
|
|
// At a glance, we can estimate that there are pellets on a third of the grid.
|
|
|
|
// This is not accurate so we might either reserve too much or too little memory,
|
|
|
|
// but this is will still be faster than not calling reserve at all!
|
|
|
|
// This will be very noticeable on both very large vectors (10 thousands of elements),
|
|
|
|
// Or small vectors in functions called very frequently.
|
|
|
|
|
|
|
|
positions.reserve((ROWS * COLUMNS) / 3);
|
|
|
|
|
2021-07-05 11:54:54 +00:00
|
|
|
for (std::size_t row = 0; row < ROWS; row++) {
|
|
|
|
for (std::size_t column = 0; column < COLUMNS; column++) {
|
2021-07-01 12:33:59 +00:00
|
|
|
if (board[row][column] == int(Cell::power_pellet))
|
2021-07-06 08:07:35 +00:00
|
|
|
positions.emplace_back(column, row);
|
2020-11-27 13:10:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return positions;
|
|
|
|
}
|
2021-07-05 12:10:01 +00:00
|
|
|
|
2021-09-16 14:36:57 +00:00
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
|
2021-07-05 12:10:01 +00:00
|
|
|
} // namespace pacman
|