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.
111 lines
2.8 KiB
111 lines
2.8 KiB
2 years ago
|
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];
|
||
|
}
|
||
|
}
|