Files
OpenFrontIO/src/core/execution/BotSpawner.ts
T
2025-02-01 12:05:11 -08:00

69 lines
2.1 KiB
TypeScript

import { consolex } from "../Consolex";
import { Cell, Game, PlayerType } from "../game/Game";
import { TileRef } from "../game/GameMap";
import { PseudoRandom } from "../PseudoRandom";
import { GameID, SpawnIntent } from "../Schemas";
import { simpleHash } from "../Util";
import { BOT_NAME_PREFIXES, BOT_NAME_SUFFIXES } from "./utils/BotNames";
export class BotSpawner {
private random: PseudoRandom
private bots: SpawnIntent[] = [];
constructor(private gs: Game, gameID: GameID) {
this.random = new PseudoRandom(simpleHash(gameID))
}
spawnBots(numBots: number): SpawnIntent[] {
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): SpawnIntent | null {
const tile = this.randTile()
if (!this.gs.isLand(tile)) {
return null
}
for (const spawn of this.bots) {
if (this.gs.manhattanDist(this.gs.ref(spawn.x, spawn.y), tile) < 30) {
return null
}
}
return {
type: 'spawn',
playerID: this.random.nextID(),
name: botName,
playerType: PlayerType.Bot,
x: this.gs.x(tile),
y: this.gs.y(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())
)
}
}