From 49aafe6379f42a9b10efd4cfeab7425c68a0af0e Mon Sep 17 00:00:00 2001 From: evanpelle Date: Sun, 22 Sep 2024 13:00:48 -0700 Subject: [PATCH] give fake humans alliance behavior --- TODO.txt | 2 +- src/core/execution/AttackExecution.ts | 2 +- src/core/execution/FakeHumanExecution.ts | 52 +++++++++++++++++++++--- src/core/game/GameImpl.ts | 18 +++++++- src/core/game/PlayerImpl.ts | 3 ++ 5 files changed, 68 insertions(+), 9 deletions(-) diff --git a/TODO.txt b/TODO.txt index 5f18b9929..844f9ba44 100644 --- a/TODO.txt +++ b/TODO.txt @@ -133,7 +133,7 @@ * first place has crown DONE 9/20/2024 * can't attack ally DONE 9/20/2024 * add updates to eventbox: boats (max count, too far) DONE 9/20/2024 -* BUG: boats landing doesn't launch attack +* BUG: boats landing doesn't launch attack DONE 9/20/2024 * fake humans handle alliances * make alliances expire * make year clock diff --git a/src/core/execution/AttackExecution.ts b/src/core/execution/AttackExecution.ts index b725069f4..3a4d6fcbf 100644 --- a/src/core/execution/AttackExecution.ts +++ b/src/core/execution/AttackExecution.ts @@ -109,7 +109,7 @@ export class AttackExecution implements Execution { if (ticks < this.mg.config().numSpawnPhaseTurns()) { return } - if (this.breakAlliance) { + if (this.breakAlliance && this._owner.alliedWith(this.target as Player)) { this.breakAlliance = false this._owner.breakAllianceWith(this.target as Player) } diff --git a/src/core/execution/FakeHumanExecution.ts b/src/core/execution/FakeHumanExecution.ts index c2a69c6a4..1d5c72d13 100644 --- a/src/core/execution/FakeHumanExecution.ts +++ b/src/core/execution/FakeHumanExecution.ts @@ -1,5 +1,5 @@ import {EventBus} from "../EventBus"; -import {Cell, Execution, MutableGame, MutablePlayer, Player, PlayerID, PlayerInfo, PlayerType, TerrainType, TerraNullius, Tile} from "../game/Game" +import {Cell, Execution, MutableGame, MutablePlayer, Player, PlayerInfo, PlayerType, TerrainType, TerraNullius, Tile} from "../game/Game" import {PseudoRandom} from "../PseudoRandom" import {and, bfs, dist, simpleHash} from "../Util"; import {AttackExecution} from "./AttackExecution"; @@ -13,10 +13,12 @@ export class FakeHumanExecution implements Execution { private attackRate: number private mg: MutableGame private neighborsTerraNullius = true - private player: Player = null + private player: MutablePlayer = null private enemy: Player | null = null + private rejected: Set = new Set + constructor(private playerInfo: PlayerInfo) { this.random = new PseudoRandom(simpleHash(playerInfo.id)) @@ -52,6 +54,8 @@ export class FakeHumanExecution implements Execution { return } + this.handleAllianceRequests() + if (ticks % 100 == 0) { this.enemy = null } @@ -94,10 +98,48 @@ export class FakeHumanExecution implements Execution { const enemies = enemyborder.map(t => t.owner()).filter(o => o.isPlayer()).map(o => o as Player).sort((a, b) => a.troops() - b.troops()) - if (this.random.nextInt(0, 1) == 1) { - this.sendAttack(enemies[0]) + if (this.random.chance(10)) { + const toAlly = this.random.randElement(enemies) + if (!this.player.alliedWith(toAlly)) { + this.player.createAllianceRequest(toAlly) + } + } + + if (this.random.chance(2)) { + if (!this.player.alliedWith(enemies[0]) || this.random.chance(30)) { + this.sendAttack(enemies[0]) + } } else { - this.sendAttack(enemies[this.random.nextInt(0, enemies.length)]) + if (!this.player.alliedWith(enemies[0]) || this.random.chance(60)) { + this.sendAttack(this.random.randElement(enemies)) + } + } + } + + handleAllianceRequests() { + for (const req of this.player.incomingAllianceRequests()) { + if (this.rejected.has(req.requestor())) { + continue + } + if (req.requestor().numTilesOwned() > this.player.numTilesOwned() * 2) { + req.accept() + continue + } + if (req.recipient().numTilesOwned() > this.player.numTilesOwned()) { + if (this.random.chance(2)) { + req.accept() + } else { + req.reject() + this.rejected.add(req.recipient()) + } + continue + } + if (this.random.chance(5)) { + req.accept() + } else { + req.reject() + this.rejected.add(req.recipient()) + } } } diff --git a/src/core/game/GameImpl.ts b/src/core/game/GameImpl.ts index 414e002a6..2c831f4e6 100644 --- a/src/core/game/GameImpl.ts +++ b/src/core/game/GameImpl.ts @@ -49,7 +49,21 @@ export class GameImpl implements MutableGame { } } - createAllianceRequest(requestor: Player, recipient: Player): MutableAllianceRequest { + createAllianceRequest(requestor: MutablePlayer, recipient: Player): MutableAllianceRequest { + if (requestor.alliedWith(recipient)) { + console.log('cannot request alliance, already allied') + return + } + if (recipient.incomingAllianceRequests().find(ar => ar.requestor() == requestor) != null) { + console.log(`duplicate alliance request from ${requestor.name()}`) + return + } + const correspondingReq = requestor.incomingAllianceRequests().find(ar => ar.requestor() == recipient) + if (correspondingReq != null) { + console.log(`got corresponding alliance requests, accepting`) + correspondingReq.accept() + return + } const ar = new AllianceRequestImpl(requestor, recipient, this._ticks, this) this.allianceRequests.push(ar) this.eventBus.emit(new AllianceRequestEvent(ar)) @@ -333,7 +347,7 @@ export class GameImpl implements MutableGame { const breakerSet = new Set(breaker.alliances()) const alliances = other.alliances().filter(a => breakerSet.has(a)) if (alliances.length != 1) { - throw new Error('must have exactly one alliance') + throw new Error(`must have exactly one alliance, have ${alliances.length}`) } this.alliances_ = this.alliances_.filter(a => a != alliances[0]) this.eventBus.emit(new BrokeAllianceEvent(breaker, other)) diff --git a/src/core/game/PlayerImpl.ts b/src/core/game/PlayerImpl.ts index 842b51b58..46bd28ee1 100644 --- a/src/core/game/PlayerImpl.ts +++ b/src/core/game/PlayerImpl.ts @@ -151,6 +151,9 @@ export class PlayerImpl implements MutablePlayer { } createAllianceRequest(recipient: Player): MutableAllianceRequest { + if (this.alliedWith(recipient)) { + throw new Error(`cannot create alliance request, already allies`) + } return this.gs.createAllianceRequest(this, recipient) }