c2f035acc0
- Mark ChessViewModel, navigation, relay subscriptions as complete - Update file structure to reflect KMP commons migration - Update checklist with completed items - Revise next steps to focus on FAB and badge display Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
267 lines
10 KiB
Markdown
267 lines
10 KiB
Markdown
# Live Chess Implementation Status
|
|
|
|
## ✅ Completed Implementation
|
|
|
|
### 1. Chess Engine & Move Validation
|
|
- **kchesslib dependency** added to `quartz/build.gradle.kts:150`
|
|
- **ChessEngine** interface with expect/actual pattern:
|
|
- `ChessEngine.kt` (commonMain) - Platform-agnostic API
|
|
- `ChessEngine.jvmAndroid.kt` (jvmAndroid) - kchesslib implementation
|
|
- **Full move validation**: Legal moves, check/checkmate, castling, en passant, pawn promotion
|
|
- **FEN import/export**: Board state serialization
|
|
- **Move history tracking**: SAN notation
|
|
|
|
### 2. Interactive UI Components (commons/)
|
|
- **InteractiveChessBoard.kt**: Click-to-move with visual feedback
|
|
- Selected piece highlighting (green)
|
|
- Legal move indicators (circles/rings)
|
|
- Automatic move validation
|
|
- Callback system for move events
|
|
|
|
- **LiveChessGame.kt**: Complete game UI
|
|
- NewChessGameDialog (challenge creation)
|
|
- LiveChessGameScreen (full game interface)
|
|
- GameInfoHeader (turn indicator, game status)
|
|
- MoveHistoryDisplay (SAN move list)
|
|
- GameControls (Resign, Offer Draw)
|
|
|
|
### 3. Nostr Event Protocol (quartz/nip64Chess/)
|
|
**New Event Kinds:**
|
|
| Kind | Event | Purpose |
|
|
|------|-------|---------|
|
|
| 30064 | LiveChessGameChallengeEvent | Create/accept challenges |
|
|
| 30065 | LiveChessGameAcceptEvent | Accept challenge |
|
|
| 30066 | LiveChessMoveEvent | Individual moves (SAN + FEN) |
|
|
| 30067 | LiveChessGameEndEvent | Game result & termination |
|
|
|
|
**Event Factory Integration** (EventFactory.kt:190-193):
|
|
- All live chess events registered for automatic parsing
|
|
|
|
### 4. Game State Management
|
|
- **LiveChessGameState.kt**: Coordinates engine, Nostr, and UI
|
|
- Turn validation
|
|
- Move synchronization
|
|
- Automatic end detection (checkmate/stalemate)
|
|
- PGN generation
|
|
- Position mismatch recovery
|
|
|
|
### 5. ChessViewModel (amethyst/ui/screen/loggedIn/chess/)
|
|
- **ChessViewModel.kt**: Full game state management & event publishing
|
|
- `activeGames: StateFlow<Map<String, LiveChessGameState>>` - Active games by ID
|
|
- `challenges: StateFlow<List<Note>>` - Incoming/outgoing challenges
|
|
- `badgeCount: StateFlow<Int>` - Notification count
|
|
- `createChallenge()` - Create open or directed challenges
|
|
- `acceptChallenge()` - Accept challenge and start game
|
|
- `publishMove()` - Send moves to relays
|
|
- `resign()` / `offerDraw()` - End game actions
|
|
- **Relay subscriptions** via `LocalCache.live.newEventBundles`
|
|
- Auto-handles incoming moves, acceptances, endings, challenges
|
|
|
|
- **ChessViewModelFactory.kt**: ViewModel factory with Account injection
|
|
- **ChessGameScreen.kt**: Wrapper connecting ViewModel to LiveChessGameScreen UI
|
|
|
|
### 6. Feed Integration
|
|
**Chess Feed Filter** (TopNavFilterState.kt:130-142):
|
|
- Shows Kind 64 (completed games)
|
|
- Shows Kind 30064 (challenges - open & directed)
|
|
- Shows Kind 30067 (game endings)
|
|
- Excludes Kind 30066 (individual moves - too noisy)
|
|
|
|
**Event Rendering** (Chess.kt, NoteCompose.kt):
|
|
- `RenderChessGame()` - Completed PGN games (Kind 64)
|
|
- `RenderLiveChessChallenge()` - Challenge cards with visual states:
|
|
- 🔓 **Open challenges** (green border)
|
|
- 💌 **Incoming challenges** (orange border)
|
|
- ⏳ **Sent challenges** (gray border)
|
|
- `RenderLiveChessGameEnd()` - Game results with PGN
|
|
|
|
## 🚧 Remaining Work
|
|
|
|
### Priority 1: FAB & Challenge Creation
|
|
**Files to modify:**
|
|
1. **HomeScreen.kt** or chess-specific screen
|
|
```kotlin
|
|
var showNewGameDialog by remember { mutableStateOf(false) }
|
|
|
|
Scaffold(
|
|
floatingActionButton = {
|
|
if (isChessFeed) {
|
|
FloatingActionButton(
|
|
onClick = { showNewGameDialog = true }
|
|
) {
|
|
Icon(Icons.Default.Add, "New Game")
|
|
}
|
|
}
|
|
}
|
|
)
|
|
|
|
if (showNewGameDialog) {
|
|
NewChessGameDialog(
|
|
onDismiss = { showNewGameDialog = false },
|
|
onCreateGame = { opponentPubkey, color ->
|
|
viewModel.createChallenge(opponentPubkey, color)
|
|
showNewGameDialog = false
|
|
}
|
|
)
|
|
}
|
|
```
|
|
|
|
### Priority 4: In-App Badges (Optional)
|
|
**Files to create:**
|
|
1. **BadgeProvider.kt** (commons/)
|
|
```kotlin
|
|
object ChessBadgeProvider {
|
|
fun getBadgeCount(
|
|
challenges: List<LiveChessGameChallengeEvent>,
|
|
activeGames: List<LiveChessGameState>,
|
|
userPubkey: String
|
|
): Int {
|
|
val incomingChallenges = challenges.count {
|
|
it.opponentPubkey() == userPubkey
|
|
}
|
|
val yourTurnGames = activeGames.count { it.isPlayerTurn() }
|
|
return incomingChallenges + yourTurnGames
|
|
}
|
|
}
|
|
```
|
|
|
|
2. **Badge Display** - Add to chess filter icon:
|
|
```kotlin
|
|
BadgedBox(badge = { Badge { Text("$count") } }) {
|
|
Icon(/* chess icon */)
|
|
}
|
|
```
|
|
|
|
## 📋 Implementation Checklist
|
|
|
|
### Phase 1: Basic Playability ✅ COMPLETE
|
|
- [x] Create ChessViewModel
|
|
- [x] Add navigation route for LiveChessGameScreen (Route.ChessGame exists)
|
|
- [x] Create ChessGameScreen wrapper
|
|
- [x] Wire up NewGameDialog → ViewModel.createChallenge()
|
|
- [x] Implement event publishing (challenges, moves, game end)
|
|
- [ ] Test: Create challenge, see it in feed
|
|
|
|
### Phase 2: Two-Player Functionality ✅ COMPLETE
|
|
- [x] Implement relay subscriptions for game events
|
|
- [x] Wire up move synchronization (publish/receive)
|
|
- [x] Handle challenge acceptance flow
|
|
- [ ] Test: Play complete game between two accounts
|
|
|
|
### Phase 3: Polish (IN PROGRESS)
|
|
- [ ] Add FAB to chess feed
|
|
- [ ] Implement badge counts display in nav
|
|
- [x] Add "Accept Challenge" button to incoming challenge cards
|
|
- [x] Add "View Game" navigation from challenge/game-end cards
|
|
- [ ] Handle edge cases (network errors, position desync, abandoned games)
|
|
|
|
### Phase 4: Persistence (Optional)
|
|
- [ ] Create Room entities for active games
|
|
- [ ] Store games locally for offline viewing
|
|
- [ ] Sync on app start
|
|
- [ ] Background service for "your turn" notifications
|
|
|
|
## 🎯 UX Decisions Implemented
|
|
|
|
Based on user choices:
|
|
|
|
1. ✅ **Entry Point**: FAB on Chess feed (pending UI implementation)
|
|
2. ✅ **Display**: Visual cards in one feed with borders/icons
|
|
3. ✅ **Discovery**: Open challenges shown in Chess feed (green border)
|
|
4. ✅ **Tap Action**: Navigate directly to full screen (pending nav)
|
|
5. ⏳ **Notifications**: In-app badge for counts (pending implementation)
|
|
6. ✅ **Filter Scope**: Meaningful events only (completed games, challenges, endings)
|
|
7. ⏳ **Storage**: Local cache + relay sync (pending Room/ViewModel)
|
|
8. ✅ **Input**: Click-to-move (already implemented)
|
|
|
|
## 🔧 Quick Start for Development
|
|
|
|
### Test the Chess Engine:
|
|
```kotlin
|
|
val engine = ChessEngine()
|
|
engine.reset()
|
|
val result = engine.makeMove("e2", "e4")
|
|
println("Move success: ${result.success}, SAN: ${result.san}")
|
|
```
|
|
|
|
### Test the Interactive Board:
|
|
```kotlin
|
|
@Composable
|
|
fun TestScreen() {
|
|
val engine = remember { ChessEngine().apply { reset() } }
|
|
InteractiveChessBoard(
|
|
engine = engine,
|
|
onMoveMade = { san -> println("Move made: $san") }
|
|
)
|
|
}
|
|
```
|
|
|
|
### View Chess Feed:
|
|
1. Open Amethyst
|
|
2. Select "Chess" from home feed dropdown
|
|
3. See completed games (Kind 64)
|
|
4. See challenges with colored borders (Kind 30064)
|
|
5. See game endings with results (Kind 30067)
|
|
|
|
## 📁 File Structure
|
|
|
|
```
|
|
AmethystMultiplatform/
|
|
├── quartz/ # Protocol layer (KMP)
|
|
│ ├── src/commonMain/kotlin/.../nip64Chess/
|
|
│ │ ├── ChessEngine.kt ✅ Engine interface
|
|
│ │ ├── ChessPosition.kt ✅ Board state
|
|
│ │ ├── ChessMove.kt ✅ Move representation
|
|
│ │ ├── ChessGame.kt ✅ Game model
|
|
│ │ ├── PGNParser.kt ✅ PGN parsing (31 tests)
|
|
│ │ ├── ChessGameEvent.kt ✅ Kind 64
|
|
│ │ ├── LiveChessEvents.kt ✅ Data classes
|
|
│ │ ├── LiveChessGameEvents.kt ✅ Kind 30064-30067
|
|
│ │ └── LiveChessGameState.kt ✅ Game coordinator
|
|
│ └── src/jvmAndroid/kotlin/.../nip64Chess/
|
|
│ └── ChessEngine.jvmAndroid.kt ✅ kchesslib impl
|
|
│
|
|
├── commons/ # Shared UI (Android/Desktop) - KMP
|
|
│ └── src/commonMain/kotlin/.../commons/chess/
|
|
│ ├── ChessBoard.kt ✅ Static board
|
|
│ ├── InteractiveChessBoard.kt ✅ Click-to-move
|
|
│ ├── ChessGameViewer.kt ✅ PGN playback
|
|
│ ├── MoveNavigator.kt ✅ Move controls
|
|
│ ├── PGNMetadata.kt ✅ Game info
|
|
│ └── LiveChessGame.kt ✅ Dialog + screen
|
|
│
|
|
├── amethyst/ # Android app
|
|
│ └── src/main/java/.../amethyst/
|
|
│ ├── ui/note/types/
|
|
│ │ └── Chess.kt ✅ Event renderers (3 types)
|
|
│ ├── ui/note/
|
|
│ │ └── NoteCompose.kt ✅ Event dispatching
|
|
│ ├── ui/screen/
|
|
│ │ ├── TopNavFilterState.kt ✅ Chess filter (3 kinds)
|
|
│ │ └── loggedIn/chess/
|
|
│ │ ├── ChessViewModel.kt ✅ State & event publishing
|
|
│ │ ├── ChessViewModelFactory.kt ✅ ViewModel factory
|
|
│ │ ├── ChessGameScreen.kt ✅ Game screen wrapper
|
|
│ │ └── dal/ChessFeedFilter.kt ✅ Feed filter
|
|
│ └── ui/navigation/routes/
|
|
│ └── Route.ChessGame ✅ Navigation route
|
|
│
|
|
└── docs/
|
|
└── live-chess-implementation-status.md ✅ This file
|
|
```
|
|
|
|
## 🚀 Next Steps
|
|
|
|
**To complete the chess feature**, implement:
|
|
|
|
1. ~~**ChessViewModel**~~ ✅ - Game state management & event publishing
|
|
2. ~~**Navigation**~~ ✅ - Route to LiveChessGameScreen
|
|
3. ~~**Event Subscriptions**~~ ✅ - Listen for opponent moves
|
|
4. **FAB** - Add "New Game" button to chess feed
|
|
5. **Badge Display** - Show badge count in navigation
|
|
6. **Test** - Play a complete game between two test accounts
|
|
|
|
---
|
|
|
|
**Status**: Core chess functionality fully implemented. ViewModel and relay subscriptions complete. Ready for FAB/badge polish and end-to-end testing.
|