feat(core): migrate to multi-board architecture and implement per-game InitBoards

### Major changes
- Replace single-board MatchState (`Board`) with multi-board map (`Boards`)
- Update GenericMatch to initialize empty Boards and populate them via GameRules.InitBoards
- Remove legacy `newEmptyBoard` helper from match.go
- Update .gitignore to include *BKP* patterns

### GameRules interface
- Add InitBoards(players, cfg) to allow games to construct their own board sets
- Add detailed documentation explaining method responsibilities and usage
- Improve MovePayload comment clarity

### TicTacToe updates
- Implement InitBoards to produce a single `"tictactoe"` board
- Replace all old references to `state.Board` with `state.Boards["tictactoe"]`
- Make CheckGameOver, ValidateMove, and ApplyMove multi-board compatible

### Battleship updates
- Implement InitBoards generating per-player ships + shots boards:
  - p0_ships, p0_shots
  - p1_ships, p1_shots

### Match flow updates
- Boards are now created only when all players have joined
- Initial state broadcast now includes `boards` instead of `board`

This completes the backend migration for multi-board games and prepares the architecture
for Battleship and other complex board-based games.
This commit is contained in:
2025-12-03 17:52:27 +05:30
parent 1c31c489c7
commit bcdc5faea5
5 changed files with 69 additions and 24 deletions

View File

@@ -63,18 +63,6 @@ func indexOfPlayerByID(players []*structs.Player, userID string) int {
return -1
}
func newEmptyBoard(rows, cols int) *structs.Board {
b := &structs.Board{
Rows: rows,
Cols: cols,
Grid: make([][]string, rows),
}
for r := 0; r < rows; r++ {
b.Grid[r] = make([]string, cols)
}
return b
}
// -------------------------
// Match interface methods
// -------------------------
@@ -136,7 +124,7 @@ func (m *GenericMatch) MatchInit(
// ---- 6. create initial state (board from config) ----
state := &structs.MatchState{
Players: []*structs.Player{},
Board: newEmptyBoard(cfg.Board.Rows, cfg.Board.Cols),
Boards: map[string]*structs.Board{}, // empty, will be filled later
Turn: 0,
Winner: -1,
GameOver: false,
@@ -217,6 +205,9 @@ func (m *GenericMatch) MatchJoin(
// Assign player symbols/colors/etc. Pass structs.Player directly.
m.Rules.AssignPlayerSymbols(s.Players)
// Initialize boards using game rules
s.Boards = m.Rules.InitBoards(s.Players, m.Config)
// Broadcast initial state
if data, err := json.Marshal(s); err == nil {
if err := dispatcher.BroadcastMessage(OpState, data, nil, nil, true); err != nil {