mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-07-19 15:15:04 +00:00
fakehumans send boats, improved map
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user