anchor moves all work except zero. <dot> also working

This commit is contained in:
2025-10-19 13:51:57 +01:00
parent b6f5d7ae9f
commit aa42066f57
4 changed files with 44 additions and 31 deletions
+1
View File
@@ -321,6 +321,7 @@ The unified API is designed to accommodate:
- ✅ **Specialized hooks** - Complete (useMazeNavigation, useVimMotions, useAnimation)
- ✅ **Single source of truth** - Complete (hero position as authoritative)
- ✅ **React-first architecture** - Complete (state-driven rendering)
- ✅ **Hero movement implementation** - Complete (hjkl, anchors, repeat with counts)
- ✅ **Platform integration** - Ready
- ⏳ **Advanced features** - Pending (scoring, animations, etc.)
+14 -22
View File
@@ -26,43 +26,35 @@ export function useMazeNavigation(maze: MazeCell[][]): MazeNavigator {
if (direction === 'left' || direction === 'right') {
const step = direction === 'left' ? -1 : 1;
let cc = c;
let lastValidPos = { row: r, col: c };
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;
return { row: r, col: cc };
if (next < 0 || next >= colsCount) break;
if (maze[r][next].includes('wall')) break;
if (!maze[r][next].includes('wall')) {
lastValidPos = { row: r, col: next };
}
cc = next;
}
return lastValidPos.col !== c ? lastValidPos : null;
} else {
const step = direction === 'top' ? -1 : 1;
let rr = r;
let lastValidPos = { row: r, col: c };
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;
return { row: rr, col: c };
if (next < 0 || next >= rowsCount) break;
if (maze[next][c].includes('wall')) break;
if (!maze[next][c].includes('wall')) {
lastValidPos = { row: next, col: c };
}
rr = next;
}
return lastValidPos.row !== r ? lastValidPos : null;
}
}
+24 -3
View File
@@ -37,6 +37,10 @@ export function useCursor(board: BoardManager, gameStatusManager: GameStatusMana
}
position.current = targetCoord;
if (hero && hero.heroPos) {
hero.moveHero(dRows, dCols, steps, gameStatusManager.gameStatus, gameStatusManager.setGameStatus);
vimMotions.setLastMotion({ dr: dRows, dc: dCols, steps });
}
}
function moveLeft(count = 1): void {
@@ -73,7 +77,13 @@ export function useCursor(board: BoardManager, gameStatusManager: GameStatusMana
anchorTarget.col < currentPos.col ? -1 : 0;
const steps = Math.abs(anchorTarget.row - currentPos.row) + Math.abs(anchorTarget.col - currentPos.col);
move(dc, dr, steps);
position.current = anchorTarget;
if (hero && hero.heroPos) {
hero.moveTo(anchorTarget);
if (steps > 0) {
vimMotions.setLastMotion({ dr, dc, steps });
}
}
}
function moveToStart(): void {
@@ -94,9 +104,20 @@ export function useCursor(board: BoardManager, gameStatusManager: GameStatusMana
function repeatLastMotion(): void {
const motion = vimMotions.repeatLastMotion();
if (!motion) return;
if (!motion || !hero || !hero.heroPos) return;
move(motion.dc, motion.dr, motion.steps);
const currentPos = position.current;
const targetCoord = {
row: currentPos.row + motion.dr * motion.steps,
col: currentPos.col + motion.dc * motion.steps
};
if (navigator.validatePath(currentPos, { row: motion.dr, col: motion.dc }, motion.steps)) {
position.current = targetCoord;
hero.moveHero(motion.dr, motion.dc, motion.steps, gameStatusManager.gameStatus, gameStatusManager.setGameStatus);
} else {
window.dispatchEvent(new Event("maze-invalid"));
}
}
function resetCount(): void {
+5 -6
View File
@@ -14,7 +14,7 @@ const RELEVANT_KEYS = new Set([
export const useGameKeys = (props: UseGameKeysParams) => {
const { cursor, gameStatusManager } = props;
const { gameStatus, setGameStatus } = gameStatusManager;
const { gameStatus } = gameStatusManager;
const [keyLog, setKeyLog] = useState<KeyLogEntry[]>([]);
const logRef = useRef<KeyLogEntry[]>([]);
const { hero } = cursor;
@@ -96,16 +96,15 @@ export const useGameKeys = (props: UseGameKeysParams) => {
const count = Math.max(1, parseInt(cursor.getCount() || "1", 10));
cursor.resetCount();
if (!hero) return;
switch (ev.key) {
case "h":
case "H": hero.moveHero(0, -1, count, gameStatus, setGameStatus); break;
case "H": cursor.moveLeft(count); break;
case "j":
case "J": hero.moveHero(1, 0, count, gameStatus, setGameStatus); break;
case "J": cursor.moveDown(count); break;
case "k":
case "K": hero.moveHero(-1, 0, count, gameStatus, setGameStatus); break;
case "K": cursor.moveUp(count); break;
case "l":
case "L": hero.moveHero(0, 1, count, gameStatus, setGameStatus); break;
case "L": cursor.moveRight(count); break;
default: return;
}
};