extend GameManager game state with jury, bingo, leaderboard

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-12 19:50:43 +01:00
parent b79ddb9679
commit aedd3c032a
2 changed files with 74 additions and 2 deletions

View File

@@ -232,21 +232,59 @@ export class GameManager {
return result
}
getGameStateForPlayer(playerId: string, allPlayerIds: string[]): GameState {
getGameStateForPlayer(
playerId: string,
allPlayerIds: string[],
displayNames?: Record<string, string>,
): GameState {
return {
lineup,
myPrediction: this.getPrediction(playerId),
predictionsLocked: this.locked,
predictionSubmitted: this.buildPredictionSubmitted(allPlayerIds),
currentJuryRound: this.getCurrentJuryRound(),
juryResults: this.juryResults,
myJuryVote: this.getPlayerJuryVote(playerId),
myBingoCard: this.getBingoCard(playerId),
bingoAnnouncements: this.bingoAnnouncements,
leaderboard: this.buildLeaderboard(allPlayerIds, displayNames ?? {}),
}
}
getGameStateForDisplay(allPlayerIds: string[]): GameState {
getGameStateForDisplay(
allPlayerIds: string[],
displayNames?: Record<string, string>,
): GameState {
return {
lineup,
myPrediction: null,
predictionsLocked: this.locked,
predictionSubmitted: this.buildPredictionSubmitted(allPlayerIds),
currentJuryRound: this.getCurrentJuryRound(),
juryResults: this.juryResults,
myJuryVote: null,
myBingoCard: null,
bingoAnnouncements: this.bingoAnnouncements,
leaderboard: this.buildLeaderboard(allPlayerIds, displayNames ?? {}),
}
}
private buildLeaderboard(
playerIds: string[],
displayNames: Record<string, string>,
): { playerId: string; displayName: string; juryPoints: number; bingoPoints: number; totalPoints: number }[] {
return playerIds
.map((id) => {
const juryPoints = this.getJuryScore(id)
const bingoPoints = this.getBingoScore(id)
return {
playerId: id,
displayName: displayNames[id] ?? "Unknown",
juryPoints,
bingoPoints,
totalPoints: juryPoints + bingoPoints,
}
})
.sort((a, b) => b.totalPoints - a.totalPoints)
}
}

View File

@@ -305,6 +305,40 @@ describe("GameManager", () => {
})
})
describe("getGameStateForPlayer (with jury + bingo)", () => {
it("includes jury round state", () => {
gm.openJuryRound("SE", "Sweden", "🇸🇪")
gm.submitJuryVote("p1", 8)
const state = gm.getGameStateForPlayer("p1", ["p1"])
expect(state.currentJuryRound).not.toBeNull()
expect(state.currentJuryRound!.countryCode).toBe("SE")
expect(state.myJuryVote).toBe(8)
})
it("includes bingo card", () => {
gm.generateBingoCards(["p1"])
const state = gm.getGameStateForPlayer("p1", ["p1"])
expect(state.myBingoCard).not.toBeNull()
expect(state.myBingoCard!.squares).toHaveLength(16)
})
it("includes leaderboard with jury + bingo scores", () => {
gm.generateBingoCards(["p1"])
gm.openJuryRound("SE", "Sweden", "🇸🇪")
gm.submitJuryVote("p1", 8)
gm.closeJuryRound()
const card = gm.getBingoCard("p1")!
gm.tapBingoSquare("p1", card.squares[0]!.tropeId)
const state = gm.getGameStateForPlayer("p1", ["p1"], { p1: "Player 1" })
expect(state.leaderboard).toHaveLength(1)
expect(state.leaderboard[0]!.juryPoints).toBe(5) // solo voter = exact match
expect(state.leaderboard[0]!.bingoPoints).toBe(2) // 1 tapped * 2
expect(state.leaderboard[0]!.totalPoints).toBe(7)
})
})
describe("getGameStateForDisplay", () => {
it("returns null myPrediction", () => {
gm.submitPrediction("p1", "SE", "DE", "IT", "GB")