diff --git a/src/core/execution/FakeHumanExecution.ts b/src/core/execution/FakeHumanExecution.ts index d0861aedf..518d9417e 100644 --- a/src/core/execution/FakeHumanExecution.ts +++ b/src/core/execution/FakeHumanExecution.ts @@ -16,6 +16,7 @@ import { NukeExecution } from "./NukeExecution"; import { MissileSiloExecution } from "./MissileSiloExecution"; import { EmojiExecution } from "./EmojiExecution"; import { AllianceRequestReplyExecution } from "./alliance/AllianceRequestReplyExecution"; +import { closestTwoTiles } from "./Util"; export class FakeHumanExecution implements Execution { @@ -186,10 +187,17 @@ export class FakeHumanExecution implements Execution { } } + if (this.player.isAlliedWith(this.enemy)) { + this.enemy = null + return + } + if (this.enemy) { this.maybeSendNuke(this.enemy) - if (this.player.sharesBorderWith(this.enemy) && !this.player.isAlliedWith(this.enemy)) { + if (this.player.sharesBorderWith(this.enemy)) { this.sendAttack(this.enemy) + } else { + this.maybeSendBoatAttack(this.enemy) } return } @@ -221,6 +229,24 @@ export class FakeHumanExecution implements Execution { } } + private maybeSendBoatAttack(other: Player) { + const closest = closestTwoTiles( + Array.from(this.player.borderTiles()).filter(t => t.isOceanShore()), + Array.from(other.borderTiles()).filter(t => t.isOceanShore()) + ) + if (closest == null) { + return + } + if (manhattanDist(closest.x.cell(), closest.y.cell()) < this.mg.config().boatMaxDistance()) { + this.mg.addExecution(new TransportShipExecution( + this.player.id(), + other.id(), + closest.y.cell(), + this.player.troops() / 5 + )) + } + } + private handleUnits() { const ports = this.player.units(UnitType.Port) if (ports.length == 0 && this.player.gold() > this.cost(UnitType.Port)) { diff --git a/src/core/execution/Util.ts b/src/core/execution/Util.ts index c7c7db742..a1a13af86 100644 --- a/src/core/execution/Util.ts +++ b/src/core/execution/Util.ts @@ -1,4 +1,4 @@ -import {Game, Cell} from "../game/Game"; +import { Game, Cell, Tile } from "../game/Game"; export function getSpawnCells(gs: Game, cell: Cell): Cell[] { @@ -23,3 +23,48 @@ export function getSpawnCells(gs: Game, cell: Cell): Cell[] { } return result; } + +export function closestTwoTiles(x: Iterable, y: Iterable): { x: Tile, y: Tile } { + const xSorted = Array.from(x).sort((a, b) => a.cell().x - b.cell().x); + const ySorted = Array.from(y).sort((a, b) => a.cell().x - b.cell().x); + + if (xSorted.length == 0 || ySorted.length == 0) { + return null; + } + + let i = 0; + let j = 0; + let minDistance = Infinity; + let result = { x: xSorted[0], y: ySorted[0] }; + + while (i < xSorted.length && j < ySorted.length) { + const currentX = xSorted[i]; + const currentY = ySorted[j]; + + const distance = + Math.abs(currentX.cell().x - currentY.cell().x) + + Math.abs(currentX.cell().y - currentY.cell().y); + + if (distance < minDistance) { + minDistance = distance; + result = { x: currentX, y: currentY }; + } + + // If we're at the end of X, must move Y forward + if (i === xSorted.length - 1) { + j++; + } + // If we're at the end of Y, must move X forward + else if (j === ySorted.length - 1) { + i++; + } + // Otherwise, move whichever pointer has smaller x value + else if (currentX.cell().x < currentY.cell().x) { + i++; + } else { + j++; + } + } + + return result; +} \ No newline at end of file