diff --git a/src/core/Util.ts b/src/core/Util.ts index 69317accf..c5cbe044e 100644 --- a/src/core/Util.ts +++ b/src/core/Util.ts @@ -129,6 +129,20 @@ export function boundingBoxTiles( return tiles; } +export function getMode(counts: Map): T | null { + let mode: T | null = null; + let maxCount = 0; + + for (const [item, count] of counts) { + if (count > maxCount) { + maxCount = count; + mode = item; + } + } + + return mode; +} + export function calculateBoundingBoxCenter( gm: GameMap, borderTiles: ReadonlySet, diff --git a/src/core/execution/PlayerExecution.ts b/src/core/execution/PlayerExecution.ts index fed23323d..66e10c854 100644 --- a/src/core/execution/PlayerExecution.ts +++ b/src/core/execution/PlayerExecution.ts @@ -2,7 +2,7 @@ import { Config } from "../configuration/Config"; import { Execution, Game, Player, UnitType } from "../game/Game"; import { GameImpl } from "../game/GameImpl"; import { GameMap, TileRef } from "../game/GameMap"; -import { calculateBoundingBox, inscribed, simpleHash } from "../Util"; +import { calculateBoundingBox, getMode, inscribed, simpleHash } from "../Util"; export class PlayerExecution implements Execution { private readonly ticksPerClusterCalc = 20; @@ -221,28 +221,20 @@ export class PlayerExecution implements Execution { } private getCapturingPlayer(cluster: Set): Player | null { - // Collect unique neighbor IDs (excluding self) as candidates - const candidatesIDs = new Set(); - const selfID = this.player.smallID(); - + const neighbors = new Map(); for (const t of cluster) { for (const neighbor of this.mg.neighbors(t)) { - if (this.mg.ownerID(neighbor) !== selfID) { - candidatesIDs.add(this.mg.ownerID(neighbor)); + const owner = this.mg.owner(neighbor); + if ( + owner.isPlayer() && + owner !== this.player && + !owner.isFriendly(this.player) + ) { + neighbors.set(owner, (neighbors.get(owner) ?? 0) + 1); } } } - // Filter out friendly and non-player candidates - const neighbors = new Set(); - for (const id of candidatesIDs) { - const neighbor = this.mg.playerBySmallID(id); - if (!neighbor.isPlayer() || neighbor.isFriendly(this.player)) { - continue; - } - neighbors.add(neighbor); - } - // If there are no enemies, return null if (neighbors.size === 0) { return null; @@ -251,7 +243,7 @@ export class PlayerExecution implements Execution { // Get the largest attack from the neighbors let largestNeighborAttack: Player | null = null; let largestTroopCount = 0; - for (const neighbor of neighbors) { + for (const [neighbor] of neighbors) { for (const attack of neighbor.outgoingAttacks()) { if (attack.target() === this.player) { if (attack.troops() > largestTroopCount) { @@ -262,9 +254,12 @@ export class PlayerExecution implements Execution { } } - // Return the largest neighbor attack - // If there is no largest neighbor attack, this will return null - return largestNeighborAttack; + if (largestNeighborAttack !== null) { + return largestNeighborAttack; + } + + // There are no ongoing attacks, so find the enemy with the largest border. + return getMode(neighbors); } private calculateClusters(): Set[] {