import {State} from "./state"; import Coordinates from "../model/coordinates.ts"; import {MazeCell} from "../model/maze.ts"; export default function handleUserClicked(state: State, x: number, y: number): State { if (isClickAllowed(x, y, state)) { const maze = state.maze!; // 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 === maze.end.x && y === 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; }