make sendBoat() more efficient: find random tiles instead of doing a breadth first search

This commit is contained in:
Evan
2025-04-04 16:04:57 -07:00
parent 190a67b72a
commit 2cb8c239cf
+43 -56
View File
@@ -15,7 +15,7 @@ import {
Tick,
UnitType,
} from "../game/Game";
import { andFN, manhattanDistFN, TileRef } from "../game/GameMap";
import { manhattanDistFN, TileRef } from "../game/GameMap";
import { PseudoRandom } from "../PseudoRandom";
import { GameID } from "../Schemas";
import { calculateBoundingBox, simpleHash } from "../Util";
@@ -151,12 +151,12 @@ export class FakeHumanExecution implements Execution {
if (enemyborder.length == 0) {
if (this.random.chance(5)) {
this.sendBoat();
this.sendBoatRandomly();
}
return;
}
if (this.random.chance(10)) {
this.sendBoat();
this.sendBoatRandomly();
return;
}
@@ -503,58 +503,30 @@ export class FakeHumanExecution implements Execution {
);
}
sendBoat(tries: number = 0, oceanShore: TileRef[] = null) {
if (tries > 10) {
return;
}
if (oceanShore == null) {
oceanShore = Array.from(this.player.borderTiles()).filter((t) =>
this.mg.isOceanShore(t),
);
}
sendBoatRandomly() {
const oceanShore = Array.from(this.player.borderTiles()).filter((t) =>
this.mg.isOceanShore(t),
);
if (oceanShore.length == 0) {
return;
}
const src = this.random.randElement(oceanShore);
const otherShore = Array.from(
this.mg.bfs(
src,
andFN(
(gm, t) => gm.isOcean(t) || gm.isOceanShore(t),
manhattanDistFN(src, 200),
),
const dst = this.randOceanShoreTile(src, 250);
if (dst == null) {
return;
}
this.mg.addExecution(
new TransportShipExecution(
this.player.id(),
this.mg.owner(dst).id(),
dst,
this.player.troops() / 5,
),
).filter((t) => this.mg.isOceanShore(t) && this.mg.owner(t) != this.player);
if (otherShore.length == 0) {
return;
}
for (let i = 0; i < 20; i++) {
const dst = this.random.randElement(otherShore);
if (this.isSmallIsland(dst)) {
continue;
}
if (
this.mg.owner(dst).isPlayer() &&
this.player.isFriendly(this.mg.owner(dst) as Player)
) {
continue;
}
this.mg.addExecution(
new TransportShipExecution(
this.player.id(),
this.mg.hasOwner(dst) ? this.mg.owner(dst).id() : null,
dst,
this.player.troops() / 5,
),
);
return;
}
this.sendBoat(tries + 1, oceanShore);
);
return;
}
randomLand(): TileRef | null {
@@ -593,13 +565,28 @@ export class FakeHumanExecution implements Execution {
);
}
isSmallIsland(tile: TileRef): boolean {
return (
this.mg.bfs(
tile,
andFN((gm, t) => gm.isLand(t), manhattanDistFN(tile, 10)),
).size < 50
);
private randOceanShoreTile(tile: TileRef, dist: number): TileRef | null {
const x = this.mg.x(tile);
const y = this.mg.y(tile);
for (let i = 0; i < 500; i++) {
const randX = this.random.nextInt(x - dist, x + dist);
const randY = this.random.nextInt(y - dist, y + dist);
if (!this.mg.isValidCoord(randX, randY)) {
continue;
}
const randTile = this.mg.ref(randX, randY);
if (!this.mg.isOceanShore(randTile)) {
continue;
}
const owner = this.mg.owner(randTile);
if (!owner.isPlayer()) {
return randTile;
}
if (!owner.isFriendly(this.player)) {
return randTile;
}
}
return null;
}
owner(): Player {