From c1dc6217a502924f7774099da751a86e62af561c Mon Sep 17 00:00:00 2001 From: evanpelle Date: Sun, 1 Sep 2024 19:18:38 -0700 Subject: [PATCH] improve AttackExecution perf --- TODO.txt | 2 +- src/core/configuration/DefaultConfig.ts | 4 +- src/core/configuration/DevConfig.ts | 2 +- src/core/execution/AttackExecution.ts | 131 +++++++++++------------- src/core/execution/BotSpawner.ts | 2 +- 5 files changed, 66 insertions(+), 75 deletions(-) diff --git a/TODO.txt b/TODO.txt index 1a7a60340..6903dfea6 100644 --- a/TODO.txt +++ b/TODO.txt @@ -73,10 +73,10 @@ * end game when no players left (or after 1 hour or so?) DONE 9/1/2024 * add structured logging DONE 9/1/2024 * improve background image DONE 9/1/2024 +* make attack execution stream tiles to pq DONE 9/1/2024 * center map on game start * make mediterranion ocean, fix panama canal * remove tiny islands -* make attack execution stream tiles to pq * Create exit to menu button * use better favicon * show next game in menu diff --git a/src/core/configuration/DefaultConfig.ts b/src/core/configuration/DefaultConfig.ts index 6ea574ea4..7e33a03da 100644 --- a/src/core/configuration/DefaultConfig.ts +++ b/src/core/configuration/DefaultConfig.ts @@ -48,9 +48,9 @@ export class DefaultConfig implements Config { attackTilesPerTick(attacker: Player, defender: Player | TerraNullius, numAdjacentTilesWithEnemy: number): number { if (defender.isPlayer()) { - return within(attacker.numTilesOwned() / defender.numTilesOwned() * 2, .01, .5) * numAdjacentTilesWithEnemy * 2 + return within(attacker.numTilesOwned() / defender.numTilesOwned() * 2, .01, .5) * numAdjacentTilesWithEnemy * 2 / 25 } else { - return numAdjacentTilesWithEnemy * 2 + return numAdjacentTilesWithEnemy * 2 / 25 } } diff --git a/src/core/configuration/DevConfig.ts b/src/core/configuration/DevConfig.ts index 11f4f4755..8ec543dc0 100644 --- a/src/core/configuration/DevConfig.ts +++ b/src/core/configuration/DevConfig.ts @@ -16,7 +16,7 @@ export const devConfig = new class extends DefaultConfig { } numBots(): number { - return 250 + return 350 } startTroops(playerInfo: PlayerInfo): number { diff --git a/src/core/execution/AttackExecution.ts b/src/core/execution/AttackExecution.ts index a70e5ffb3..fab415c5d 100644 --- a/src/core/execution/AttackExecution.ts +++ b/src/core/execution/AttackExecution.ts @@ -14,7 +14,6 @@ export class AttackExecution implements Execution { private mg: MutableGame private numTilesWithEnemy = 0 - private borderTiles: Set = new Set() constructor( private troops: number, @@ -60,14 +59,21 @@ export class AttackExecution implements Execution { // Existing attack on same target, add troops if (otherAttack._owner == this._owner && otherAttack.targetID == this.targetID) { otherAttack.troops += this.troops - otherAttack.calculateToConquer() + otherAttack.refreshToConquer() this.active = false return } } } - this.calculateToConquer() + this.refreshToConquer() + } + + private refreshToConquer() { + this.toConquer.clear() + for (const tile of this._owner.borderTiles()) { + this.addNeighbors(tile) + } } tick(ticks: number) { @@ -79,40 +85,31 @@ export class AttackExecution implements Execution { } let numTilesPerTick = this.mg.config().attackTilesPerTick(this._owner, this.target, this.numTilesWithEnemy + this.random.nextInt(0, 5)) - if (this.targetCell != null) { - numTilesPerTick /= 2 - } - let badTiles = 0 + + let tries = 0 while (numTilesPerTick > 0) { if (this.troops < 1) { this.active = false return } - if (this.toConquer.size() < this.numTilesWithEnemy / 1.2) { - this.calculateToConquer() - } - if (badTiles > 1000) { - console.log('bad tiles') - this.borderTiles.clear() - this.calculateToConquer() - badTiles = 0 - continue - } if (this.toConquer.size() == 0) { - badTiles = 0 - this.active = false - this._owner.addTroops(this.troops) - return + this.refreshToConquer() + if (this.toConquer.size() == 0) { + this.active = false + this._owner.addTroops(this.troops) + return + } } - const toConquerContainer = this.toConquer.dequeue() - const tileToConquer: Tile = toConquerContainer.tile + const tileToConquer = this.toConquer.dequeue().tile + const onBorder = tileToConquer.neighbors().filter(t => t.owner() == this._owner).length > 0 if (tileToConquer.owner() != this.target || !onBorder) { - badTiles++ continue } + this.addNeighbors(tileToConquer) + const {attackerTroopLoss, defenderTroopLoss, tilesPerTickUsed} = this.mg.config().attackLogic(this._owner, this.target, tileToConquer) numTilesPerTick -= tilesPerTickUsed this.troops -= attackerTroopLoss @@ -120,18 +117,46 @@ export class AttackExecution implements Execution { this.target.removeTroops(defenderTroopLoss) } this._owner.conquer(tileToConquer) - if (this.target.isPlayer() && this.target.numTilesOwned() < 100) { - for (let i = 0; i < 10; i++) { - for (const tile of this.target.tiles()) { - if (tile.borders(this._owner)) { - this._owner.conquer(tile) - } else { - for (const neighbor of tile.neighbors()) { - const no = neighbor.owner() - if (no.isPlayer() && no != this.target) { - this.mg.player(no.id()).conquer(tile) - break - } + this.checkDefenderDead() + } + } + + private addNeighbors(tile: Tile) { + for (const neighbor of tile.neighbors()) { + if (neighbor.isWater() || neighbor.owner() != this.target) { + continue + } + this.numTilesWithEnemy += 1 + let numOwnedByMe = neighbor.neighbors() + .filter(t => t.isLand()) + .filter(t => t.owner() == this._owner) + .length + let dist = 0 + if (this.targetCell != null) { + dist = manhattanDist(tile.cell(), this.targetCell) + } + if (numOwnedByMe > 2) { + numOwnedByMe = 10 + } + this.toConquer.enqueue(new TileContainer( + neighbor, + this.random.nextInt(0, 2) - numOwnedByMe + Math.floor(tile.magnitude() / 10), + )) + } + } + + private checkDefenderDead() { + if (this.target.isPlayer() && this.target.numTilesOwned() < 100) { + for (let i = 0; i < 10; i++) { + for (const tile of this.target.tiles()) { + if (tile.borders(this._owner)) { + this._owner.conquer(tile) + } else { + for (const neighbor of tile.neighbors()) { + const no = neighbor.owner() + if (no.isPlayer() && no != this.target) { + this.mg.player(no.id()).conquer(tile) + break } } } @@ -140,40 +165,6 @@ export class AttackExecution implements Execution { } } - private calculateToConquer() { - this.numTilesWithEnemy = 0 - this.toConquer.clear() - - const newBorder: Set = new Set() - // TODO: figure out existing border - let existingBorder: ReadonlySet = new Set() - if (existingBorder.size == 0) { - existingBorder = this._owner.borderTiles() - } - for (const tile of existingBorder) { - for (const neighbor of tile.neighbors()) { - if (neighbor.isWater() || neighbor.owner() != this.target) { - continue - } - newBorder.add(neighbor) - this.numTilesWithEnemy += 1 - let numOwnedByMe = neighbor.neighbors() - .filter(t => t.isLand()) - .filter(t => t.owner() == this._owner) - .length - let dist = 0 - if (this.targetCell != null) { - dist = manhattanDist(tile.cell(), this.targetCell) - } - // if (numOwnedByMe > 3) { - // numOwnedByMe = 1000 - // } - this.toConquer.enqueue(new TileContainer(neighbor, this.random.nextInt(0, 4) - numOwnedByMe + tile.magnitude() / 5)) - } - } - this.borderTiles = newBorder - } - owner(): MutablePlayer { return this._owner } diff --git a/src/core/execution/BotSpawner.ts b/src/core/execution/BotSpawner.ts index c2e70f823..c0d5b18a7 100644 --- a/src/core/execution/BotSpawner.ts +++ b/src/core/execution/BotSpawner.ts @@ -33,7 +33,7 @@ export class BotSpawner { return null } for (const spawn of this.bots) { - if (manhattanDist(new Cell(spawn.x, spawn.y), tile.cell()) < 70) { + if (manhattanDist(new Cell(spawn.x, spawn.y), tile.cell()) < 30) { return null } }