import { Board } from "./board.js"; import { Player } from "./player.js"; import { DuplicatePlayerError } from "./errors/duplicate_player_error.js"; import { NotParticipatingError } from "./errors/not_participating_error.js"; import { OutOfTurnError } from "./errors/out_of_turn_error.js"; import { GameCompleteError } from "./errors/game_complete_error.js"; class PlayerData { pos: number = 0; snakeCount: number = 0; ladderCount: number = 0; } export class Game { public players: Map = new Map(); private winningPlayer: Player | undefined; private nextPlayer: Player | undefined; constructor(public gameId: number, public board: Board) {} get playerCount() { return this.players.size; } get winner() { return this.winningPlayer; } get isComplete() { return this.winningPlayer !== undefined; } addPlayer(player: Player) { if (this.hasPlayer(player)) { new DuplicatePlayerError(this.gameId, player.playerId); } this.players.set(player, new PlayerData()); } hasPlayer(player: Player) { return this.players.has(player); } rollDice(player: Player, roll: number) { const playerData = this.players.get(player); if (!playerData) { throw new NotParticipatingError( this.gameId, player.playerId, "roll dice" ); } if (this.nextPlayer && this.nextPlayer !== player) { throw new OutOfTurnError(this.gameId, player.playerId); } if (this.winningPlayer) { throw new GameCompleteError(this.gameId, player.playerId); } const rollPos = playerData.pos + roll; if (this.board.tileHasLadder(rollPos)) { playerData.ladderCount++; } else if (this.board.tileHasSnake(rollPos)) { playerData.snakeCount++; } playerData.pos = this.board.calculateLandingPosition(rollPos); if (playerData.pos >= this.board.size) { this.winningPlayer = player; } this.nextTurn(player); } ladderCountForPlayer(player: Player) { const playerData = this.players.get(player); if (!playerData) { throw new NotParticipatingError( this.gameId, player.playerId, "get ladder count" ); } return playerData.ladderCount; } snakeCountForPlayer(player: Player) { const playerData = this.players.get(player); if (!playerData) { throw new NotParticipatingError( this.gameId, player.playerId, "get snake count" ); } return playerData.snakeCount; } private nextTurn(currentPlayer: Player) { const players = Array.from(this.players.keys()); const playerIndex = players.indexOf(currentPlayer); const nextIndex = playerIndex === players.length - 1 ? 0 : playerIndex + 1; this.nextPlayer = players[nextIndex]; } }