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: 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 ```bash
git submodule update --init --recursive
npm install npm install
``` ```
+1
View File
@@ -127,6 +127,7 @@ export class PlayerImpl implements MutablePlayer {
} }
removeTroops(troops: number): void { removeTroops(troops: number): void {
this._troops -= troops this._troops -= troops
this._troops = Math.max(this._troops, 0)
} }
isPlayer(): this is MutablePlayer {return true as const} 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 {Colord, colord} from "colord";
import {pastelTheme} from "./PastelTheme"; import {pastelTheme} from "./PastelTheme";
export interface Config { export interface Config {
theme(): Theme; theme(): Theme;
player(): PlayerConfig player(): PlayerConfig
@@ -13,7 +14,12 @@ export interface Config {
export interface PlayerConfig { export interface PlayerConfig {
startTroops(playerInfo: PlayerInfo): number startTroops(playerInfo: PlayerInfo): number
troopAdditionRate(player: Player): 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 attackAmount(attacker: Player, defender: Player | TerraNullius): number
boatAttackAmount(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 {Config, PlayerConfig, Theme} from "./Config";
import {pastelTheme} from "./PastelTheme"; import {pastelTheme} from "./PastelTheme";
@@ -19,9 +19,28 @@ export const defaultConfig = new class implements Config {
} }
export const defaultPlayerConfig = new class implements PlayerConfig { 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 { boatAttackAmount(attacker: Player, defender: Player | TerraNullius): number {
return attacker.troops() / 5 return attacker.troops() / 5
} }
attackAmount(attacker: Player, defender: Player | TerraNullius) { attackAmount(attacker: Player, defender: Player | TerraNullius) {
if (attacker.info().isBot) { if (attacker.info().isBot) {
return attacker.troops() / 20 return attacker.troops() / 20
@@ -44,8 +63,4 @@ export const defaultPlayerConfig = new class implements PlayerConfig {
return Math.min(player.troops() + toAdd, max) 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 {Cell, Execution, MutableGame, MutablePlayer, PlayerID, Player, TerrainTypes, TerraNullius, Tile} from "../Game";
import {PseudoRandom} from "../PseudoRandom"; import {PseudoRandom} from "../PseudoRandom";
import {manhattanDist} from "../Util"; import {manhattanDist} from "../Util";
import {PlayerConfig} from "../configuration/Config";
export class AttackExecution implements Execution { export class AttackExecution implements Execution {
private active: boolean = true; private active: boolean = true;
@@ -20,7 +21,8 @@ export class AttackExecution implements Execution {
private troops: number, private troops: number,
private _ownerID: PlayerID, private _ownerID: PlayerID,
private targetID: PlayerID | null, private targetID: PlayerID | null,
private targetCell: Cell | null private targetCell: Cell | null,
private playerConfig: PlayerConfig
) { } ) { }
init(mg: MutableGame, ticks: number) { init(mg: MutableGame, ticks: number) {
@@ -61,7 +63,7 @@ export class AttackExecution implements Execution {
return return
} }
let numTilesPerTick = this.numTilesWithEnemy / 4 let numTilesPerTick = this.playerConfig.attackTilesPerTick(this._owner, this.target, this.numTilesWithEnemy)
if (this.targetCell != null) { if (this.targetCell != null) {
numTilesPerTick /= 2 numTilesPerTick /= 2
} }
@@ -88,15 +90,13 @@ export class AttackExecution implements Execution {
badTiles++ badTiles++
continue continue
} }
// TODO: move this to configs const {attackerTroopLoss, defenderTroopLoss, tilesPerTickUsed} = this.playerConfig.attackLogic(this._owner, this.target, tileToConquer)
this._owner.conquer(tileToConquer) numTilesPerTick -= tilesPerTickUsed
this.troops -= attackerTroopLoss
if (this.target.isPlayer()) { if (this.target.isPlayer()) {
this.troops -= Math.max(this.target.troops() / this._owner.troops(), 1) this.target.removeTroops(defenderTroopLoss)
numTilesPerTick -= Math.max(this.target.troops() / this._owner.troops(), .25)
} else {
this.troops -= 1
numTilesPerTick -= 1
} }
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 {Boat, Cell, Execution, MutableBoat, MutableGame, MutablePlayer, Player, PlayerID, Tile} from "../Game";
import {manhattanDist} from "../Util"; import {manhattanDist} from "../Util";
import {AttackExecution} from "./AttackExecution"; import {AttackExecution} from "./AttackExecution";
import {PlayerConfig} from "../configuration/Config";
export class BoatAttackExecution implements Execution { export class BoatAttackExecution implements Execution {
@@ -29,7 +30,8 @@ export class BoatAttackExecution implements Execution {
private attackerID: PlayerID, private attackerID: PlayerID,
private targetID: PlayerID | null, private targetID: PlayerID | null,
private cell: Cell, private cell: Cell,
private troops: number private troops: number,
private playerConfig: PlayerConfig
) { } ) { }
init(mg: MutableGame, ticks: number) { init(mg: MutableGame, ticks: number) {
@@ -80,7 +82,7 @@ export class BoatAttackExecution implements Execution {
return return
} }
this.attacker.conquer(this.dst) 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 this.active = false
return 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 {Cell, Execution, MutableGame, MutablePlayer, Player, PlayerID, PlayerInfo, TerraNullius} from "../Game"
import {PseudoRandom} from "../PseudoRandom" import {PseudoRandom} from "../PseudoRandom"
import {AttackExecution} from "./AttackExecution"; import {AttackExecution} from "./AttackExecution";
@@ -10,7 +11,7 @@ export class BotExecution implements Execution {
private gs: MutableGame private gs: MutableGame
private neighborsTerra = true private neighborsTerra = true
constructor(private bot: MutablePlayer) { constructor(private bot: MutablePlayer, private playerConfig: PlayerConfig) {
this.random = new PseudoRandom(bot.id()) this.random = new PseudoRandom(bot.id())
this.attackRate = this.random.nextInt(10, 50) this.attackRate = this.random.nextInt(10, 50)
@@ -57,7 +58,8 @@ export class BotExecution implements Execution {
this.bot.troops() / 20, this.bot.troops() / 20,
this.bot.id(), this.bot.id(),
toAttack.isPlayer() ? toAttack.id() : null, toAttack.isPlayer() ? toAttack.id() : null,
null null,
this.playerConfig
)) ))
} }
+3 -1
View File
@@ -25,7 +25,8 @@ export class Executor {
intent.troops, intent.troops,
intent.attackerID, intent.attackerID,
intent.targetID, intent.targetID,
new Cell(intent.targetX, intent.targetY) new Cell(intent.targetX, intent.targetY),
this.playerConfig
) )
) )
} else if (intent.type == "spawn") { } else if (intent.type == "spawn") {
@@ -43,6 +44,7 @@ export class Executor {
intent.targetID, intent.targetID,
new Cell(intent.x, intent.y), new Cell(intent.x, intent.y),
intent.troops, intent.troops,
this.playerConfig
) )
) )
} else { } else {
+1 -1
View File
@@ -30,7 +30,7 @@ export class SpawnExecution implements Execution {
}) })
this.gs.addExecution(new PlayerExecution(player.id(), this.playerConfig)) this.gs.addExecution(new PlayerExecution(player.id(), this.playerConfig))
if (player.info().isBot) { if (player.info().isBot) {
this.gs.addExecution(new BotExecution(player)) this.gs.addExecution(new BotExecution(player, this.playerConfig))
} }
this.active = false this.active = false
} }