|
| 1 | +# SpeedChess — Copilot Instructions |
| 2 | + |
| 3 | +Project conventions and gotchas for AI agents working in this repository. |
| 4 | + |
| 5 | +## Stack |
| 6 | + |
| 7 | +- React 19 + TypeScript (strict), Vite 8, `vite-plugin-pwa` |
| 8 | +- Vitest 3.2.4 (1400+ tests) |
| 9 | +- Deployed to GitHub Pages at `https://swon404.github.io/SpeedChess/` (base `/SpeedChess/`) |
| 10 | +- Dev server: `npm run dev` (port 5180) |
| 11 | +- `npm install` requires `--legacy-peer-deps` |
| 12 | + |
| 13 | +## Repo Layout |
| 14 | + |
| 15 | +- `src/engine/` — custom chess engine (no external chess library) |
| 16 | + - Board is `[rank][file]` 8×8 array; **rank 0 = white back rank** |
| 17 | + - `rules.ts` exports `legalMovesFrom`, `allLegalMoves`, `makeMove`, `gameResult`, `inCheck`, `teleportTargets`, `portalAt`, `findKing` |
| 18 | + - `bot.ts` — opponent AI; `notation.ts` — SAN/UCI helpers |
| 19 | +- `src/puzzles/` — puzzle databases (standard + portal) and React wrappers |
| 20 | +- `src/screens/` — top-level screens (`NewGameScreen`, `PuzzlesScreen`, etc.) |
| 21 | +- `src/components/` — UI (`Board.tsx`, etc.) |
| 22 | +- `src/GameContext.tsx` — global game state context |
| 23 | +- `scripts/` — one-off tsx scripts (puzzle import, asset cropping) |
| 24 | + |
| 25 | +## FEN Conventions |
| 26 | + |
| 27 | +- FEN strings must have **at least 4 fields**: `placement turn castling ep` (halfmove/fullmove optional). |
| 28 | +- Square color: `(file + rank) % 2 === 0 ? "dark" : "light"` (file/rank are 0-indexed). |
| 29 | + |
| 30 | +## Portal Chess Mechanics |
| 31 | + |
| 32 | +Portal Chess is a custom variant. Key rules when generating/validating puzzles: |
| 33 | + |
| 34 | +- Each side has at most one active portal square (`state.portals[color]`). |
| 35 | +- A piece type is designated `creator` per color (`state.portalCreators[color]`). The creator is **exempt** from teleporting through its own portal. |
| 36 | + - With `creator: "K"`, all Q/R/B/N pieces from that side teleport on entering their portal. |
| 37 | +- When a non-creator piece moves onto its own portal square, teleport is **forced** (not optional). |
| 38 | +- `teleportTargets(state, from, color)` returns the portal square plus all empty squares (excluding `from` and the portal square). Bishops are restricted to squares matching the portal-square color. |
| 39 | +- When the **creator** piece moves and `state.portals[color] === null`, a portal **auto-drops** at the landing square. |
| 40 | +- Extended UCI for portal moves: `"e2e4@d8"` = move to `e4` (which is the portal), then teleport to `d8`. |
| 41 | + |
| 42 | +## Puzzle Generation Pattern (`portal-puzzle-db.ts`) |
| 43 | + |
| 44 | +Generators emit `RawCandidate[]` and `build()` validates each one by replaying moves through the engine. Invalid candidates (illegal moves, intermediate mate, non-mate at end) are silently dropped — design speculatively, let `validate()` filter. |
| 45 | + |
| 46 | +```ts |
| 47 | +function validate(c: RawCandidate): boolean { |
| 48 | + let s: GameState | null = setupState(c); |
| 49 | + for (let i = 0; i < c.moves.length; i++) { |
| 50 | + s = applyMove(s, c.moves[i]); |
| 51 | + if (!s) return false; |
| 52 | + const r = gameResult(s); |
| 53 | + if (i === c.moves.length - 1) { |
| 54 | + if (r.kind !== "checkmate") return false; |
| 55 | + } else { |
| 56 | + if (r.kind !== "ongoing") return false; |
| 57 | + } |
| 58 | + } |
| 59 | + return true; |
| 60 | +} |
| 61 | +``` |
| 62 | + |
| 63 | +Pitfalls observed: |
| 64 | +- Direct (non-portal) mates leak: e.g. rook on a-file slides to `a7` without using portal. Exclude conflicting source files when generating. |
| 65 | +- Defenders may block: long-diagonal bishop mates fail when a defender rook can interpose. Prefer adjacent diagonal mates with pawn/queen support. |
| 66 | +- Creator-king dropping a portal at its own landing square blocks the rook's path (king occupies the portal). Workarounds are non-trivial. |
| 67 | + |
| 68 | +## Testing & Shipping |
| 69 | + |
| 70 | +Standard ship workflow (PowerShell): |
| 71 | + |
| 72 | +```powershell |
| 73 | +npm run build 2>&1 | Select-Object -Last 4 |
| 74 | +git add -A |
| 75 | +git commit -m "..." |
| 76 | +git push |
| 77 | +``` |
| 78 | + |
| 79 | +- Run all tests: `npx vitest run 2>&1 | Select-Object -Last 8` |
| 80 | +- Run a file: `npx vitest run path/to/file.test.ts 2>&1 | Select-Object -Last 10` |
| 81 | +- Tests live under `src/**/__tests__/*.test.ts` |
| 82 | +- Don't leave throwaway debug tests committed (`debug-*.test.ts`, `*-stats.test.ts`) |
| 83 | + |
| 84 | +## Coding Conventions |
| 85 | + |
| 86 | +- TypeScript strict mode — no implicit `any`, no unchecked nulls. |
| 87 | +- Engine code is pure/functional: state transitions return new objects rather than mutating. |
| 88 | +- React components use hooks + context (`GameContext`); no Redux. |
| 89 | +- Avoid adding chess libraries; extend the in-house engine. |
| 90 | +- Don't add docstrings/comments to code you didn't change. |
| 91 | + |
| 92 | +## Operational |
| 93 | + |
| 94 | +- OS: Windows; shell: PowerShell. Chain commands with `;`, never `&&`. |
| 95 | +- Don't `Start-Sleep` after async commands — terminal output notifications arrive automatically. |
0 commit comments