Files
OpenFrontIO/src/core/execution/BotSpawner.ts
T
2025-03-31 13:09:27 -07:00

68 lines
1.9 KiB
TypeScript

import { consolex } from "../Consolex";
import { Game, PlayerInfo, PlayerType } from "../game/Game";
import { TileRef } from "../game/GameMap";
import { PseudoRandom } from "../PseudoRandom";
import { GameID } from "../Schemas";
import { simpleHash } from "../Util";
import { SpawnExecution } from "./SpawnExecution";
import { BOT_NAME_PREFIXES, BOT_NAME_SUFFIXES } from "./utils/BotNames";
export class BotSpawner {
private random: PseudoRandom;
private bots: SpawnExecution[] = [];
constructor(
private gs: Game,
gameID: GameID,
) {
this.random = new PseudoRandom(simpleHash(gameID));
}
spawnBots(numBots: number): SpawnExecution[] {
let tries = 0;
while (this.bots.length < numBots) {
if (tries > 10000) {
consolex.log("too many retries while spawning bots, giving up");
return this.bots;
}
const botName = this.randomBotName();
const spawn = this.spawnBot(botName);
if (spawn != null) {
this.bots.push(spawn);
} else {
tries++;
}
}
return this.bots;
}
spawnBot(botName: string): SpawnExecution | null {
const tile = this.randTile();
if (!this.gs.isLand(tile)) {
return null;
}
for (const spawn of this.bots) {
if (this.gs.manhattanDist(spawn.tile, tile) < 30) {
return null;
}
}
return new SpawnExecution(
new PlayerInfo("", botName, PlayerType.Bot, null, this.random.nextID()),
tile,
);
}
private randomBotName(): string {
const prefixIndex = this.random.nextInt(0, BOT_NAME_PREFIXES.length);
const suffixIndex = this.random.nextInt(0, BOT_NAME_SUFFIXES.length);
return `${BOT_NAME_PREFIXES[prefixIndex]} ${BOT_NAME_SUFFIXES[suffixIndex]}`;
}
private randTile(): TileRef {
return this.gs.ref(
this.random.nextInt(0, this.gs.width()),
this.random.nextInt(0, this.gs.height()),
);
}
}