From 8941bf6d58e6ac1f62db35d4866773acd143ce78 Mon Sep 17 00:00:00 2001 From: Scott Anderson <662325+scottanderson@users.noreply.github.com> Date: Mon, 14 Apr 2025 20:37:55 -0400 Subject: [PATCH] PlayerExecution --- src/core/execution/PlayerExecution.ts | 73 ++++++++++++++++++--------- 1 file changed, 49 insertions(+), 24 deletions(-) diff --git a/src/core/execution/PlayerExecution.ts b/src/core/execution/PlayerExecution.ts index cae9b9b04..885ce768e 100644 --- a/src/core/execution/PlayerExecution.ts +++ b/src/core/execution/PlayerExecution.ts @@ -16,10 +16,10 @@ import { calculateBoundingBox, getMode, inscribed, simpleHash } from "../Util"; export class PlayerExecution implements Execution { private readonly ticksPerClusterCalc = 20; - private player: Player; - private config: Config; + private player: Player | null = null; + private config: Config | null = null; private lastCalc = 0; - private mg: Game; + private mg: Game | null = null; private active = true; constructor(private playerID: PlayerID) {} @@ -42,6 +42,9 @@ export class PlayerExecution implements Execution { } tick(ticks: number) { + if (this.mg === null || this.config === null || this.player === null) { + throw new Error("Not initialized"); + } this.player.decayRelations(); const hasPort = this.player.units(UnitType.Port).length > 0; this.player.units().forEach((u) => { @@ -49,13 +52,14 @@ export class PlayerExecution implements Execution { u.delete(); return; } - if (hasPort && u.type() == UnitType.Warship) { + if (hasPort && u.type() === UnitType.Warship) { u.modifyHealth(1); } + if (this.mg === null) return; const tileOwner = this.mg.owner(u.tile()); if (u.info().territoryBound) { if (tileOwner.isPlayer()) { - if (tileOwner != this.player) { + if (tileOwner !== this.player) { this.mg.player(tileOwner.id()).captureUnit(u); } } else { @@ -67,10 +71,10 @@ export class PlayerExecution implements Execution { if (!this.player.isAlive()) { this.player.units().forEach((u) => { if ( - u.type() != UnitType.AtomBomb && - u.type() != UnitType.HydrogenBomb && - u.type() != UnitType.MIRVWarhead && - u.type() != UnitType.MIRV + u.type() !== UnitType.AtomBomb && + u.type() !== UnitType.HydrogenBomb && + u.type() !== UnitType.MIRVWarhead && + u.type() !== UnitType.MIRV ) { u.delete(); } @@ -111,6 +115,9 @@ export class PlayerExecution implements Execution { } private removeClusters() { + if (this.mg === null || this.player === null) { + throw new Error("Not initialized"); + } const clusters = this.calculateClusters(); clusters.sort((a, b) => b.size - a.size); @@ -130,6 +137,9 @@ export class PlayerExecution implements Execution { } private surroundedBySamePlayer(cluster: Set): false | Player { + if (this.mg === null || this.player === null) { + throw new Error("Not initialized"); + } const enemies = new Set(); for (const tile of cluster) { const isOceanShore = this.mg.isOceanShore(tile); @@ -139,19 +149,19 @@ export class PlayerExecution implements Execution { if ( isOceanShore || this.mg.isOnEdgeOfMap(tile) || - this.mg.neighbors(tile).some((n) => !this.mg.hasOwner(n)) + this.mg.neighbors(tile).some((n) => !this.mg?.hasOwner(n)) ) { return false; } this.mg .neighbors(tile) - .filter((n) => this.mg.ownerID(n) != this.player.smallID()) - .forEach((p) => enemies.add(this.mg.ownerID(p))); - if (enemies.size != 1) { + .filter((n) => this.mg?.ownerID(n) !== this.player?.smallID()) + .forEach((p) => this.mg && enemies.add(this.mg.ownerID(p))); + if (enemies.size !== 1) { return false; } } - if (enemies.size != 1) { + if (enemies.size !== 1) { return false; } const enemy = this.mg.playerBySmallID(Array.from(enemies)[0]) as Player; @@ -164,6 +174,9 @@ export class PlayerExecution implements Execution { } private isSurrounded(cluster: Set): boolean { + if (this.mg === null || this.player === null) { + throw new Error("Not initialized"); + } const enemyTiles = new Set(); for (const tr of cluster) { if (this.mg.isShore(tr) || this.mg.isOnEdgeOfMap(tr)) { @@ -171,10 +184,10 @@ export class PlayerExecution implements Execution { } this.mg .neighbors(tr) - .filter((n) => this.mg.ownerID(n) != this.player.smallID()) + .filter((n) => this.mg?.ownerID(n) !== this.player?.smallID()) .forEach((n) => enemyTiles.add(n)); } - if (enemyTiles.size == 0) { + if (enemyTiles.size === 0) { return false; } const enemyBox = calculateBoundingBox(this.mg, enemyTiles); @@ -183,9 +196,12 @@ export class PlayerExecution implements Execution { } private removeCluster(cluster: Set) { + if (this.mg === null || this.player === null) { + throw new Error("Not initialized"); + } if ( Array.from(cluster).some( - (t) => this.mg.ownerID(t) != this.player.smallID(), + (t) => this.mg?.ownerID(t) !== this.player?.smallID(), ) ) { // Other removeCluster operations could change tile owners, @@ -194,16 +210,16 @@ export class PlayerExecution implements Execution { } const capturing = this.getCapturingPlayer(cluster); - if (capturing == null) { + if (capturing === null) { return; } const firstTile = cluster.values().next().value; const filter = (_, t: TileRef): boolean => - this.mg.ownerID(t) == this.player.smallID(); + this.mg?.ownerID(t) === this.player?.smallID(); const tiles = this.mg.bfs(firstTile, filter); - if (this.player.numTilesOwned() == tiles.size) { + if (this.player.numTilesOwned() === tiles.size) { const gold = this.player.gold(); this.mg.displayMessage( `Conquered ${this.player.displayName()} received ${renderNumber( @@ -222,10 +238,13 @@ export class PlayerExecution implements Execution { } private getCapturingPlayer(cluster: Set): Player | null { + if (this.mg === null || this.player === null) { + throw new Error("Not initialized"); + } const neighborsIDs = new Set(); for (const t of cluster) { for (const neighbor of this.mg.neighbors(t)) { - if (this.mg.ownerID(neighbor) != this.player.smallID()) { + if (this.mg.ownerID(neighbor) !== this.player.smallID()) { neighborsIDs.add(this.mg.ownerID(neighbor)); } } @@ -239,7 +258,7 @@ export class PlayerExecution implements Execution { continue; } for (const attack of neighbor.outgoingAttacks()) { - if (attack.target() == this.player) { + if (attack.target() === this.player) { if (attack.troops() > largestTroopCount) { largestTroopCount = attack.troops(); largestNeighborAttack = neighbor; @@ -247,7 +266,7 @@ export class PlayerExecution implements Execution { } } } - if (largestNeighborAttack != null) { + if (largestNeighborAttack !== null) { return largestNeighborAttack; } @@ -260,10 +279,13 @@ export class PlayerExecution implements Execution { if (!capturing.isPlayer()) { return null; } - return capturing as Player; + return capturing; } private calculateClusters(): Set[] { + if (this.mg === null || this.player === null) { + throw new Error("Not initialized"); + } const seen = new Set(); const border = this.player.borderTiles(); const clusters: Set[] = []; @@ -294,6 +316,9 @@ export class PlayerExecution implements Execution { } owner(): Player { + if (this.player === null) { + throw new Error("Not initialized"); + } return this.player; }