diff --git a/src/useBoard/types.ts b/src/useBoard/types.ts index b573977..3d2fc10 100644 --- a/src/useBoard/types.ts +++ b/src/useBoard/types.ts @@ -27,6 +27,6 @@ export type BoardManager = { export type MazeNavigator = { isValidMove: (from: Coord, to: Coord) => boolean; - findAnchorTarget: (from: Coord, direction: 'left' | 'right' | 'top' | 'bottom') => Coord | null; + findAnchorTarget: (from: Coord, direction: 'left' | 'right' | 'top' | 'bottom', hasKey?: boolean) => Coord | null; validatePath: (from: Coord, direction: Coord, steps: number) => boolean; }; diff --git a/src/useBoard/useMazeNavigation.ts b/src/useBoard/useMazeNavigation.ts index f2f43b7..3b48bae 100644 --- a/src/useBoard/useMazeNavigation.ts +++ b/src/useBoard/useMazeNavigation.ts @@ -10,57 +10,77 @@ export function useMazeNavigation(maze: MazeCell[][]): MazeNavigator { return true; } - function findAnchorTarget(from: Coord, direction: 'left'|'right'|'top'|'bottom'): Coord | null { - if (!maze.length) return null; + function findAnchorTarget(from: Coord, direction: 'left'|'right'|'top'|'bottom', hasKey: boolean = false): Coord | null { + if (!maze.length) return null; - const rowsCount = maze.length; - const colsCount = maze[0]?.length ?? 0; - const { row: r, col: c } = from; + const rowsCount = maze.length; + const colsCount = maze[0]?.length ?? 0; + const { row: r, col: c } = from; - if (!maze[r] || !maze[r][c] || maze[r][c].includes('wall')) return null; + if (!maze[r] || !maze[r][c] || maze[r][c].includes('wall')) return null; - if (direction === 'left' || direction === 'right') { - const step = direction === 'left' ? -1 : 1; - let cc = c; + if (direction === 'left' || direction === 'right') { + const step = direction === 'left' ? -1 : 1; + let cc = c; + let edgeCell: Coord | null = null; - while (true) { - const next = cc + step; - if (next < 0 || next >= colsCount) return null; - if (maze[r][next].includes('wall')) { - const wallIdx = next; - const expectedWallIdx = direction === 'left' ? 0 : colsCount - 1; - const expectedCellIdx = direction === 'left' ? 1 : colsCount - 2; + while (true) { + const next = cc + step; + if (next < 0 || next >= colsCount) return null; + if (maze[r][next].includes('wall')) { + const wallIdx = next; + const expectedWallIdx = direction === 'left' ? 0 : colsCount - 1; + const expectedCellIdx = direction === 'left' ? 1 : colsCount - 2; - if (wallIdx !== expectedWallIdx) return null; - if (cc !== expectedCellIdx) return null; - if (cc === c) return null; + if (wallIdx !== expectedWallIdx) return null; + if (cc !== expectedCellIdx) return null; + if (cc === c) return null; - return { row: r, col: cc }; - } - cc = next; - } - } else { - const step = direction === 'top' ? -1 : 1; - let rr = r; + edgeCell = { row: r, col: cc }; + + if (hasKey && wallIdx === expectedWallIdx) { + const wallPos = { row: r, col: wallIdx }; + if (maze[wallPos.row]?.[wallPos.col]?.includes('exit')) { + return wallPos; + } + } + + return edgeCell; + } + cc = next; + } + } else { + const step = direction === 'top' ? -1 : 1; + let rr = r; + let edgeCell: Coord | null = null; - while (true) { - const next = rr + step; - if (next < 0 || next >= rowsCount) return null; - if (maze[next][c].includes('wall')) { - const wallIdx = next; - const expectedWallIdx = direction === 'top' ? 0 : rowsCount - 1; - const expectedCellIdx = direction === 'top' ? 1 : rowsCount - 2; + while (true) { + const next = rr + step; + if (next < 0 || next >= rowsCount) return null; + if (maze[next][c].includes('wall')) { + const wallIdx = next; + const expectedWallIdx = direction === 'top' ? 0 : rowsCount - 1; + const expectedCellIdx = direction === 'top' ? 1 : rowsCount - 2; - if (wallIdx !== expectedWallIdx) return null; - if (rr !== expectedCellIdx) return null; - if (rr === r) return null; + if (wallIdx !== expectedWallIdx) return null; + if (rr !== expectedCellIdx) return null; + if (rr === r) return null; - return { row: rr, col: c }; - } - rr = next; - } - } - } + edgeCell = { row: rr, col: c }; + + if (hasKey && wallIdx === expectedWallIdx) { + const wallPos = { row: wallIdx, col: c }; + if (maze[wallPos.row]?.[wallPos.col]?.includes('exit')) { + return wallPos; + } + } + + return edgeCell; + } + rr = next; + } + } + } function validatePath(from: Coord, direction: Coord, steps: number): boolean { if (!maze.length) return false; diff --git a/src/useCursor/useCursor.ts b/src/useCursor/useCursor.ts index 710b000..dda5b6c 100644 --- a/src/useCursor/useCursor.ts +++ b/src/useCursor/useCursor.ts @@ -61,29 +61,30 @@ export function useCursor(board: BoardManager, gameStatusManager: GameStatusMana move(0, 1, count); } - function moveToAnchor(target: 'start' | 'end' | 'top' | 'bottom'): void { - const currentPos = position.current; - const direction = target === 'start' ? 'left' : - target === 'end' ? 'right' : - target === 'top' ? 'top' : 'bottom'; + function moveToAnchor(target: 'start' | 'end' | 'top' | 'bottom'): void { + const currentPos = position.current; + const direction = target === 'start' ? 'left' : + target === 'end' ? 'right' : + target === 'top' ? 'top' : 'bottom'; - const anchorTarget = navigator.findAnchorTarget(currentPos, direction); - if (!anchorTarget) return; + const hasKey = gameStatusManager.gameStatus === 'has-key'; + const anchorTarget = navigator.findAnchorTarget(currentPos, direction, hasKey); + if (!anchorTarget) return; - const dr = anchorTarget.row > currentPos.row ? 1 : - anchorTarget.row < currentPos.row ? -1 : 0; - const dc = anchorTarget.col > currentPos.col ? 1 : - anchorTarget.col < currentPos.col ? -1 : 0; - const steps = Math.abs(anchorTarget.row - currentPos.row) + Math.abs(anchorTarget.col - currentPos.col); + const dr = anchorTarget.row > currentPos.row ? 1 : + anchorTarget.row < currentPos.row ? -1 : 0; + const dc = anchorTarget.col > currentPos.col ? 1 : + anchorTarget.col < currentPos.col ? -1 : 0; + const steps = Math.abs(anchorTarget.row - currentPos.row) + Math.abs(anchorTarget.col - currentPos.col); - position.current = anchorTarget; - if (hero && hero.heroPos) { - hero.moveTo(anchorTarget); - if (steps > 0) { - vimMotions.setLastMotion({ dr, dc, steps }); - } - } - } + position.current = anchorTarget; + if (hero && hero.heroPos) { + hero.moveTo(anchorTarget); + if (steps > 0) { + vimMotions.setLastMotion({ dr, dc, steps }); + } + } + } function moveToStart(): void { const currentPos = position.current;