labyrinth-frontend/src/state/userpathhandler.ts

82 lines
3.2 KiB
TypeScript

import {State} from "./state";
import Coordinates from "../model/Coordinates";
import {MazeCell} from "../model/Maze";
export default function handleUserClicked(state: State, x: number, y: number): State {
if (isClickAllowed(x, y, state)) {
// Okay, we clicked a cell that's adjacent to the end of the userpath (or which IS the end of the userpath)
// and that's not blocked by a wall. Now let's see.
if (-1 === state.userPath.findIndex(step => step.x === x && step.y === y)) {
// The clicked cell is not yet part of the userpath --> add it.
// If it's the end tile, also show a congratulation message
const showMessage = x === state.maze.end.x && y === state.maze.end.y;
return {
...state,
userPath: [...state.userPath, {x, y}],
errorMessage: showMessage ? "Congratulations! You won!" : state.errorMessage
};
} else {
// The clicked cell IS part of the userpath. Is it the last cell of it?
const lastCoordsFromUserPath = getLastCoordsFromUserPath(state);
if (lastCoordsFromUserPath.x === x && lastCoordsFromUserPath.y === y) {
// Yes, it's the last cell of the userpath --> remove it.
return {
...state,
userPath: state.userPath.filter(step => step.x !== x || step.y !== y),
errorMessage: null
}
}
}
}
// Not allowed to toggle that cell. Don't apply any change to the state.
return state;
}
function isClickAllowed(x: number, y: number, state: State): boolean {
const lastCoordsFromUserPath = getLastCoordsFromUserPath(state);
if (!lastCoordsFromUserPath) {
// when nothing has been marked yet, we can only toggle the starting position
return x === state.maze.start.x && y === state.maze.start.y;
}
if (lastCoordsFromUserPath.x === x && lastCoordsFromUserPath.y === y) {
// toggling the last position in the path is always allowed
return true;
}
if (Math.abs(x - lastCoordsFromUserPath.x) + Math.abs(y - lastCoordsFromUserPath.y) !== 1) {
// It's not a neighbor. So it's not allowed.
return false;
}
const lastCell = getCellAt(lastCoordsFromUserPath, state);
if (x === lastCoordsFromUserPath.x + 1) {
// There must be no wall to the right of the last cell.
return !lastCell.right;
}
if (x === lastCoordsFromUserPath.x - 1) {
// There must be no wall to the left of the last cell.
return !lastCell.left;
}
if (y === lastCoordsFromUserPath.y + 1) {
// There must be no wall below the last cell.
return !lastCell.bottom;
}
if (y === lastCoordsFromUserPath.y - 1) {
// There must be no wall above the last cell.
return !lastCell.top;
}
return false;
}
function getCellAt(coords: Coordinates, state: State): MazeCell {
return state.maze.grid[coords.y][coords.x];
}
function getLastCoordsFromUserPath(state: State): Coordinates | null {
if (state.userPath.length > 0) {
return state.userPath[state.userPath.length - 1];
}
return null;
}