feat(games): unify ApplyMove signatures + remove unused player conversion

Updated TicTacToeRules and BattleshipRules to implement ApplyMove(state, playerIdx, payload) (bool, bool, int) as required by GameRules.

Added win/draw resolution logic directly inside each game’s ApplyMove return.

Removed obsolete convertToGamePlayers helper.

Updated GenericMatch to call AssignPlayerSymbols with []*structs.Player directly.

Ensured all rule implementations now fully satisfy the GameRules interface.
This commit is contained in:
2025-12-01 17:02:57 +05:30
parent 3c81a8bf29
commit 3eadb49a72
5 changed files with 109 additions and 67 deletions

View File

@@ -2,6 +2,7 @@ package games
import (
"fmt"
"encoding/json"
"localrepo/plugins/structs"
)
@@ -64,7 +65,7 @@ func (b *BattleshipRules) MaxPlayers() int { return 2 }
// ------------------------------
// Assign player boards
// ------------------------------
func (b *BattleshipRules) AssignPlayerSymbols(players []*Player) {
func (b *BattleshipRules) AssignPlayerSymbols(players []*structs.Player) {
// Battleship has no symbols like X/O,
// but we use this hook to initialize per-player boards.
@@ -110,30 +111,34 @@ func (b *BattleshipRules) ValidateMove(state *structs.MatchState, playerIdx int,
// ------------------------------
// ApplyMove
// ------------------------------
func (b *BattleshipRules) ApplyMove(state *structs.MatchState, playerIdx int, payload MovePayload) {
func (b *BattleshipRules) ApplyMove(
state *structs.MatchState,
playerIdx int,
payload MovePayload,
) (bool, bool, int) {
attacker := state.Players[playerIdx]
defenderIdx := 1 - playerIdx
defender := state.Players[defenderIdx]
attacker := state.Players[playerIdx]
defenderIdx := 1 - playerIdx
defender := state.Players[defenderIdx]
r := int(payload.Data["row"].(float64))
c := int(payload.Data["col"].(float64))
r := int(payload.Data["row"].(float64))
c := int(payload.Data["col"].(float64))
shotBoard := decodeBoard(attacker.Metadata["shot_board"])
shipBoard := decodeBoard(defender.Metadata["ship_board"])
shotBoard := decodeBoard(attacker.Metadata["shot_board"])
shipBoard := decodeBoard(defender.Metadata["ship_board"])
if shipBoard[r][c] == "S" {
shotBoard[r][c] = "H"
shipBoard[r][c] = "X"
} else {
shotBoard[r][c] = "M"
}
if shipBoard[r][c] == "S" {
// hit
shotBoard[r][c] = "H"
shipBoard[r][c] = "X" // ship cell destroyed
} else {
// miss
shotBoard[r][c] = "M"
}
attacker.Metadata["shot_board"] = encodeBoard(shotBoard)
defender.Metadata["ship_board"] = encodeBoard(shipBoard)
// Save back
attacker.Metadata["shot_board"] = encodeBoard(shotBoard)
defender.Metadata["ship_board"] = encodeBoard(shipBoard)
over, winner := b.CheckGameOver(state)
return true, over, winner
}
// ------------------------------

View File

@@ -12,7 +12,7 @@ type GameRules interface {
MaxPlayers() int
// Assign symbols/colors/pieces at start.
AssignPlayerSymbols(players []*Player)
AssignPlayerSymbols(players []*structs.Player)
// Apply a move.
// Returns: (changed, gameOver, winnerIndex)

View File

@@ -1,8 +1,6 @@
package games
import (
"errors"
"fmt"
"localrepo/plugins/structs"
)
@@ -18,7 +16,7 @@ func (t *TicTacToeRules) MaxPlayers() int {
}
// Assign player symbols: X and O
func (t *TicTacToeRules) AssignPlayerSymbols(players []*Player) {
func (t *TicTacToeRules) AssignPlayerSymbols(players []*structs.Player) {
if len(players) < 2 {
return
}
@@ -57,16 +55,24 @@ func (t *TicTacToeRules) ValidateMove(state *structs.MatchState, playerIdx int,
}
// ApplyMove writes X or O to the board.
func (t *TicTacToeRules) ApplyMove(state *structs.MatchState, playerIdx int, payload MovePayload) {
func (t *TicTacToeRules) ApplyMove(
state *structs.MatchState,
playerIdx int,
payload MovePayload,
) (bool, bool, int) {
symbol := state.Players[playerIdx].Metadata["symbol"]
symbol := state.Players[playerIdx].Metadata["symbol"]
r := int(payload.Data["row"].(float64))
c := int(payload.Data["col"].(float64))
r := int(payload.Data["row"].(float64))
c := int(payload.Data["col"].(float64))
state.Board.Set(r, c, symbol)
state.Board.Set(r, c, symbol)
over, winner := t.CheckGameOver(state)
return true, over, winner
}
// CheckGameOver determines win/draw state.
func (t *TicTacToeRules) CheckGameOver(state *structs.MatchState) (bool, int) {