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.
110 lines
2.8 KiB
110 lines
2.8 KiB
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<Player, PlayerData> = 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]; |
|
} |
|
}
|
|
|