diff --git a/IMPLEMENTATION.md b/IMPLEMENTATION.md index acf967c..a227bb6 100644 --- a/IMPLEMENTATION.md +++ b/IMPLEMENTATION.md @@ -982,12 +982,115 @@ Back in normal mode (blue cursor) - ✅ All validation rules working correctly ### Next Steps -- Phase 40.3.5: Add erase functionality (x, Backspace, Delete) - Validation and conflict detection - Win condition checking --- -## Iteration 11: [Pending] +## Iteration 11: Phase 40.3.5 - Erase Functionality + +**Date**: 2025-01-22 + +### Goals +- Implement erase commands to clear user-entered digits +- Different behavior in normal vs edit mode +- Always respect given cell protection + +### Tasks Completed + +#### 1. Normal Mode Erase (x, d, Delete) +**Keys: `x`, `d`, `Delete`** +- Only work on user-entered cells +- Set cell value to '.' (empty) +- Flash red if cell is given or already empty + +**Validation Logic:** +```typescript +if (key === 'x' || key === 'd' || key === 'Delete') { + const isGiven = targetCell.classList.contains('given'); + const isUserEntered = targetCell.classList.contains('user-entered'); + + if (isGiven || !isUserEntered) { + flashInvalidMove(); + return; + } + + boardManager.setCell(position.row, position.col, '.'); + return; +} +``` + +#### 2. Edit Mode Erase (Backspace) +**Key: `Backspace`** +- Works in edit mode only +- Erases current cell value +- Flash red if cell is given +- Stay in edit mode after erasing + +**Implementation:** +```typescript +if (key === 'Backspace') { + const targetCell = cells[index]; + + if (targetCell && targetCell.classList.contains('given')) { + flashInvalidMove(); + return; + } + + boardManager.setCell(position.row, position.col, '.'); + return; +} +``` + +#### 3. Normal Mode Backspace Protection +**Key: `Backspace` in normal mode** +- Always triggers red flash (invalid move) +- Prevents accidental cell clearing in normal mode +- User must use x, d, or Delete explicitly + +### Erase Command Rules + +| Mode | Key | Empty Cell | User-Entered Cell | Given Cell | +|------|-----|------------|-------------------|------------| +| Normal | `x`, `d`, `Delete` | ❌ Red flash | ✅ Erase to '.' | ❌ Red flash | +| Normal | `Backspace` | ❌ Red flash | ❌ Red flash | ❌ Red flash | +| Edit | `Backspace` | ✅ Erase (noop) | ✅ Erase to '.' | ❌ Red flash | + +### Technical Details + +**Cell State After Erase:** +- Board string updated with '.' at cell index +- Cell loses `.user-entered` class on next render +- Cell becomes empty and eligible for `i` command again + +**Flow Example:** +``` +User enters '5' in cell with 'i' + ↓ +Cell has .user-entered class, displays '5' + ↓ +Press Escape → normal mode + ↓ +Press 'x' or 'd' or Delete + ↓ +boardManager.setCell(row, col, '.') + ↓ +Board re-renders, cell is empty + ↓ +Cell loses .user-entered, can use 'i' again +``` + +### Build Status +- ✅ TypeScript compiles cleanly +- ✅ No type errors +- ✅ All erase commands working correctly + +### Next Steps +- Validation and conflict detection +- Win condition checking + +--- + +## Iteration 12: [Pending] *To be filled as implementation progresses...* diff --git a/src/useCursor/useCursor.ts b/src/useCursor/useCursor.ts index c9a8373..ae8f585 100644 --- a/src/useCursor/useCursor.ts +++ b/src/useCursor/useCursor.ts @@ -112,6 +112,50 @@ export function useCursor(gameStatusManager: GameStatusManager, containerRef: Re return; } + if (key === 'Backspace') { + const container = containerRef.current; + if (!container) return; + + const cells = container.querySelectorAll('.sudoku-cell'); + const index = position.row * 9 + position.col; + const targetCell = cells[index]; + + if (targetCell && targetCell.classList.contains('given')) { + flashInvalidMove(); + return; + } + + boardManager.setCell(position.row, position.col, '.'); + return; + } + + return; + } + + if (key === 'x' || key === 'd' || key === 'Delete') { + const container = containerRef.current; + if (!container) return; + + const cells = container.querySelectorAll('.sudoku-cell'); + const index = position.row * 9 + position.col; + const targetCell = cells[index]; + + if (!targetCell) return; + + const isGiven = targetCell.classList.contains('given'); + const isUserEntered = targetCell.classList.contains('user-entered'); + + if (isGiven || !isUserEntered) { + flashInvalidMove(); + return; + } + + boardManager.setCell(position.row, position.col, '.'); + return; + } + + if (key === 'Backspace') { + flashInvalidMove(); return; }