diff --git a/TODO.txt b/TODO.txt index c6fe27c79..0d1c99d1a 100644 --- a/TODO.txt +++ b/TODO.txt @@ -58,8 +58,8 @@ * REFACTOR: remove player config DONE 8/29/2024 * give boats limit for how far they can go DONE 8/29/2024 * boats can go around the world DONE 8/29/2024 -* max boats (3)? -* PERF: more efficient spawns +* max boats (3) DONE 8/30/2024 +* PERF: more efficient spawns DONE 8/30/2024 * PERF: load terrain map async * PERF: enable CDN * enable load balancing metrics diff --git a/src/core/Util.ts b/src/core/Util.ts index d85fd8dcc..8d2084948 100644 --- a/src/core/Util.ts +++ b/src/core/Util.ts @@ -5,7 +5,7 @@ export function manhattanDist(c1: Cell, c2: Cell): number { return Math.abs(c1.x - c2.x) + Math.abs(c1.y - c2.y); } -export function manhattenDistWrapped(c1: Cell, c2: Cell, width: number): number { +export function manhattanDistWrapped(c1: Cell, c2: Cell, width: number): number { // Calculate x distance let dx = Math.abs(c1.x - c2.x); // Check if wrapping around the x-axis is shorter diff --git a/src/core/execution/BoatAttackExecution.ts b/src/core/execution/BoatAttackExecution.ts index c75cdaf92..08bea4103 100644 --- a/src/core/execution/BoatAttackExecution.ts +++ b/src/core/execution/BoatAttackExecution.ts @@ -1,6 +1,6 @@ import {PriorityQueue} from "@datastructures-js/priority-queue"; import {Boat, Cell, Execution, MutableBoat, MutableGame, MutablePlayer, Player, PlayerID, TerraNullius, Tile, TileEvent} from "../Game"; -import {manhattanDist, manhattenDistWrapped} from "../Util"; +import {manhattanDist, manhattanDistWrapped} from "../Util"; import {AttackExecution} from "./AttackExecution"; import {Config} from "../configuration/Config"; @@ -74,7 +74,7 @@ export class BoatAttackExecution implements Execution { this.active = false return } - if (manhattenDistWrapped(this.src.cell(), this.dst.cell(), mg.width()) > mg.config().boatMaxDistance()) { + if (manhattanDistWrapped(this.src.cell(), this.dst.cell(), mg.width()) > mg.config().boatMaxDistance()) { console.log(`boat attack distance too large, dist ${manhattanDist(this.src.cell(), this.dst.cell())} max: ${mg.config().boatMaxDistance()}`) this.active = false return diff --git a/src/core/execution/BotSpawner.ts b/src/core/execution/BotSpawner.ts index 08b83c3c5..42e5dac8c 100644 --- a/src/core/execution/BotSpawner.ts +++ b/src/core/execution/BotSpawner.ts @@ -1,65 +1,56 @@ -import {Cell, Game} from "../Game"; +import {Cell, Game, Tile, TileEvent} from "../Game"; import {PseudoRandom} from "../PseudoRandom"; import {SpawnIntent} from "../Schemas"; -import {bfs, dist as dist} from "../Util"; -import {getSpawnCells} from "./Util"; +import {bfs, dist as dist, manhattanDist} from "../Util"; export class BotSpawner { - private cellToIndex: Map; - private freeTiles: Cell[]; - private numFreeTiles; private random = new PseudoRandom(123); + private bots: SpawnIntent[] = []; constructor(private gs: Game) { } spawnBots(numBots: number): SpawnIntent[] { - const bots: SpawnIntent[] = []; - this.cellToIndex = new Map(); - this.freeTiles = new Array(); - this.numFreeTiles = 0; - - this.gs.forEachTile(tile => { - if (tile.isWater()) { - return; + let tries = 0 + while (this.bots.length < numBots - 1) { + if (tries > 10000) { + console.log('too many retries while spawning bots, giving up') + return this.bots } - if (tile.hasOwner()) { - return; + const spawn = this.spawnBot("Bot" + this.bots.length) + if (spawn != null) { + this.bots.push(spawn); + } else { + tries++ } - - this.freeTiles.push(tile.cell()); - this.cellToIndex.set(tile.cell().toString(), this.numFreeTiles); - this.numFreeTiles++; - }); - for (let i = 0; i < numBots; i++) { - bots.push(this.spawnBot("Bot" + i)); } - return bots; + return this.bots; } - spawnBot(botName: string): SpawnIntent { - const rand = this.random.nextInt(0, this.numFreeTiles); - const spawn = this.freeTiles[rand]; - bfs(this.gs.tile(spawn), dist(50)).forEach(t => this.removeCell(t.cell())) - const spawnIntent: SpawnIntent = { + spawnBot(botName: string): SpawnIntent | null { + const tile = this.randTile() + if (!tile.isLand()) { + return null + } + for (const spawn of this.bots) { + if (manhattanDist(new Cell(spawn.x, spawn.y), tile.cell()) < 50) { + return null + } + } + return { type: 'spawn', name: botName, isBot: true, - x: spawn.x, - y: spawn.y + x: tile.cell().x, + y: tile.cell().y }; - return spawnIntent; } - private removeCell(cell: Cell) { - if (!this.cellToIndex.has(cell.toString())) { - return - } - const index = this.cellToIndex.get(cell.toString()); - this.cellToIndex.delete(cell.toString()) - - this.freeTiles[index] = this.freeTiles[this.numFreeTiles - 1]; - this.cellToIndex.set(this.freeTiles[index].toString(), index); - this.numFreeTiles--; + private randTile(): Tile { + return this.gs.tile(new Cell( + this.random.nextInt(0, this.gs.width()), + this.random.nextInt(0, this.gs.height()) + )) } } +