82 lines
3.2 KiB
TypeScript
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;
|
|
}
|