From c7356a7348e25abbfdf8c25a3937d35e719b8c68 Mon Sep 17 00:00:00 2001 From: Evan Date: Sat, 5 Apr 2025 21:36:38 -0700 Subject: [PATCH] have Team be an enum instead of an object, this was causing equality problems. --- src/client/ClientGameRunner.ts | 6 +-- src/client/Transport.ts | 4 +- src/client/graphics/layers/SpawnTimer.ts | 6 +-- src/client/graphics/layers/WinModal.ts | 10 ++--- src/core/Schemas.ts | 6 +-- src/core/Util.ts | 4 +- src/core/configuration/PastelTheme.ts | 8 ++-- src/core/configuration/PastelThemeDark.ts | 8 ++-- src/core/execution/WinCheckExecution.ts | 15 ++----- src/core/game/Game.ts | 8 +--- src/core/game/GameImpl.ts | 10 ++--- src/core/game/GameUpdates.ts | 6 +-- src/core/game/GameView.ts | 10 ++--- src/core/game/PlayerImpl.ts | 4 +- src/core/game/TeamAssignment.ts | 10 ++--- tests/TeamAssignment.test.ts | 50 +++++++++++------------ 16 files changed, 72 insertions(+), 93 deletions(-) diff --git a/src/client/ClientGameRunner.ts b/src/client/ClientGameRunner.ts index 1082b8bdb..fad943459 100644 --- a/src/client/ClientGameRunner.ts +++ b/src/client/ClientGameRunner.ts @@ -11,7 +11,7 @@ import { import { createGameRecord } from "../core/Util"; import { ServerConfig } from "../core/configuration/Config"; import { getConfig } from "../core/configuration/ConfigLoader"; -import { TeamName, UnitType } from "../core/game/Game"; +import { Team, UnitType } from "../core/game/Game"; import { ErrorUpdate, GameUpdateType, @@ -189,13 +189,13 @@ export class ClientGameRunner { clientID: this.lobby.clientID, }, ]; - let winner: ClientID | TeamName | null = null; + let winner: ClientID | Team | null = null; if (update.winnerType == "player") { winner = this.gameView .playerBySmallID(update.winner as number) .clientID(); } else { - winner = update.winner as TeamName; + winner = update.winner as Team; } const record = createGameRecord( diff --git a/src/client/Transport.ts b/src/client/Transport.ts index 38498c9fa..1b50fbdad 100644 --- a/src/client/Transport.ts +++ b/src/client/Transport.ts @@ -6,7 +6,7 @@ import { GameType, PlayerID, PlayerType, - TeamName, + Team, Tick, UnitType, } from "../core/game/Game"; @@ -128,7 +128,7 @@ export class SendSetTargetTroopRatioEvent implements GameEvent { export class SendWinnerEvent implements GameEvent { constructor( - public readonly winner: ClientID | TeamName, + public readonly winner: ClientID | Team, public readonly allPlayersStats: AllPlayersStats, public readonly winnerType: "player" | "team", ) {} diff --git a/src/client/graphics/layers/SpawnTimer.ts b/src/client/graphics/layers/SpawnTimer.ts index 95ed07cd7..48d241104 100644 --- a/src/client/graphics/layers/SpawnTimer.ts +++ b/src/client/graphics/layers/SpawnTimer.ts @@ -1,5 +1,5 @@ import { blue, red } from "../../../core/configuration/Colors"; -import { GameMode, TeamName } from "../../../core/game/Game"; +import { GameMode, Team } from "../../../core/game/Game"; import { GameView } from "../../../core/game/GameView"; import { TransformHandler } from "../TransformHandler"; import { Layer } from "./Layer"; @@ -28,12 +28,12 @@ export class SpawnTimer implements Layer { const numBlueTiles = this.game .players() - .filter((p) => p.teamName() == TeamName.Blue) + .filter((p) => p.team() == Team.Blue) .reduce((acc, p) => acc + p.numTilesOwned(), 0); const numRedTiles = this.game .players() - .filter((p) => p.teamName() == TeamName.Red) + .filter((p) => p.team() == Team.Red) .reduce((acc, p) => acc + p.numTilesOwned(), 0); this.ratio = numBlueTiles / (numBlueTiles + numRedTiles); diff --git a/src/client/graphics/layers/WinModal.ts b/src/client/graphics/layers/WinModal.ts index 7b421237b..c2bfd2528 100644 --- a/src/client/graphics/layers/WinModal.ts +++ b/src/client/graphics/layers/WinModal.ts @@ -1,7 +1,7 @@ import { LitElement, css, html } from "lit"; import { customElement, state } from "lit/decorators.js"; import { EventBus } from "../../../core/EventBus"; -import { TeamName } from "../../../core/game/Game"; +import { Team } from "../../../core/game/Game"; import { GameUpdateType } from "../../../core/game/GameUpdates"; import { GameView, PlayerView } from "../../../core/game/GameView"; import { PseudoRandom } from "../../../core/PseudoRandom"; @@ -226,13 +226,9 @@ export class WinModal extends LitElement implements Layer { this.game.updatesSinceLastTick()[GameUpdateType.Win].forEach((wu) => { if (wu.winnerType === "team") { this.eventBus.emit( - new SendWinnerEvent( - wu.winner as TeamName, - wu.allPlayersStats, - "team", - ), + new SendWinnerEvent(wu.winner as Team, wu.allPlayersStats, "team"), ); - if (wu.winner == this.game.myPlayer()?.teamName()) { + if (wu.winner == this.game.myPlayer()?.team()) { this._title = "Your team won!"; this.won = true; } else { diff --git a/src/core/Schemas.ts b/src/core/Schemas.ts index 71c28ac99..0dc8d9ae7 100644 --- a/src/core/Schemas.ts +++ b/src/core/Schemas.ts @@ -6,7 +6,7 @@ import { GameMode, GameType, PlayerType, - TeamName, + Team, UnitType, } from "./game/Game"; @@ -364,7 +364,7 @@ const ClientBaseMessageSchema = z.object({ export const ClientSendWinnerSchema = ClientBaseMessageSchema.extend({ type: z.literal("winner"), - winner: ID.or(z.nativeEnum(TeamName)).nullable(), + winner: ID.or(z.nativeEnum(Team)).nullable(), allPlayersStats: AllPlayersStatsSchema, winnerType: z.enum(["player", "team"]), }); @@ -425,7 +425,7 @@ export const GameRecordSchema = z.object({ num_turns: z.number(), turns: z.array(TurnSchema), winner: z - .union([ID, z.nativeEnum(TeamName)]) + .union([ID, z.nativeEnum(Team)]) .nullable() .optional(), winnerType: z.enum(["player", "team"]).nullable().optional(), diff --git a/src/core/Util.ts b/src/core/Util.ts index b2e3f76e4..eaf83edae 100644 --- a/src/core/Util.ts +++ b/src/core/Util.ts @@ -1,7 +1,7 @@ import DOMPurify from "dompurify"; import { customAlphabet } from "nanoid"; import twemoji from "twemoji"; -import { Cell, Game, Player, TeamName, Unit } from "./game/Game"; +import { Cell, Game, Player, Team, Unit } from "./game/Game"; import { andFN, GameMap, manhattanDistFN, TileRef } from "./game/GameMap"; import { AllPlayersStats, @@ -253,7 +253,7 @@ export function createGameRecord( turns: Turn[], start: number, end: number, - winner: ClientID | TeamName | null, + winner: ClientID | Team | null, winnerType: "player" | "team" | null, allPlayersStats: AllPlayersStats, ): GameRecord { diff --git a/src/core/configuration/PastelTheme.ts b/src/core/configuration/PastelTheme.ts index d8058521e..93fbeacc7 100644 --- a/src/core/configuration/PastelTheme.ts +++ b/src/core/configuration/PastelTheme.ts @@ -1,7 +1,7 @@ import { Colord, colord } from "colord"; import { PseudoRandom } from "../PseudoRandom"; import { simpleHash } from "../Util"; -import { PlayerType, TeamName, TerrainType } from "../game/Game"; +import { PlayerType, Team, TerrainType } from "../game/Game"; import { GameMap, TileRef } from "../game/GameMap"; import { PlayerView } from "../game/GameView"; import { @@ -37,13 +37,13 @@ export const pastelTheme = new (class implements Theme { private _spawnHighlightColor = colord({ r: 255, g: 213, b: 79 }); territoryColor(player: PlayerView): Colord { - if (player.teamName() == TeamName.Bot) { + if (player.team() == Team.Bot) { return botColor; } - if (player.teamName() == TeamName.Red) { + if (player.team() == Team.Red) { return red; } - if (player.teamName() == TeamName.Blue) { + if (player.team() == Team.Blue) { return blue; } if (player.info().playerType == PlayerType.Human) { diff --git a/src/core/configuration/PastelThemeDark.ts b/src/core/configuration/PastelThemeDark.ts index d7a268170..ad318b5e2 100644 --- a/src/core/configuration/PastelThemeDark.ts +++ b/src/core/configuration/PastelThemeDark.ts @@ -1,7 +1,7 @@ import { Colord, colord } from "colord"; import { PseudoRandom } from "../PseudoRandom"; import { simpleHash } from "../Util"; -import { PlayerType, TeamName, TerrainType } from "../game/Game"; +import { PlayerType, Team, TerrainType } from "../game/Game"; import { GameMap, TileRef } from "../game/GameMap"; import { PlayerView } from "../game/GameView"; import { @@ -37,13 +37,13 @@ export const pastelThemeDark = new (class implements Theme { private _spawnHighlightColor = colord({ r: 255, g: 213, b: 79 }); territoryColor(player: PlayerView): Colord { - if (player.teamName() == TeamName.Bot) { + if (player.team() == Team.Bot) { return botColor; } - if (player.teamName() == TeamName.Red) { + if (player.team() == Team.Red) { return red; } - if (player.teamName() == TeamName.Blue) { + if (player.team() == Team.Blue) { return blue; } if (player.info().playerType == PlayerType.Human) { diff --git a/src/core/execution/WinCheckExecution.ts b/src/core/execution/WinCheckExecution.ts index 47d3c7ed3..a18521998 100644 --- a/src/core/execution/WinCheckExecution.ts +++ b/src/core/execution/WinCheckExecution.ts @@ -1,12 +1,5 @@ import { GameEvent } from "../EventBus"; -import { - Execution, - Game, - GameMode, - Player, - Team, - TeamName, -} from "../game/Game"; +import { Execution, Game, GameMode, Player, Team } from "../game/Game"; export class WinEvent implements GameEvent { constructor(public readonly winner: Player) {} @@ -73,9 +66,9 @@ export class WinCheckExecution implements Execution { this.mg.numLandTiles() - this.mg.numTilesWithFallout(); const percentage = (max[1] / numTilesWithoutFallout) * 100; if (percentage > this.mg.config().percentageTilesOwnedToWin()) { - if (max[0].name == TeamName.Bot) return; - this.mg.setWinner(max[0].name, this.mg.stats().stats()); - console.log(`${max[0].name} has won the game`); + if (max[0] == Team.Bot) return; + this.mg.setWinner(max[0], this.mg.stats().stats()); + console.log(`${max[0]} has won the game`); this.active = false; } } diff --git a/src/core/game/Game.ts b/src/core/game/Game.ts index 5dd3087dc..5019e4b15 100644 --- a/src/core/game/Game.ts +++ b/src/core/game/Game.ts @@ -37,7 +37,7 @@ export enum Difficulty { Impossible = "Impossible", } -export enum TeamName { +export enum Team { Red = "Red", Blue = "Blue", Bot = "Bot", @@ -75,10 +75,6 @@ export enum GameMode { Team = "Team", } -export interface Team { - name: TeamName; -} - export interface UnitInfo { cost: (player: Player | PlayerView) => Gold; // Determines if its owner changes when its tile is conquered. @@ -443,7 +439,7 @@ export interface Game extends GameMap { ticks(): Tick; inSpawnPhase(): boolean; executeNextTick(): GameUpdates; - setWinner(winner: Player | TeamName, allPlayersStats: AllPlayersStats): void; + setWinner(winner: Player | Team, allPlayersStats: AllPlayersStats): void; config(): Config; // Units diff --git a/src/core/game/GameImpl.ts b/src/core/game/GameImpl.ts index b3ccc7eb9..4f56d8da5 100644 --- a/src/core/game/GameImpl.ts +++ b/src/core/game/GameImpl.ts @@ -20,7 +20,6 @@ import { PlayerInfo, PlayerType, Team, - TeamName, TerrainType, TerraNullius, Unit, @@ -76,11 +75,8 @@ export class GameImpl implements Game { private _stats: StatsImpl = new StatsImpl(); - private playerTeams: Team[] = [ - { name: TeamName.Red }, - { name: TeamName.Blue }, - ]; - private botTeam: Team = { name: TeamName.Bot }; + private playerTeams: Team[] = [Team.Red, Team.Blue]; + private botTeam: Team = Team.Bot; constructor( private _humans: PlayerInfo[], @@ -555,7 +551,7 @@ export class GameImpl implements Game { }); } - setWinner(winner: Player | TeamName, allPlayersStats: AllPlayersStats): void { + setWinner(winner: Player | Team, allPlayersStats: AllPlayersStats): void { this.addUpdate({ type: GameUpdateType.Win, winner: typeof winner === "string" ? winner : winner.smallID(), diff --git a/src/core/game/GameUpdates.ts b/src/core/game/GameUpdates.ts index 044a2327e..5f78111f9 100644 --- a/src/core/game/GameUpdates.ts +++ b/src/core/game/GameUpdates.ts @@ -6,7 +6,7 @@ import { NameViewData, PlayerID, PlayerType, - TeamName, + Team, Tick, UnitType, } from "./Game"; @@ -92,7 +92,7 @@ export interface PlayerUpdate { name: string; displayName: string; id: PlayerID; - teamName?: TeamName; + team?: Team; smallID: number; playerType: PlayerType; isAlive: boolean; @@ -161,7 +161,7 @@ export interface WinUpdate { type: GameUpdateType.Win; allPlayersStats: AllPlayersStats; // Player id or team name. - winner: number | TeamName; + winner: number | Team; winnerType: "player" | "team"; } diff --git a/src/core/game/GameView.ts b/src/core/game/GameView.ts index e5423010e..c59e735cf 100644 --- a/src/core/game/GameView.ts +++ b/src/core/game/GameView.ts @@ -15,7 +15,7 @@ import { PlayerInfo, PlayerProfile, PlayerType, - TeamName, + Team, TerrainType, TerraNullius, Tick, @@ -177,8 +177,8 @@ export class PlayerView { id(): PlayerID { return this.data.id; } - teamName(): TeamName { - return this.data.teamName; + team(): Team | null { + return this.data.team; } type(): PlayerType { return this.data.playerType; @@ -223,9 +223,7 @@ export class PlayerView { } isOnSameTeam(other: PlayerView): boolean { - return ( - this.data.teamName != null && this.data.teamName == other.data.teamName - ); + return this.data.team != null && this.data.team == other.data.team; } isFriendly(other: PlayerView): boolean { diff --git a/src/core/game/PlayerImpl.ts b/src/core/game/PlayerImpl.ts index e84f70d97..d4757274f 100644 --- a/src/core/game/PlayerImpl.ts +++ b/src/core/game/PlayerImpl.ts @@ -127,7 +127,7 @@ export class PlayerImpl implements Player { name: this.name(), displayName: this.displayName(), id: this.id(), - teamName: this.team()?.name, + team: this.team(), smallID: this.smallID(), playerType: this.type(), isAlive: this.isAlive(), @@ -596,7 +596,7 @@ export class PlayerImpl implements Player { if (this.team() == null || other.team() == null) { return false; } - return this._team.name == other.team().name; + return this._team == other.team(); } isFriendly(other: Player): boolean { diff --git a/src/core/game/TeamAssignment.ts b/src/core/game/TeamAssignment.ts index b744c7a83..d389f4aef 100644 --- a/src/core/game/TeamAssignment.ts +++ b/src/core/game/TeamAssignment.ts @@ -1,4 +1,4 @@ -import { PlayerInfo, Team, TeamName } from "./Game"; +import { PlayerInfo, Team } from "./Game"; export function assignTeams( players: PlayerInfo[], @@ -38,7 +38,7 @@ export function assignTeams( for (const player of clanPlayers) { if (redTeamCount < maxTeamSize) { redTeamCount++; - result.set(player, { name: TeamName.Red }); + result.set(player, Team.Red); } else { result.set(player, "kicked"); } @@ -48,7 +48,7 @@ export function assignTeams( for (const player of clanPlayers) { if (blueTeamCount < maxTeamSize) { blueTeamCount++; - result.set(player, { name: TeamName.Blue }); + result.set(player, Team.Blue); } else { result.set(player, "kicked"); } @@ -60,10 +60,10 @@ export function assignTeams( for (const player of noClanPlayers) { if (redTeamCount <= blueTeamCount) { redTeamCount++; - result.set(player, { name: TeamName.Red }); + result.set(player, Team.Red); } else { blueTeamCount++; - result.set(player, { name: TeamName.Blue }); + result.set(player, Team.Blue); } } diff --git a/tests/TeamAssignment.test.ts b/tests/TeamAssignment.test.ts index a1f9e2231..4fb18f8e8 100644 --- a/tests/TeamAssignment.test.ts +++ b/tests/TeamAssignment.test.ts @@ -1,4 +1,4 @@ -import { PlayerInfo, PlayerType, TeamName } from "../src/core/game/Game"; +import { PlayerInfo, PlayerType, Team } from "../src/core/game/Game"; import { assignTeams } from "../src/core/game/TeamAssignment"; describe("assignTeams", () => { @@ -25,10 +25,10 @@ describe("assignTeams", () => { const result = assignTeams(players); // Check that players are assigned alternately - expect(result.get(players[0])).toEqual({ name: TeamName.Red }); - expect(result.get(players[1])).toEqual({ name: TeamName.Blue }); - expect(result.get(players[2])).toEqual({ name: TeamName.Red }); - expect(result.get(players[3])).toEqual({ name: TeamName.Blue }); + expect(result.get(players[0])).toEqual(Team.Red); + expect(result.get(players[1])).toEqual(Team.Blue); + expect(result.get(players[2])).toEqual(Team.Red); + expect(result.get(players[3])).toEqual(Team.Blue); }); it("should keep clan members together on the same team", () => { @@ -42,10 +42,10 @@ describe("assignTeams", () => { const result = assignTeams(players); // Check that clan members are on the same team - expect(result.get(players[0])).toEqual({ name: TeamName.Red }); - expect(result.get(players[1])).toEqual({ name: TeamName.Red }); - expect(result.get(players[2])).toEqual({ name: TeamName.Blue }); - expect(result.get(players[3])).toEqual({ name: TeamName.Blue }); + expect(result.get(players[0])).toEqual(Team.Red); + expect(result.get(players[1])).toEqual(Team.Red); + expect(result.get(players[2])).toEqual(Team.Blue); + expect(result.get(players[3])).toEqual(Team.Blue); }); it("should handle mixed clan and non-clan players", () => { @@ -59,10 +59,10 @@ describe("assignTeams", () => { const result = assignTeams(players); // Check that clan members are together and non-clan players balance teams - expect(result.get(players[0])).toEqual({ name: TeamName.Red }); - expect(result.get(players[1])).toEqual({ name: TeamName.Red }); - expect(result.get(players[2])).toEqual({ name: TeamName.Blue }); - expect(result.get(players[3])).toEqual({ name: TeamName.Blue }); + expect(result.get(players[0])).toEqual(Team.Red); + expect(result.get(players[1])).toEqual(Team.Red); + expect(result.get(players[2])).toEqual(Team.Blue); + expect(result.get(players[3])).toEqual(Team.Blue); }); it("should kick players when teams are full", () => { @@ -78,14 +78,14 @@ describe("assignTeams", () => { const result = assignTeams(players); // Check that players are kicked when teams are full - expect(result.get(players[0])).toEqual({ name: TeamName.Red }); - expect(result.get(players[1])).toEqual({ name: TeamName.Red }); - expect(result.get(players[2])).toEqual({ name: TeamName.Red }); + expect(result.get(players[0])).toEqual(Team.Red); + expect(result.get(players[1])).toEqual(Team.Red); + expect(result.get(players[2])).toEqual(Team.Red); expect(result.get(players[3])).toEqual("kicked"); - expect(result.get(players[4])).toEqual({ name: TeamName.Blue }); - expect(result.get(players[5])).toEqual({ name: TeamName.Blue }); + expect(result.get(players[4])).toEqual(Team.Blue); + expect(result.get(players[5])).toEqual(Team.Blue); }); it("should handle empty player list", () => { @@ -96,7 +96,7 @@ describe("assignTeams", () => { it("should handle single player", () => { const players = [createPlayer("1")]; const result = assignTeams(players); - expect(result.get(players[0])).toEqual({ name: TeamName.Red }); + expect(result.get(players[0])).toEqual(Team.Red); }); it("should handle multiple clans with different sizes", () => { @@ -112,11 +112,11 @@ describe("assignTeams", () => { const result = assignTeams(players); // Check that larger clans are assigned first - expect(result.get(players[0])).toEqual({ name: TeamName.Red }); - expect(result.get(players[1])).toEqual({ name: TeamName.Red }); - expect(result.get(players[2])).toEqual({ name: TeamName.Red }); - expect(result.get(players[3])).toEqual({ name: TeamName.Blue }); - expect(result.get(players[4])).toEqual({ name: TeamName.Blue }); - expect(result.get(players[5])).toEqual({ name: TeamName.Blue }); + expect(result.get(players[0])).toEqual(Team.Red); + expect(result.get(players[1])).toEqual(Team.Red); + expect(result.get(players[2])).toEqual(Team.Red); + expect(result.get(players[3])).toEqual(Team.Blue); + expect(result.get(players[4])).toEqual(Team.Blue); + expect(result.get(players[5])).toEqual(Team.Blue); }); });