From 0d7c58d5b833255928882ea9bda9e7fd4629a7c2 Mon Sep 17 00:00:00 2001 From: Scott Anderson <662325+scottanderson@users.noreply.github.com> Date: Sat, 12 Jul 2025 12:24:44 -0400 Subject: [PATCH] Unit count (#1402) ## Description: Use an iterative approach to counting units to reduce array allocations. ## Please complete the following: - [x] I have added screenshots for all UI updates - [x] I process any text displayed to the user through translateText() and I've added it to the en.json file - [x] I have added relevant tests to the test directory - [ ] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced - [x] I understand that submitting code with bugs that could have been caught through manual testing blocks releases and new features for all contributors --- src/client/index.html | 2 +- src/core/execution/PortExecution.ts | 2 +- src/core/execution/TradeShipExecution.ts | 2 +- src/core/execution/TransportShipExecution.ts | 2 +- src/core/execution/WarshipExecution.ts | 4 ++-- src/core/game/Game.ts | 2 ++ src/core/game/GameImpl.ts | 10 ++++++++++ src/core/game/PlayerImpl.ts | 13 ++++++++++++- src/core/game/TransportShipUtils.ts | 2 +- 9 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/client/index.html b/src/client/index.html index 14e989d7b..4a0b8cfb7 100644 --- a/src/client/index.html +++ b/src/client/index.html @@ -187,7 +187,7 @@ diff --git a/src/core/execution/PortExecution.ts b/src/core/execution/PortExecution.ts index a7d070562..2df238fc2 100644 --- a/src/core/execution/PortExecution.ts +++ b/src/core/execution/PortExecution.ts @@ -75,7 +75,7 @@ export class PortExecution implements Execution { } shouldSpawnTradeShip(): boolean { - const numTradeShips = this.mg.units(UnitType.TradeShip).length; + const numTradeShips = this.mg.unitCount(UnitType.TradeShip); const spawnRate = this.mg.config().tradeShipSpawnRate(numTradeShips); for (let i = 0; i < this.port!.level(); i++) { if (this.random.chance(spawnRate)) { diff --git a/src/core/execution/TradeShipExecution.ts b/src/core/execution/TradeShipExecution.ts index b0e4f12fb..381d35fd9 100644 --- a/src/core/execution/TradeShipExecution.ts +++ b/src/core/execution/TradeShipExecution.ts @@ -130,7 +130,7 @@ export class TradeShipExecution implements Execution { .config() .tradeShipGold( this.tilesTraveled, - this.tradeShip!.owner().units(UnitType.Port).length, + this.tradeShip!.owner().unitCount(UnitType.Port), ); if (this.wasCaptured) { diff --git a/src/core/execution/TransportShipExecution.ts b/src/core/execution/TransportShipExecution.ts index fde575805..291e5551f 100644 --- a/src/core/execution/TransportShipExecution.ts +++ b/src/core/execution/TransportShipExecution.ts @@ -67,7 +67,7 @@ export class TransportShipExecution implements Execution { this.pathFinder = PathFinder.Mini(mg, 10_000, true, 10); if ( - this.attacker.units(UnitType.TransportShip).length >= + this.attacker.unitCount(UnitType.TransportShip) >= mg.config().boatMaxNumber() ) { mg.displayMessage( diff --git a/src/core/execution/WarshipExecution.ts b/src/core/execution/WarshipExecution.ts index 83a095b70..d11e97c57 100644 --- a/src/core/execution/WarshipExecution.ts +++ b/src/core/execution/WarshipExecution.ts @@ -55,7 +55,7 @@ export class WarshipExecution implements Execution { this.warship.delete(); return; } - const hasPort = this.warship.owner().units(UnitType.Port).length > 0; + const hasPort = this.warship.owner().unitCount(UnitType.Port) > 0; if (hasPort) { this.warship.modifyHealth(1); } @@ -75,7 +75,7 @@ export class WarshipExecution implements Execution { } private findTargetUnit(): Unit | undefined { - const hasPort = this.warship.owner().units(UnitType.Port).length > 0; + const hasPort = this.warship.owner().unitCount(UnitType.Port) > 0; const patrolRangeSquared = this.mg.config().warshipPatrolRange() ** 2; const ships = this.mg.nearbyUnits( diff --git a/src/core/game/Game.ts b/src/core/game/Game.ts index 86f1631df..799f6e47e 100644 --- a/src/core/game/Game.ts +++ b/src/core/game/Game.ts @@ -519,6 +519,7 @@ export interface Player { // Units units(...types: UnitType[]): Unit[]; + unitCount(type: UnitType): number; unitsConstructed(type: UnitType): number; unitsOwned(type: UnitType): number; buildableUnits(tile: TileRef): BuildableUnit[]; @@ -638,6 +639,7 @@ export interface Game extends GameMap { // Units units(...types: UnitType[]): Unit[]; + unitCount(type: UnitType): number; unitInfo(type: UnitType): UnitInfo; hasUnitNearby( tile: TileRef, diff --git a/src/core/game/GameImpl.ts b/src/core/game/GameImpl.ts index 2e3719a24..b9a318bdf 100644 --- a/src/core/game/GameImpl.ts +++ b/src/core/game/GameImpl.ts @@ -209,9 +209,19 @@ export class GameImpl implements Game { units(...types: UnitType[]): Unit[] { return Array.from(this._players.values()).flatMap((p) => p.units(...types)); } + + unitCount(type: UnitType): number { + let total = 0; + for (const player of this._players.values()) { + total += player.unitCount(type); + } + return total; + } + unitInfo(type: UnitType): UnitInfo { return this.config().unitInfo(type); } + nations(): Nation[] { return this._nations; } diff --git a/src/core/game/PlayerImpl.ts b/src/core/game/PlayerImpl.ts index 2506afb87..c32a88e80 100644 --- a/src/core/game/PlayerImpl.ts +++ b/src/core/game/PlayerImpl.ts @@ -243,12 +243,23 @@ export class PlayerImpl implements Player { return total; } + // Count of units owned by the player, not including construction + unitCount(type: UnitType): number { + let total = 0; + for (const unit of this._units) { + if (unit.type() === type) { + total += unit.level(); + } + } + return total; + } + // Count of units owned by the player, including construction unitsOwned(type: UnitType): number { let total = 0; for (const unit of this._units) { if (unit.type() === type) { - total++; + total += unit.level(); continue; } if (unit.type() !== UnitType.Construction) continue; diff --git a/src/core/game/TransportShipUtils.ts b/src/core/game/TransportShipUtils.ts index 5d3f6963c..d9ec739ad 100644 --- a/src/core/game/TransportShipUtils.ts +++ b/src/core/game/TransportShipUtils.ts @@ -9,7 +9,7 @@ export function canBuildTransportShip( tile: TileRef, ): TileRef | false { if ( - player.units(UnitType.TransportShip).length >= game.config().boatMaxNumber() + player.unitCount(UnitType.TransportShip) >= game.config().boatMaxNumber() ) { return false; }