You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
116 lines
3.3 KiB
116 lines
3.3 KiB
import { EventProcessor, IEventProcessor } from "../utils/event_processor.js"; |
|
|
|
import { GameStartedEvent } from "../game/events/game_started_event.js"; |
|
import { PlayerJoinedEvent } from "../game/events/player_joined_event.js"; |
|
import { PlayerRolledEvent } from "../game/events/player_rolled_event.js"; |
|
|
|
import { Game } from "../game/game.js"; |
|
import { Board } from "../game/board.js"; |
|
import { Player } from "../game/player.js"; |
|
|
|
import { MaxPlayersExceededError } from "./errors/max_players_exceeded_error.js"; |
|
import { GameNotStartedError } from "./errors/game_not_started_error.js"; |
|
import { DuplicateGameError } from "./errors/duplicate_game_error.js"; |
|
import { TournamentIncompleteError } from "./errors/tournament_incomplete_error.js"; |
|
|
|
// Provide Tournament class with additional EventProcessor methods |
|
export interface Tournament extends IEventProcessor {} |
|
|
|
interface ITournamentOptions { |
|
maxPlayersPerGame: number; |
|
} |
|
|
|
@EventProcessor.watch |
|
export class Tournament implements ITournamentOptions { |
|
gamesMap = new Map<number, Game>(); |
|
playersMap = new Map<number, Player>(); |
|
|
|
maxPlayersPerGame = 2; |
|
|
|
constructor(public board: Board, options: Partial<ITournamentOptions> = {}) { |
|
Object.assign(this, options); |
|
} |
|
|
|
get players() { |
|
return Array.from(this.playersMap.values()); |
|
} |
|
|
|
get games() { |
|
return Array.from(this.gamesMap.values()); |
|
} |
|
|
|
@EventProcessor.handle(GameStartedEvent) |
|
onGameStarted(gameStartedEvent: GameStartedEvent) { |
|
this.newGame(gameStartedEvent.gameId); |
|
} |
|
|
|
@EventProcessor.handle(PlayerJoinedEvent) |
|
onPlayerJoined(playerJoinedEvent: PlayerJoinedEvent) { |
|
const game = this.getGame(playerJoinedEvent.gameId); |
|
if (!game) { |
|
throw new GameNotStartedError( |
|
playerJoinedEvent.gameId, |
|
playerJoinedEvent.playerId |
|
); |
|
} |
|
|
|
const player = this.getOrCreatePlayer(playerJoinedEvent.playerId); |
|
|
|
if (game.playerCount >= this.maxPlayersPerGame) { |
|
throw new MaxPlayersExceededError( |
|
game.gameId, |
|
player.playerId, |
|
this.maxPlayersPerGame |
|
); |
|
} |
|
|
|
player.join(game); |
|
game.addPlayer(player); |
|
} |
|
|
|
@EventProcessor.handle(PlayerRolledEvent) |
|
onPlayerRolled(playerRolledEvent: PlayerRolledEvent) { |
|
const game = this.getGame(playerRolledEvent.gameId); |
|
if (!game) { |
|
throw new GameNotStartedError( |
|
playerRolledEvent.gameId, |
|
playerRolledEvent.playerId |
|
); |
|
} |
|
|
|
const player = this.getOrCreatePlayer(playerRolledEvent.playerId); |
|
player.rollDice(game, playerRolledEvent.roll); |
|
} |
|
|
|
getGame(gameId: number) { |
|
return this.gamesMap.get(gameId); |
|
} |
|
|
|
newGame(gameId: number) { |
|
if (this.gamesMap.has(gameId)) { |
|
throw new DuplicateGameError(gameId); |
|
} |
|
const game = new Game(gameId, this.board); |
|
this.gamesMap.set(gameId, game); |
|
return game; |
|
} |
|
|
|
getOrCreatePlayer(playerId: number) { |
|
let player = this.playersMap.get(playerId); |
|
if (!player) { |
|
player = new Player(playerId); |
|
this.playersMap.set(playerId, player); |
|
} |
|
return player; |
|
} |
|
|
|
requireCompletion() { |
|
const incompleteGameIds = Array.from(this.gamesMap.values()) |
|
.filter((game: Game) => !game.isComplete) |
|
.map((game: Game) => game.gameId); |
|
|
|
if (incompleteGameIds.length) { |
|
throw new TournamentIncompleteError(incompleteGameIds); |
|
} |
|
} |
|
}
|
|
|