diff --git a/src/core/execution/FakeHumanExecution.ts b/src/core/execution/FakeHumanExecution.ts index d55161654..083f23e6a 100644 --- a/src/core/execution/FakeHumanExecution.ts +++ b/src/core/execution/FakeHumanExecution.ts @@ -437,6 +437,7 @@ export class FakeHumanExecution implements Execution { this.maybeSpawnStructure(UnitType.Port) || this.maybeSpawnWarship() || this.maybeSpawnStructure(UnitType.Factory) || + this.maybeSpawnStructure(UnitType.SAMLauncher) || this.maybeSpawnStructure(UnitType.MissileSilo) ); } diff --git a/src/core/execution/SAMLauncherExecution.ts b/src/core/execution/SAMLauncherExecution.ts index 0c444ef91..c1b3f71c8 100644 --- a/src/core/execution/SAMLauncherExecution.ts +++ b/src/core/execution/SAMLauncherExecution.ts @@ -50,7 +50,8 @@ class SAMTargetingSystem { private isInRange(tile: TileRef) { const samTile = this.sam.tile(); - const rangeSquared = this.mg.config().defaultSamRange() ** 2; + const range = this.mg.config().defaultSamRange(); + const rangeSquared = range * range; return this.mg.euclideanDistSquared(samTile, tile) <= rangeSquared; } diff --git a/src/core/execution/nation/structureSpawnTileValue.ts b/src/core/execution/nation/structureSpawnTileValue.ts index 563f42f80..55e1cfa90 100644 --- a/src/core/execution/nation/structureSpawnTileValue.ts +++ b/src/core/execution/nation/structureSpawnTileValue.ts @@ -13,24 +13,9 @@ export function structureSpawnTileValue( const borderSpacing = mg.config().nukeMagnitudes(UnitType.AtomBomb).outer; const structureSpacing = borderSpacing * 2; switch (type) { - case UnitType.Port: - return (tile) => { - let w = 0; - - // Prefer to be far away from other structures of the same type - const otherTiles: Set = new Set(otherUnits.map((u) => u.tile())); - otherTiles.delete(tile); - const closestOther = closestTwoTiles(mg, otherTiles, [tile]); - if (closestOther !== null) { - const d = mg.manhattanDist(closestOther.x, tile); - w += Math.min(d, structureSpacing); - } - - return w; - }; case UnitType.City: case UnitType.Factory: - case UnitType.MissileSilo: + case UnitType.MissileSilo: { return (tile) => { let w = 0; @@ -56,6 +41,68 @@ export function structureSpawnTileValue( // TODO: Cities and factories should consider train range limits return w; }; + } + case UnitType.Port: { + return (tile) => { + let w = 0; + + // Prefer to be far away from other structures of the same type + const otherTiles: Set = new Set(otherUnits.map((u) => u.tile())); + otherTiles.delete(tile); + const closestOther = closestTwoTiles(mg, otherTiles, [tile]); + if (closestOther !== null) { + const d = mg.manhattanDist(closestOther.x, tile); + w += Math.min(d, structureSpacing); + } + + return w; + }; + } + case UnitType.SAMLauncher: { + const protectTiles: Set = new Set(); + for (const unit of player.units()) { + switch(unit.type()) { + case UnitType.City: + case UnitType.Factory: + case UnitType.MissileSilo: + case UnitType.Port: + protectTiles.add(unit.tile()); + } + } + const range = mg.config().defaultSamRange(); + const rangeSquared = range * range; + return (tile) => { + let w = 0; + + // Prefer higher elevations + w += mg.magnitude(tile); + + // Prefer to be away from the border + const closestBorder = closestTwoTiles(mg, borderTiles, [tile]); + if (closestBorder !== null) { + const d = mg.manhattanDist(closestBorder.x, tile); + w += Math.min(d, borderSpacing); + } + + // Prefer to be far away from other structures of the same type + const otherTiles: Set = new Set(otherUnits.map((u) => u.tile())); + otherTiles.delete(tile); + const closestOther = closestTwoTiles(mg, otherTiles, [tile]); + if (closestOther !== null) { + const d = mg.manhattanDist(closestOther.x, tile); + w += Math.min(d, structureSpacing); + } + + // Prefer to be in range of other structures + for (const maybeProtected of protectTiles) { + const distanceSquared = mg.euclideanDistSquared(tile, maybeProtected); + if (distanceSquared > rangeSquared) continue; + w += structureSpacing; + } + + return w; + }; + } default: throw new Error(`Value function not implemented for ${type}`); }