moved attack logic to config

This commit is contained in:
evanpelle
2024-08-16 13:10:44 -07:00
parent 0806ab17c5
commit 51c05f9d10
9 changed files with 51 additions and 24 deletions
-1
View File
@@ -11,7 +11,6 @@ To build the project, you will need to have Node.js and npm installed. You can d
Before building the project, you will need to install the dependencies. You can do this by running the following command in the project directory:
```bash
git submodule update --init --recursive
npm install
```
+1
View File
@@ -127,6 +127,7 @@ export class PlayerImpl implements MutablePlayer {
}
removeTroops(troops: number): void {
this._troops -= troops
this._troops = Math.max(this._troops, 0)
}
isPlayer(): this is MutablePlayer {return true as const}
+8 -2
View File
@@ -1,7 +1,8 @@
import {Player, PlayerID, PlayerInfo, TerrainType, TerrainTypes, TerraNullius} from "../Game";
import {Player, PlayerID, PlayerInfo, TerrainType, TerrainTypes, TerraNullius, Tile} from "../Game";
import {Colord, colord} from "colord";
import {pastelTheme} from "./PastelTheme";
export interface Config {
theme(): Theme;
player(): PlayerConfig
@@ -13,7 +14,12 @@ export interface Config {
export interface PlayerConfig {
startTroops(playerInfo: PlayerInfo): number
troopAdditionRate(player: Player): number
attackLogic(attack: Player, defender: Player | TerraNullius): number
attackTilesPerTick(attacker: Player, defender: Player | TerraNullius, numAdjacentTilesWithEnemy: number): number
attackLogic(attacker: Player, defender: Player | TerraNullius, tileToConquer: Tile): {
attackerTroopLoss: number,
defenderTroopLoss: number,
tilesPerTickUsed: number
}
attackAmount(attacker: Player, defender: Player | TerraNullius): number
boatAttackAmount(attacker: Player, defender: Player | TerraNullius): number
}
+20 -5
View File
@@ -1,4 +1,4 @@
import {Player, PlayerInfo, TerraNullius} from "../Game";
import {Player, PlayerInfo, TerraNullius, Tile} from "../Game";
import {Config, PlayerConfig, Theme} from "./Config";
import {pastelTheme} from "./PastelTheme";
@@ -19,9 +19,28 @@ export const defaultConfig = new class implements Config {
}
export const defaultPlayerConfig = new class implements PlayerConfig {
attackLogic(attacker: Player, defender: Player | TerraNullius, tileToConquer: Tile): {attackerTroopLoss: number; defenderTroopLoss: number; tilesPerTickUsed: number} {
if (defender.isPlayer()) {
return {
attackerTroopLoss: Math.max(defender.troops() / attacker.troops(), 1),
defenderTroopLoss: 0,
tilesPerTickUsed: Math.max(defender.troops() / attacker.troops(), .25)
}
} else {
return {attackerTroopLoss: 1, defenderTroopLoss: 0, tilesPerTickUsed: 1}
}
}
attackTilesPerTick(attacker: Player, defender: Player | TerraNullius, numAdjacentTilesWithEnemy: number): number {
return numAdjacentTilesWithEnemy / 4
}
boatAttackAmount(attacker: Player, defender: Player | TerraNullius): number {
return attacker.troops() / 5
}
attackAmount(attacker: Player, defender: Player | TerraNullius) {
if (attacker.info().isBot) {
return attacker.troops() / 20
@@ -44,8 +63,4 @@ export const defaultPlayerConfig = new class implements PlayerConfig {
return Math.min(player.troops() + toAdd, max)
}
attackLogic(attack: Player, defender: Player | TerraNullius): number {
throw new Error("Method not implemented.");
}
}
+9 -9
View File
@@ -2,6 +2,7 @@ import PriorityQueue from "priority-queue-typescript";
import {Cell, Execution, MutableGame, MutablePlayer, PlayerID, Player, TerrainTypes, TerraNullius, Tile} from "../Game";
import {PseudoRandom} from "../PseudoRandom";
import {manhattanDist} from "../Util";
import {PlayerConfig} from "../configuration/Config";
export class AttackExecution implements Execution {
private active: boolean = true;
@@ -20,7 +21,8 @@ export class AttackExecution implements Execution {
private troops: number,
private _ownerID: PlayerID,
private targetID: PlayerID | null,
private targetCell: Cell | null
private targetCell: Cell | null,
private playerConfig: PlayerConfig
) { }
init(mg: MutableGame, ticks: number) {
@@ -61,7 +63,7 @@ export class AttackExecution implements Execution {
return
}
let numTilesPerTick = this.numTilesWithEnemy / 4
let numTilesPerTick = this.playerConfig.attackTilesPerTick(this._owner, this.target, this.numTilesWithEnemy)
if (this.targetCell != null) {
numTilesPerTick /= 2
}
@@ -88,15 +90,13 @@ export class AttackExecution implements Execution {
badTiles++
continue
}
// TODO: move this to configs
this._owner.conquer(tileToConquer)
const {attackerTroopLoss, defenderTroopLoss, tilesPerTickUsed} = this.playerConfig.attackLogic(this._owner, this.target, tileToConquer)
numTilesPerTick -= tilesPerTickUsed
this.troops -= attackerTroopLoss
if (this.target.isPlayer()) {
this.troops -= Math.max(this.target.troops() / this._owner.troops(), 1)
numTilesPerTick -= Math.max(this.target.troops() / this._owner.troops(), .25)
} else {
this.troops -= 1
numTilesPerTick -= 1
this.target.removeTroops(defenderTroopLoss)
}
this._owner.conquer(tileToConquer)
}
}
+4 -2
View File
@@ -2,6 +2,7 @@ import PriorityQueue from "priority-queue-typescript";
import {Boat, Cell, Execution, MutableBoat, MutableGame, MutablePlayer, Player, PlayerID, Tile} from "../Game";
import {manhattanDist} from "../Util";
import {AttackExecution} from "./AttackExecution";
import {PlayerConfig} from "../configuration/Config";
export class BoatAttackExecution implements Execution {
@@ -29,7 +30,8 @@ export class BoatAttackExecution implements Execution {
private attackerID: PlayerID,
private targetID: PlayerID | null,
private cell: Cell,
private troops: number
private troops: number,
private playerConfig: PlayerConfig
) { }
init(mg: MutableGame, ticks: number) {
@@ -80,7 +82,7 @@ export class BoatAttackExecution implements Execution {
return
}
this.attacker.conquer(this.dst)
this.mg.addExecution(new AttackExecution(this.troops, this.attacker.id(), this.targetID, null))
this.mg.addExecution(new AttackExecution(this.troops, this.attacker.id(), this.targetID, null, this.playerConfig))
this.active = false
return
}
+4 -2
View File
@@ -1,3 +1,4 @@
import {PlayerConfig} from "../configuration/Config";
import {Cell, Execution, MutableGame, MutablePlayer, Player, PlayerID, PlayerInfo, TerraNullius} from "../Game"
import {PseudoRandom} from "../PseudoRandom"
import {AttackExecution} from "./AttackExecution";
@@ -10,7 +11,7 @@ export class BotExecution implements Execution {
private gs: MutableGame
private neighborsTerra = true
constructor(private bot: MutablePlayer) {
constructor(private bot: MutablePlayer, private playerConfig: PlayerConfig) {
this.random = new PseudoRandom(bot.id())
this.attackRate = this.random.nextInt(10, 50)
@@ -57,7 +58,8 @@ export class BotExecution implements Execution {
this.bot.troops() / 20,
this.bot.id(),
toAttack.isPlayer() ? toAttack.id() : null,
null
null,
this.playerConfig
))
}
+3 -1
View File
@@ -25,7 +25,8 @@ export class Executor {
intent.troops,
intent.attackerID,
intent.targetID,
new Cell(intent.targetX, intent.targetY)
new Cell(intent.targetX, intent.targetY),
this.playerConfig
)
)
} else if (intent.type == "spawn") {
@@ -43,6 +44,7 @@ export class Executor {
intent.targetID,
new Cell(intent.x, intent.y),
intent.troops,
this.playerConfig
)
)
} else {
+1 -1
View File
@@ -30,7 +30,7 @@ export class SpawnExecution implements Execution {
})
this.gs.addExecution(new PlayerExecution(player.id(), this.playerConfig))
if (player.info().isBot) {
this.gs.addExecution(new BotExecution(player))
this.gs.addExecution(new BotExecution(player, this.playerConfig))
}
this.active = false
}