anchor moves all work except zero. <dot> also working
This commit is contained in:
@@ -321,6 +321,7 @@ The unified API is designed to accommodate:
|
|||||||
- ✅ **Specialized hooks** - Complete (useMazeNavigation, useVimMotions, useAnimation)
|
- ✅ **Specialized hooks** - Complete (useMazeNavigation, useVimMotions, useAnimation)
|
||||||
- ✅ **Single source of truth** - Complete (hero position as authoritative)
|
- ✅ **Single source of truth** - Complete (hero position as authoritative)
|
||||||
- ✅ **React-first architecture** - Complete (state-driven rendering)
|
- ✅ **React-first architecture** - Complete (state-driven rendering)
|
||||||
|
- ✅ **Hero movement implementation** - Complete (hjkl, anchors, repeat with counts)
|
||||||
- ✅ **Platform integration** - Ready
|
- ✅ **Platform integration** - Ready
|
||||||
- ⏳ **Advanced features** - Pending (scoring, animations, etc.)
|
- ⏳ **Advanced features** - Pending (scoring, animations, etc.)
|
||||||
|
|
||||||
|
|||||||
@@ -26,43 +26,35 @@ export function useMazeNavigation(maze: MazeCell[][]): MazeNavigator {
|
|||||||
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) return null;
|
if (next < 0 || next >= colsCount) break;
|
||||||
if (maze[r][next].includes('wall')) {
|
if (maze[r][next].includes('wall')) break;
|
||||||
const wallIdx = next;
|
if (!maze[r][next].includes('wall')) {
|
||||||
const expectedWallIdx = direction === 'left' ? 0 : colsCount - 1;
|
lastValidPos = { row: r, col: next };
|
||||||
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 };
|
|
||||||
}
|
}
|
||||||
cc = next;
|
cc = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return lastValidPos.col !== c ? lastValidPos : null;
|
||||||
} else {
|
} else {
|
||||||
const step = direction === 'top' ? -1 : 1;
|
const step = direction === 'top' ? -1 : 1;
|
||||||
let rr = r;
|
let rr = r;
|
||||||
|
let lastValidPos = { row: r, col: c };
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const next = rr + step;
|
const next = rr + step;
|
||||||
if (next < 0 || next >= rowsCount) return null;
|
if (next < 0 || next >= rowsCount) break;
|
||||||
if (maze[next][c].includes('wall')) {
|
if (maze[next][c].includes('wall')) break;
|
||||||
const wallIdx = next;
|
if (!maze[next][c].includes('wall')) {
|
||||||
const expectedWallIdx = direction === 'top' ? 0 : rowsCount - 1;
|
lastValidPos = { row: next, col: c };
|
||||||
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 };
|
|
||||||
}
|
}
|
||||||
rr = next;
|
rr = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return lastValidPos.row !== r ? lastValidPos : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,10 @@ export function useCursor(board: BoardManager, gameStatusManager: GameStatusMana
|
|||||||
}
|
}
|
||||||
|
|
||||||
position.current = targetCoord;
|
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 {
|
function moveLeft(count = 1): void {
|
||||||
@@ -73,7 +77,13 @@ export function useCursor(board: BoardManager, gameStatusManager: GameStatusMana
|
|||||||
anchorTarget.col < currentPos.col ? -1 : 0;
|
anchorTarget.col < currentPos.col ? -1 : 0;
|
||||||
const steps = Math.abs(anchorTarget.row - currentPos.row) + Math.abs(anchorTarget.col - currentPos.col);
|
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 {
|
function moveToStart(): void {
|
||||||
@@ -94,9 +104,20 @@ export function useCursor(board: BoardManager, gameStatusManager: GameStatusMana
|
|||||||
|
|
||||||
function repeatLastMotion(): void {
|
function repeatLastMotion(): void {
|
||||||
const motion = vimMotions.repeatLastMotion();
|
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 {
|
function resetCount(): void {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ const RELEVANT_KEYS = new Set([
|
|||||||
|
|
||||||
export const useGameKeys = (props: UseGameKeysParams) => {
|
export const useGameKeys = (props: UseGameKeysParams) => {
|
||||||
const { cursor, gameStatusManager } = props;
|
const { cursor, gameStatusManager } = props;
|
||||||
const { gameStatus, setGameStatus } = gameStatusManager;
|
const { gameStatus } = gameStatusManager;
|
||||||
const [keyLog, setKeyLog] = useState<KeyLogEntry[]>([]);
|
const [keyLog, setKeyLog] = useState<KeyLogEntry[]>([]);
|
||||||
const logRef = useRef<KeyLogEntry[]>([]);
|
const logRef = useRef<KeyLogEntry[]>([]);
|
||||||
const { hero } = cursor;
|
const { hero } = cursor;
|
||||||
@@ -96,16 +96,15 @@ export const useGameKeys = (props: UseGameKeysParams) => {
|
|||||||
const count = Math.max(1, parseInt(cursor.getCount() || "1", 10));
|
const count = Math.max(1, parseInt(cursor.getCount() || "1", 10));
|
||||||
cursor.resetCount();
|
cursor.resetCount();
|
||||||
|
|
||||||
if (!hero) return;
|
|
||||||
switch (ev.key) {
|
switch (ev.key) {
|
||||||
case "h":
|
case "h":
|
||||||
case "H": hero.moveHero(0, -1, count, gameStatus, setGameStatus); break;
|
case "H": cursor.moveLeft(count); break;
|
||||||
case "j":
|
case "j":
|
||||||
case "J": hero.moveHero(1, 0, count, gameStatus, setGameStatus); break;
|
case "J": cursor.moveDown(count); break;
|
||||||
case "k":
|
case "k":
|
||||||
case "K": hero.moveHero(-1, 0, count, gameStatus, setGameStatus); break;
|
case "K": cursor.moveUp(count); break;
|
||||||
case "l":
|
case "l":
|
||||||
case "L": hero.moveHero(0, 1, count, gameStatus, setGameStatus); break;
|
case "L": cursor.moveRight(count); break;
|
||||||
default: return;
|
default: return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user