Each possible position now contains the path the character takes to reach it
This commit is contained in:
parent
a14a54c279
commit
1a5505fe3f
@ -1,6 +1,11 @@
|
||||
import {EnumType} from "typescript";
|
||||
|
||||
export enum Direction {
|
||||
left,
|
||||
up,
|
||||
right,
|
||||
down
|
||||
}
|
||||
}
|
||||
|
||||
export const getDirections = () => Object.values(Direction)
|
||||
.filter(d => !isNaN(Number(d))) as Direction[];
|
||||
|
@ -1,13 +1,13 @@
|
||||
import {TileType} from "./tileType";
|
||||
import {Character, PacMan} from "./character";
|
||||
import {Direction} from "./direction";
|
||||
import {Direction, getDirections} from "./direction";
|
||||
|
||||
/**
|
||||
* Finds all the possible positions for the character to move to
|
||||
* @param board The board the character is on
|
||||
* @param character The current position of the character
|
||||
* @param steps The number of steps the character can move
|
||||
* @returns {Path[]} An array of paths the character can move to
|
||||
* @returns An array of paths the character can move to
|
||||
*/
|
||||
export default function findPossiblePositions(board: GameMap, character: Character, steps: number): Path[] {
|
||||
return findPossibleRecursive(board, character.position, steps, character instanceof PacMan);
|
||||
@ -16,41 +16,55 @@ export default function findPossiblePositions(board: GameMap, character: Charact
|
||||
/**
|
||||
* Uses recursion to move through the board and find all the possible positions
|
||||
* @param board The board the character is on
|
||||
* @param path The current path the character is on
|
||||
* @param currentPos The current path the character is on
|
||||
* @param steps The number of steps the character can move
|
||||
* @param isPacMan True if the character is Pac-Man, false if it is a ghost
|
||||
* @returns {Path[]} An array of paths the character can move to
|
||||
* @returns An array of paths the character can move to
|
||||
*/
|
||||
function findPossibleRecursive(board: GameMap, path: Path, steps: number, isPacMan: boolean): Path[] {
|
||||
function findPossibleRecursive(board: GameMap, currentPos: Path, steps: number, isPacMan: boolean): Path[] {
|
||||
|
||||
const paths: Path[] = [];
|
||||
if (isOutsideBoard(path, board.length)) {
|
||||
if (isOutsideBoard(currentPos, board.length)) {
|
||||
if (isPacMan) {
|
||||
return addTeleportationTiles(board, path, steps, isPacMan);
|
||||
return addTeleportationTiles(board, currentPos, steps, isPacMan);
|
||||
}
|
||||
} else if (!isWall(board, path)) {
|
||||
} else if (!isWall(board, currentPos)) {
|
||||
if (steps === 0) {
|
||||
paths.push(path);
|
||||
paths.push(currentPos);
|
||||
} else {
|
||||
|
||||
addToPath(currentPos);
|
||||
|
||||
steps--;
|
||||
paths.push(...tryMove(board, path, Direction.up, steps, isPacMan));
|
||||
paths.push(...tryMove(board, path, Direction.right, steps, isPacMan));
|
||||
paths.push(...tryMove(board, path, Direction.down, steps, isPacMan));
|
||||
paths.push(...tryMove(board, path, Direction.left, steps, isPacMan));
|
||||
for (const direction of getDirections()) {
|
||||
paths.push(...tryMove(board, currentPos, direction, steps, isPacMan));
|
||||
}
|
||||
}
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to move the character in the given direction
|
||||
* Adds the current position to the path, if it's not on the spawn and it's not already in the path
|
||||
* @param currentPos The current path the character is on
|
||||
*/
|
||||
function addToPath(currentPos: Path): void {
|
||||
if (!currentPos.path) {
|
||||
currentPos.path = [];
|
||||
} else if(!currentPos.path.includes(currentPos.end)) {
|
||||
currentPos.path = [...currentPos.path, currentPos.end];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to move the character in the given direction. The character can move in all directions except the one it came from.
|
||||
* Only Pac-Man characters can move through the teleportation tiles.
|
||||
* @param board The board the character is on
|
||||
* @param path The current path the character is on
|
||||
* @param direction The direction to move in
|
||||
* @param steps The number of steps the character can move
|
||||
* @param isPacMan True if the character is Pac-Man, false if it is a ghost
|
||||
* @returns {Path[]} An array of paths the character can move to
|
||||
* @returns An array of paths the character can move to
|
||||
*/
|
||||
function tryMove(board: GameMap, path: Path, direction: Direction, steps: number, isPacMan: boolean): Path[] {
|
||||
|
||||
@ -81,7 +95,7 @@ function tryMove(board: GameMap, path: Path, direction: Direction, steps: number
|
||||
|
||||
if (path.direction !== (direction + 2) % 4) {
|
||||
return findPossibleRecursive(board, {
|
||||
end: getNewPosition(), direction: direction
|
||||
end: getNewPosition(), direction: direction, path: path.path
|
||||
}, steps, isPacMan);
|
||||
}
|
||||
return [];
|
||||
@ -90,15 +104,16 @@ function tryMove(board: GameMap, path: Path, direction: Direction, steps: number
|
||||
/**
|
||||
* Finds all the possible paths when using teleportation tiles
|
||||
* @param board The board the character is on
|
||||
* @param path The current path the character is on
|
||||
* @param currentPath The current path the character is on
|
||||
* @param steps The number of steps the character can move
|
||||
* @param isPacMan True if the character is Pac-Man, false if it is a ghost
|
||||
*/
|
||||
function addTeleportationTiles(board: GameMap, path: Path, steps: number, isPacMan: boolean): Path[] {
|
||||
function addTeleportationTiles(board: GameMap, currentPath: Path, steps: number, isPacMan: boolean): Path[] {
|
||||
const possiblePositions = findTeleportationTiles(board);
|
||||
const paths: Path[] = [];
|
||||
for (const pos of possiblePositions) {
|
||||
if (pos.end.x !== Math.max(path.end.x, 0) || pos.end.y !== Math.max(path.end.y, 0)) {
|
||||
if (pos.end.x !== Math.max(currentPath.end.x, 0) || pos.end.y !== Math.max(currentPath.end.y, 0)) {
|
||||
pos.path = currentPath.path;
|
||||
paths.push(...findPossibleRecursive(board, pos, steps, isPacMan));
|
||||
}
|
||||
}
|
||||
@ -108,7 +123,7 @@ function addTeleportationTiles(board: GameMap, path: Path, steps: number, isPacM
|
||||
/**
|
||||
* Finds all the teleportation tiles on the board
|
||||
* @param board The board the character is on
|
||||
* @returns {Path[]} An array of paths containing the teleportation tiles
|
||||
* @returns An array of paths containing the teleportation tiles
|
||||
*/
|
||||
function findTeleportationTiles(board: GameMap): Path[] {
|
||||
const possiblePositions: Path[] = [];
|
||||
|
@ -13,48 +13,91 @@ beforeEach(() => {
|
||||
test("Pac-Man rolls one from start, should return one position", () => {
|
||||
const result = possibleMovesAlgorithm(testMap, pacMan, 1);
|
||||
expect(result.length).toBe(1);
|
||||
expect(result).toEqual(getPath({at: {x: 3, y: 2}, direction: Direction.up}));
|
||||
expect(result[0].path?.length).toBe(0);
|
||||
expect(result).toEqual([{end: {x: 3, y: 2}, direction: Direction.up, path: []}]);
|
||||
});
|
||||
|
||||
test("Pac-Man rolls two from start, should return one position", () => {
|
||||
const result = possibleMovesAlgorithm(testMap, pacMan, 2);
|
||||
expect(result.length).toBe(1);
|
||||
expect(result).toEqual(getPath({at: {x: 3, y: 1}, direction: Direction.up}));
|
||||
expect(result[0].path?.length).toBe(1);
|
||||
expect(result).toEqual([{end: {x: 3, y: 1}, direction: Direction.up, path: [{x: 3, y: 2}]}]);
|
||||
});
|
||||
|
||||
test("Pac-Man rolls three from start, should return two positions", () => {
|
||||
const result = possibleMovesAlgorithm(testMap, pacMan, 3);
|
||||
expect(result.length).toBe(2);
|
||||
arrayEquals(result, getPath({at: {x: 2, y: 1}, direction: Direction.left}, {at: {x: 4, y: 1}, direction: Direction.right}));
|
||||
arrayEquals(result, [{end: {x: 2, y: 1}, direction: Direction.left, path: [{x: 3, y: 2}, {x: 3, y: 1}]},
|
||||
{end: {x: 4, y: 1}, direction: Direction.right, path: [{x: 3, y: 2}, {x: 3, y: 1}]}]);
|
||||
});
|
||||
|
||||
test("Pac-Man rolls four from start, should return two positions", () => {
|
||||
const result = possibleMovesAlgorithm(testMap, pacMan, 4);
|
||||
expect(result.length).toBe(2);
|
||||
arrayEquals(result, getPath({at: {x: 1, y: 1}, direction: Direction.left}, {at: {x: 5, y: 1}, direction: Direction.right}));
|
||||
arrayEquals(result, [{
|
||||
end: {x: 1, y: 1},
|
||||
direction: Direction.left,
|
||||
path: [{x: 3, y: 2}, {x: 3, y: 1}, {x: 2, y: 1}]
|
||||
}, {
|
||||
end: {x: 5, y: 1},
|
||||
direction: Direction.right,
|
||||
path: [{x: 3, y: 2}, {x: 3, y: 1}, {x: 4, y: 1}]
|
||||
}]);
|
||||
});
|
||||
|
||||
test("Pac-Man rolls five from start, should return four positions", () => {
|
||||
const result = possibleMovesAlgorithm(testMap, pacMan, 5);
|
||||
expect(result.length).toBe(4);
|
||||
arrayEquals(result, getPath(
|
||||
{at: {x: 5, y: 0}, direction: Direction.up},
|
||||
{at: {x: 6, y: 1}, direction: Direction.right},
|
||||
{at: {x: 1, y: 2}, direction: Direction.down},
|
||||
{at: {x: 5, y: 2}, direction: Direction.down}
|
||||
));
|
||||
arrayEquals(result, [{
|
||||
end: {x: 5, y: 0},
|
||||
direction: Direction.up,
|
||||
path: [{x: 3, y: 2}, {x: 3, y: 1}, {x: 4, y: 1}, {x: 5, y: 1}]
|
||||
}, {
|
||||
end: {x: 6, y: 1},
|
||||
direction: Direction.right,
|
||||
path: [{x: 3, y: 2}, {x: 3, y: 1}, {x: 4, y: 1}, {x: 5, y: 1}]
|
||||
}, {
|
||||
end: {x: 1, y: 2},
|
||||
direction: Direction.down,
|
||||
path: [{x: 3, y: 2}, {x: 3, y: 1}, {x: 2, y: 1}, {x: 1, y: 1}]
|
||||
}, {
|
||||
end: {x: 5, y: 2},
|
||||
direction: Direction.down,
|
||||
path: [{x: 3, y: 2}, {x: 3, y: 1}, {x: 4, y: 1}, {x: 5, y: 1}]
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
test("Pac-Man rolls six from start, should return six positions", () => {
|
||||
const result = possibleMovesAlgorithm(testMap, pacMan, 6);
|
||||
expect(result.length).toBe(6);
|
||||
arrayEquals(result, getPath(
|
||||
{at: {x: 1, y: 3}, direction: Direction.down},
|
||||
{at: {x: 0, y: 5}, direction:Direction.right},
|
||||
{at: {x: 5, y: 3}, direction: Direction.down},
|
||||
{at: {x: 7, y: 1}, direction: Direction.right},
|
||||
{at: {x: 10, y: 5}, direction: Direction.left},
|
||||
{at: {x: 5, y: 10}, direction: Direction.up}));
|
||||
arrayEquals(result, [
|
||||
{
|
||||
end: {x: 1, y: 3},
|
||||
direction: Direction.down,
|
||||
path: [{x: 3, y: 2}, {x: 3, y: 1}, {x: 2, y: 1}, {x: 1, y: 1}, {x: 1, y: 2}]
|
||||
}, {
|
||||
end: {x: 0, y: 5},
|
||||
direction: Direction.right,
|
||||
path: [{x: 3, y: 2}, {x: 3, y: 1}, {x: 4, y: 1}, {x: 5, y: 1}, {x: 5, y: 0}]
|
||||
}, {
|
||||
end: {x: 5, y: 3},
|
||||
direction: Direction.down,
|
||||
path: [{x: 3, y: 2}, {x: 3, y: 1}, {x: 4, y: 1}, {x: 5, y: 1}, {x: 5, y: 2}]
|
||||
}, {
|
||||
end: {x: 7, y: 1},
|
||||
direction: Direction.right,
|
||||
path: [{x: 3, y: 2}, {x: 3, y: 1}, {x: 4, y: 1}, {x: 5, y: 1}, {x: 6, y: 1}]
|
||||
}, {
|
||||
end: {x: 10, y: 5},
|
||||
direction: Direction.left,
|
||||
path: [{x: 3, y: 2}, {x: 3, y: 1}, {x: 4, y: 1}, {x: 5, y: 1}, {x: 5, y: 0}]
|
||||
}, {
|
||||
end: {x: 5, y: 10},
|
||||
direction: Direction.up,
|
||||
path: [{x: 3, y: 2}, {x: 3, y: 1}, {x: 4, y: 1}, {x: 5, y: 1}, {x: 5, y: 0}]
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
test("Pac-Man rolls four from position [5,1] (right), should return 11", () => {
|
||||
@ -66,13 +109,13 @@ test("Pac-Man rolls four from position [5,1] (right), should return 11", () => {
|
||||
test("Pac-Man rolls three from position [1,5] (left), should return 5", () => {
|
||||
pacMan.follow({end: {x: 1, y: 5}, direction: Direction.left});
|
||||
const result = possibleMovesAlgorithm(testMap, pacMan, 3);
|
||||
arrayEquals(result, getPath(
|
||||
{at: {x: 1, y: 2}, direction: Direction.up},
|
||||
{at: {x: 1, y: 8}, direction: Direction.down},
|
||||
{at: {x: 5, y: 1}, direction: Direction.down},
|
||||
{at: {x: 9, y: 5}, direction: Direction.left},
|
||||
{at: {x: 5, y: 9}, direction: Direction.up},
|
||||
));
|
||||
arrayEquals(result, [
|
||||
{end: {x: 1, y: 2}, direction: Direction.up, path: [{x: 1, y: 4}, {x: 1, y: 3}]},
|
||||
{end: {x: 1, y: 8}, direction: Direction.down, path: [{x: 1, y: 6}, {x: 1, y: 7}]},
|
||||
{end: {x: 5, y: 1}, direction: Direction.down, path: [{x: 0, y: 5}, {x: 5, y: 0}]},
|
||||
{end: {x: 9, y: 5}, direction: Direction.left, path: [{x: 0, y: 5}, {x: 10, y: 5}]},
|
||||
{end: {x: 5, y: 9}, direction: Direction.up, path: [{x: 0, y: 5}, {x: 5, y: 10}]},
|
||||
]);
|
||||
expect(result.length).toBe(5);
|
||||
});
|
||||
|
||||
@ -82,10 +125,6 @@ test("Pac-Man rolls six from position [1,5] (down), should return 17", () => {
|
||||
expect(result.length).toBe(17);
|
||||
});
|
||||
|
||||
function getPath(...positions: DirectionalPosition[]): Path[] {
|
||||
return positions.map(pos => ({end: {x: pos.at.x, y: pos.at.y}, direction: pos.direction}));
|
||||
}
|
||||
|
||||
function arrayEquals<T extends any[]>(result: T, expected: T, message?: string): void {
|
||||
for (const item of expected) {
|
||||
expect(result, message).toContainEqual(item);
|
||||
|
Loading…
x
Reference in New Issue
Block a user