proper anchor invalidation
This commit is contained in:
@@ -14,64 +14,72 @@ export function useMazeNavigation(maze: MazeCell[][]): MazeNavigator {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function findAnchorTarget(from: Coord, direction: 'left'|'right'|'top'|'bottom'): Coord | null {
|
function findAnchorTarget(from: Coord, direction: 'left'|'right'|'top'|'bottom'): Coord | null {
|
||||||
if (!maze.length) return null;
|
if (!maze.length) return null;
|
||||||
|
|
||||||
const rowsCount = maze.length;
|
const rowsCount = maze.length;
|
||||||
const colsCount = maze[0]?.length ?? 0;
|
const colsCount = maze[0]?.length ?? 0;
|
||||||
const { row: r, col: c } = from;
|
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') {
|
if (direction === 'left' || direction === 'right') {
|
||||||
const step = direction === 'left' ? -1 : 1;
|
const step = direction === 'left' ? -1 : 1;
|
||||||
let cc = c;
|
let cc = c;
|
||||||
let lastValidPos = { row: r, col: c };
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const next = cc + step;
|
const next = cc + step;
|
||||||
if (next < 0 || next >= colsCount) break;
|
if (next < 0 || next >= colsCount) return null;
|
||||||
if (maze[r][next].includes('wall')) break;
|
if (maze[r][next].includes('wall')) {
|
||||||
if (!maze[r][next].includes('wall')) {
|
const wallIdx = next;
|
||||||
lastValidPos = { row: r, col: next };
|
const expectedWallIdx = direction === 'left' ? 0 : colsCount - 1;
|
||||||
}
|
const expectedCellIdx = direction === 'left' ? 1 : colsCount - 2;
|
||||||
cc = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
return lastValidPos.col !== c ? lastValidPos : null;
|
if (wallIdx !== expectedWallIdx) return null;
|
||||||
} else {
|
if (cc !== expectedCellIdx) return null;
|
||||||
const step = direction === 'top' ? -1 : 1;
|
if (cc === c) return null;
|
||||||
let rr = r;
|
|
||||||
let lastValidPos = { row: r, col: c };
|
|
||||||
|
|
||||||
while (true) {
|
return { row: r, col: cc };
|
||||||
const next = rr + step;
|
}
|
||||||
if (next < 0 || next >= rowsCount) break;
|
cc = next;
|
||||||
if (maze[next][c].includes('wall')) break;
|
}
|
||||||
if (!maze[next][c].includes('wall')) {
|
} else {
|
||||||
lastValidPos = { row: next, col: c };
|
const step = direction === 'top' ? -1 : 1;
|
||||||
}
|
let rr = r;
|
||||||
rr = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
return lastValidPos.row !== r ? lastValidPos : 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;
|
||||||
|
|
||||||
function validatePath(from: Coord, direction: Coord, steps: number): boolean {
|
if (wallIdx !== expectedWallIdx) return null;
|
||||||
if (!maze.length) return false;
|
if (rr !== expectedCellIdx) return null;
|
||||||
|
if (rr === r) return null;
|
||||||
|
|
||||||
let r = from.row;
|
return { row: rr, col: c };
|
||||||
let c = from.col;
|
}
|
||||||
|
rr = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (let i = 1; i <= steps; i++) {
|
function validatePath(from: Coord, direction: Coord, steps: number): boolean {
|
||||||
r += direction.row;
|
if (!maze.length) return false;
|
||||||
c += direction.col;
|
|
||||||
if (!isValidMove(from, { row: r, col: c })) return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
let r = from.row;
|
||||||
}
|
let c = from.col;
|
||||||
|
|
||||||
|
for (let i = 1; i <= steps; i++) {
|
||||||
|
r += direction.row;
|
||||||
|
c += direction.col;
|
||||||
|
if (!isValidMove(from, { row: r, col: c })) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isValidMove,
|
isValidMove,
|
||||||
|
|||||||
+70
-38
@@ -5,6 +5,25 @@ import { useGameKeys } from './useGameKeys';
|
|||||||
import { useMazeNavigation } from '../useBoard';
|
import { useMazeNavigation } from '../useBoard';
|
||||||
import { useVimMotions } from './useVimMotions';
|
import { useVimMotions } from './useVimMotions';
|
||||||
|
|
||||||
|
function validateAnchorMove(direction: 'start' | 'end' | 'top' | 'bottom', currentPos: Coord, board: BoardManager): boolean {
|
||||||
|
const navDirection = direction === 'start' ? 'left' :
|
||||||
|
direction === 'end' ? 'right' :
|
||||||
|
direction === 'top' ? 'top' : 'bottom';
|
||||||
|
|
||||||
|
const navigator = useMazeNavigation(board.mazeRef.current);
|
||||||
|
const target = navigator.findAnchorTarget(currentPos, navDirection);
|
||||||
|
|
||||||
|
if (!target) return false;
|
||||||
|
|
||||||
|
const dr = target.row > currentPos.row ? 1 :
|
||||||
|
target.row < currentPos.row ? -1 : 0;
|
||||||
|
const dc = target.col > currentPos.col ? 1 :
|
||||||
|
target.col < currentPos.col ? -1 : 0;
|
||||||
|
const steps = Math.abs(target.row - currentPos.row) + Math.abs(target.col - currentPos.col);
|
||||||
|
|
||||||
|
return navigator.validatePath(currentPos, { row: dr, col: dc }, steps);
|
||||||
|
}
|
||||||
|
|
||||||
export function useCursor(board: BoardManager, gameStatusManager: GameStatusManager) {
|
export function useCursor(board: BoardManager, gameStatusManager: GameStatusManager) {
|
||||||
const position = useRef<Coord>({ row: 0, col: 0 })
|
const position = useRef<Coord>({ row: 0, col: 0 })
|
||||||
const mode = useRef<CursorMode>('normal')
|
const mode = useRef<CursorMode>('normal')
|
||||||
@@ -25,7 +44,7 @@ export function useCursor(board: BoardManager, gameStatusManager: GameStatusMana
|
|||||||
const currentPos = position.current;
|
const currentPos = position.current;
|
||||||
const steps = Math.max(1, count);
|
const steps = Math.max(1, count);
|
||||||
const direction = { row: dRows, col: dCols };
|
const direction = { row: dRows, col: dCols };
|
||||||
|
|
||||||
const targetCoord = {
|
const targetCoord = {
|
||||||
row: currentPos.row + direction.row * steps,
|
row: currentPos.row + direction.row * steps,
|
||||||
col: currentPos.col + direction.col * steps
|
col: currentPos.col + direction.col * steps
|
||||||
@@ -59,53 +78,66 @@ export function useCursor(board: BoardManager, gameStatusManager: GameStatusMana
|
|||||||
move(0, 1, count);
|
move(0, 1, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
function moveToAnchor(target: 'start'|'end'|'top'|'bottom'): void {
|
function moveToAnchor(target: 'start' | 'end' | 'top' | 'bottom'): void {
|
||||||
const currentPos = position.current;
|
const currentPos = position.current;
|
||||||
const direction = target === 'start' ? 'left' :
|
const direction = target === 'start' ? 'left' :
|
||||||
target === 'end' ? 'right' :
|
target === 'end' ? 'right' :
|
||||||
target === 'top' ? 'top' : 'bottom';
|
target === 'top' ? 'top' : 'bottom';
|
||||||
|
|
||||||
const anchorTarget = navigator.findAnchorTarget(currentPos, direction);
|
|
||||||
if (!anchorTarget) {
|
|
||||||
window.dispatchEvent(new Event("maze-invalid"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const dr = anchorTarget.row > currentPos.row ? 1 :
|
const anchorTarget = navigator.findAnchorTarget(currentPos, direction);
|
||||||
anchorTarget.row < currentPos.row ? -1 : 0;
|
if (!anchorTarget) return;
|
||||||
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;
|
const dr = anchorTarget.row > currentPos.row ? 1 :
|
||||||
if (hero && hero.heroPos) {
|
anchorTarget.row < currentPos.row ? -1 : 0;
|
||||||
hero.moveTo(anchorTarget);
|
const dc = anchorTarget.col > currentPos.col ? 1 :
|
||||||
if (steps > 0) {
|
anchorTarget.col < currentPos.col ? -1 : 0;
|
||||||
vimMotions.setLastMotion({ dr, dc, steps });
|
const steps = Math.abs(anchorTarget.row - currentPos.row) + Math.abs(anchorTarget.col - currentPos.col);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function moveToStart(): void {
|
position.current = anchorTarget;
|
||||||
moveToAnchor('start');
|
if (hero && hero.heroPos) {
|
||||||
}
|
hero.moveTo(anchorTarget);
|
||||||
|
if (steps > 0) {
|
||||||
|
vimMotions.setLastMotion({ dr, dc, steps });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function moveToEnd(): void {
|
function moveToStart(): void {
|
||||||
moveToAnchor('end');
|
if (!validateAnchorMove('start', position.current, board)) {
|
||||||
}
|
window.dispatchEvent(new Event("maze-invalid"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
moveToAnchor('start');
|
||||||
|
}
|
||||||
|
|
||||||
function moveToTop(): void {
|
function moveToEnd(): void {
|
||||||
moveToAnchor('top');
|
if (!validateAnchorMove('end', position.current, board)) {
|
||||||
}
|
window.dispatchEvent(new Event("maze-invalid"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
moveToAnchor('end');
|
||||||
|
}
|
||||||
|
|
||||||
function moveToBottom(): void {
|
function moveToTop(): void {
|
||||||
moveToAnchor('bottom');
|
if (!validateAnchorMove('top', position.current, board)) {
|
||||||
}
|
window.dispatchEvent(new Event("maze-invalid"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
moveToAnchor('top');
|
||||||
|
}
|
||||||
|
|
||||||
|
function moveToBottom(): void {
|
||||||
|
if (!validateAnchorMove('bottom', position.current, board)) {
|
||||||
|
window.dispatchEvent(new Event("maze-invalid"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
moveToAnchor('bottom');
|
||||||
|
}
|
||||||
|
|
||||||
function repeatLastMotion(): void {
|
function repeatLastMotion(): void {
|
||||||
const motion = vimMotions.repeatLastMotion();
|
const motion = vimMotions.repeatLastMotion();
|
||||||
if (!motion || !hero || !hero.heroPos) return;
|
if (!motion || !hero || !hero.heroPos) return;
|
||||||
|
|
||||||
const currentPos = position.current;
|
const currentPos = position.current;
|
||||||
const targetCoord = {
|
const targetCoord = {
|
||||||
row: currentPos.row + motion.dr * motion.steps,
|
row: currentPos.row + motion.dr * motion.steps,
|
||||||
|
|||||||
Reference in New Issue
Block a user