diff --git a/src/core/execution/FakeHumanExecution.ts b/src/core/execution/FakeHumanExecution.ts index 10eac66ea..bae5b3690 100644 --- a/src/core/execution/FakeHumanExecution.ts +++ b/src/core/execution/FakeHumanExecution.ts @@ -461,6 +461,7 @@ export class FakeHumanExecution implements Execution { this.maybeSpawnStructure(UnitType.Port) || this.maybeSpawnWarship() || this.maybeSpawnStructure(UnitType.Factory) || + this.maybeSpawnStructure(UnitType.DefensePost) || this.maybeSpawnStructure(UnitType.SAMLauncher) || this.maybeSpawnStructure(UnitType.MissileSilo) ); diff --git a/src/core/execution/nation/structureSpawnTileValue.ts b/src/core/execution/nation/structureSpawnTileValue.ts index 55e1cfa90..e1a716e7c 100644 --- a/src/core/execution/nation/structureSpawnTileValue.ts +++ b/src/core/execution/nation/structureSpawnTileValue.ts @@ -1,4 +1,4 @@ -import { Game, Player, UnitType } from "../../game/Game"; +import { Game, Player, Relation, UnitType } from "../../game/Game"; import { TileRef } from "../../game/GameMap"; import { closestTwoTiles } from "../Util"; @@ -46,7 +46,47 @@ export function structureSpawnTileValue( return (tile) => { let w = 0; - // Prefer to be far away from other structures of the same type + // Prefer to be 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.DefensePost: { + return (tile) => { + let w = 0; + + // Prefer higher elevations + w += mg.magnitude(tile); + + const closestBorder = closestTwoTiles(mg, borderTiles, [tile]); + if (closestBorder !== null) { + // Prefer to be borderSpacing tiles from the border + const d = mg.manhattanDist(closestBorder.x, tile); + w += Math.max(0, borderSpacing - Math.abs(borderSpacing - d)); + + // Prefer adjacent players who are hostile + const neighbors: Set = new Set(); + for (const tile of mg.neighbors(closestBorder.x)) { + if (!mg.isLand(tile)) continue; + const id = mg.ownerID(tile); + if (id === player.smallID()) continue; + const neighbor = mg.playerBySmallID(id); + if (!neighbor.isPlayer()) continue; + neighbors.add(neighbor); + } + for (const neighbor of neighbors) { + w += borderSpacing * (Relation.Friendly - player.relation(neighbor)); + } + } + + // Prefer to be 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]); @@ -61,7 +101,7 @@ export function structureSpawnTileValue( case UnitType.SAMLauncher: { const protectTiles: Set = new Set(); for (const unit of player.units()) { - switch(unit.type()) { + switch (unit.type()) { case UnitType.City: case UnitType.Factory: case UnitType.MissileSilo: @@ -84,7 +124,7 @@ export function structureSpawnTileValue( w += Math.min(d, borderSpacing); } - // Prefer to be far away from other structures of the same type + // Prefer to be 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]);