fakehumans send boats, improved map

This commit is contained in:
evanpelle
2024-09-08 20:21:39 -07:00
parent 8331047a9b
commit a7ad8790aa
19 changed files with 437 additions and 55 deletions
@@ -85,7 +85,6 @@ export class BoatAttackExecution implements Execution {
this.aStarPre.compute(5)
this.path = this.aStarPre.reconstructPath()
if (this.path != null) {
console.log(`got path ${this.path.map(t => t.cell().toString())}`)
this.boat = this.attacker.addBoat(this.troops, this.src, this.target)
} else {
console.log('got null path')
+8 -2
View File
@@ -1,4 +1,4 @@
import {Cell, Execution, MutableGame, MutablePlayer, Player, PlayerID, PlayerInfo, TerraNullius} from "../Game"
import {Cell, Execution, MutableGame, MutablePlayer, Player, PlayerID, PlayerInfo, PlayerType, TerraNullius} from "../Game"
import {PseudoRandom} from "../PseudoRandom"
import {simpleHash} from "../Util";
import {AttackExecution} from "./AttackExecution";
@@ -59,7 +59,13 @@ export class BotExecution implements Execution {
}
const toAttack = border[this.random.nextInt(0, border.length)]
this.sendAttack(toAttack.owner())
const owner = toAttack.owner()
if (owner.isPlayer() && (owner.type() == PlayerType.FakeHuman || owner.type() == PlayerType.Human)) {
if (this.random.nextInt(0, 1) == 1) {
return
}
}
this.sendAttack(owner)
}
sendAttack(toAttack: Player | TerraNullius) {
+11 -5
View File
@@ -1,5 +1,5 @@
import {Cell, Execution, MutableGame, Game, MutablePlayer, PlayerInfo, TerraNullius, Tile, PlayerType} from "../Game";
import {AttackIntent, BoatAttackIntentSchema, Intent, Turn} from "../Schemas";
import {AttackIntent, BoatAttackIntentSchema, GameID, Intent, Turn} from "../Schemas";
import {AttackExecution} from "./AttackExecution";
import {SpawnExecution} from "./SpawnExecution";
import {BotSpawner} from "./BotSpawner";
@@ -7,14 +7,20 @@ import {BoatAttackExecution} from "./BoatAttackExecution";
import {PseudoRandom} from "../PseudoRandom";
import {UpdateNameExecution} from "./UpdateNameExecution";
import {FakeHumanExecution} from "./FakeHumanExecution";
import Usernames from '../../../resources/Usernames.txt'
import {simpleHash} from "../Util";
export class Executor {
private random = new PseudoRandom(999)
private usernames = Usernames.split('\n')
constructor(private gs: Game) {
// private random = new PseudoRandom(999)
private random: PseudoRandom = null
constructor(private gs: Game, gameID: GameID) {
this.random = new PseudoRandom(simpleHash(gameID))
}
createExecs(turn: Turn): Execution[] {
@@ -64,9 +70,9 @@ export class Executor {
for (let i = 0; i < numFakes; i++) {
execs.push(
new FakeHumanExecution(new PlayerInfo(
"fake_human" + i,
this.usernames[this.random.nextInt(0, this.usernames.length)],
PlayerType.FakeHuman,
this.random.nextID(),
null,
this.random.nextID()
))
)
+97 -32
View File
@@ -1,7 +1,8 @@
import {Cell, Execution, MutableGame, MutablePlayer, Player, PlayerID, PlayerInfo, TerraNullius, Tile} from "../Game"
import {Cell, Execution, MutableGame, MutablePlayer, Player, PlayerID, PlayerInfo, TerrainType, TerraNullius, Tile} from "../Game"
import {PseudoRandom} from "../PseudoRandom"
import {simpleHash} from "../Util";
import {and, bfs, dist, simpleHash} from "../Util";
import {AttackExecution} from "./AttackExecution";
import {BoatAttackExecution} from "./BoatAttackExecution";
import {SpawnExecution} from "./SpawnExecution";
export class FakeHumanExecution implements Execution {
@@ -11,11 +12,11 @@ export class FakeHumanExecution implements Execution {
private attackRate: number
private mg: MutableGame
private neighborsTerraNullius = true
private player: Player = null
constructor(private playerInfo: PlayerInfo) {
this.random = new PseudoRandom(simpleHash(playerInfo.id))
this.attackRate = this.random.nextInt(10, 50)
}
init(mg: MutableGame, ticks: number) {
@@ -25,59 +26,123 @@ export class FakeHumanExecution implements Execution {
tick(ticks: number) {
if (this.mg.inSpawnPhase()) {
if (ticks % 10 == 0) {
if (ticks % this.random.nextInt(5, 30) == 0) {
this.mg.addExecution(new SpawnExecution(
this.playerInfo,
this.randomLand().cell()
))
}
}
if (this.player == null) {
this.player = this.mg.players().find(p => p.id() == this.playerInfo.id)
if (this.player == null) {
//console.log(`player with id ${this.playerInfo.id} not found in FakeHumanExecution`)
return
}
}
if (ticks % this.attackRate != 0) {
if (this.player.troops() < this.mg.config().maxTroops(this.player) / 4) {
return
}
// if (this.neighborsTerraNullius) {
// for (const b of this.bot.borderTiles()) {
// for (const n of b.neighbors()) {
// if (n.owner() == this.mg.terraNullius() && n.isLand()) {
// this.sendAttack(this.mg.terraNullius())
// return
// }
// }
// }
// this.neighborsTerraNullius = false
// }
if (ticks % this.random.nextInt(10, 30) != 0) {
return
}
// const border = Array.from(this.bot.borderTiles()).flatMap(t => t.neighbors()).filter(t => t.hasOwner() && t.owner() != this.bot)
if (this.neighborsTerraNullius) {
for (const b of this.player.borderTiles()) {
for (const n of b.neighbors()) {
if (n.owner() == this.mg.terraNullius() && n.isLand()) {
this.sendAttack(this.mg.terraNullius())
return
}
}
}
this.neighborsTerraNullius = false
}
// if (border.length == 0) {
// return
// }
const enemyborder = Array.from(this.player.borderTiles()).flatMap(t => t.neighbors()).filter(t => t.hasOwner() && t.owner() != this.player)
if (enemyborder.length == 0 || this.random.chance(5)) {
this.sendBoat()
return
}
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])
} else {
this.sendAttack(enemies[this.random.nextInt(0, enemies.length)])
}
}
sendBoat(tries: number = 0) {
if (tries > 100) {
return
}
const oceanShore = Array.from(this.player.borderTiles()).filter(t => t.isOceanShore())
if (oceanShore.length == 0) {
return
}
const src = this.random.randElement(oceanShore)
const otherShore = Array.from(
bfs(
src,
and((t) => t.isOcean() || t.isOceanShore(), dist(src, 200))
)
).filter(t => t.isOceanShore() && t.owner() != this.player)
if (otherShore.length == 0) {
return
}
for (let i = 0; i < 100; i++) {
const dst = this.random.randElement(otherShore)
if (this.isSmallIsland(dst)) {
continue
}
this.mg.addExecution(new BoatAttackExecution(
this.player.id(),
dst.hasOwner() ? dst.owner().id() : null,
dst.cell(),
this.player.troops() / 5,
))
return
}
this.sendBoat(tries + 1)
// const toAttack = border[this.random.nextInt(0, border.length)]
// this.sendAttack(toAttack.owner())
}
randomLand(): Tile {
while (true) {
const cell = new Cell(this.random.nextInt(0, this.mg.width()), this.random.nextInt(0, this.mg.height()))
const tile = this.mg.tile(cell)
if (tile.isLand()) {
if (tile.isLand() && !tile.hasOwner()) {
if (tile.terrain() == TerrainType.Mountain && this.random.chance(2)) {
continue
}
return tile
}
}
}
// sendAttack(toAttack: Player | TerraNullius) {
// this.mg.addExecution(new AttackExecution(
// this.bot.troops() / 20,
// this.bot.id(),
// toAttack.isPlayer() ? toAttack.id() : null,
// null,
// null
// ))
// }
sendAttack(toAttack: Player | TerraNullius) {
this.mg.addExecution(new AttackExecution(
this.player.troops() / 5,
this.player.id(),
toAttack.isPlayer() ? toAttack.id() : null,
null,
null
))
}
isSmallIsland(tile: Tile): boolean {
return bfs(tile, and((t) => t.isLand(), dist(tile, 50))).size < 50
}
owner(): MutablePlayer {
return null
+1 -2
View File
@@ -97,7 +97,6 @@ export class PlayerExecution implements Execution {
}
private removeCluster(cluster: Set<Tile>) {
console.log('removing cluster!')
const arr = Array.from(cluster)
const mode = getMode(arr.flatMap(t => t.neighbors()).filter(t => t.hasOwner() && t.owner() != this.player).map(t => t.owner().id()))
if (!this.mg.hasPlayer(mode)) {
@@ -155,6 +154,6 @@ export class PlayerExecution implements Execution {
}
isActive(): boolean {
return this.player.isAlive()
return this.player == null || this.player.isAlive()
}
}