diff --git a/src/client/Client.ts b/src/client/Client.ts index 9d5b68ef0..73e71f42a 100644 --- a/src/client/Client.ts +++ b/src/client/Client.ts @@ -56,12 +56,12 @@ class Client { this.lobbiesContainer.appendChild(button); }); - // Join first lobby - if (!this.hasJoined && lobbies.length > 0) { - this.hasJoined = true - console.log(`joining lobby ${lobbies[0].id}`) - this.joinLobby(lobbies[0].id) - } + // // Join first lobby + // if (!this.hasJoined && lobbies.length > 0) { + // this.hasJoined = true + // console.log(`joining lobby ${lobbies[0].id}`) + // this.joinLobby(lobbies[0].id) + // } } async fetchLobbies() { diff --git a/src/client/ClientGame.ts b/src/client/ClientGame.ts index 272ea8349..37e6952da 100644 --- a/src/client/ClientGame.ts +++ b/src/client/ClientGame.ts @@ -95,7 +95,7 @@ export class ClientGame { this.renderer.initialize() this.input.initialize() - this.executor.spawnBots(500) + this.executor.spawnBots(1000) setInterval(() => this.tick(), 10); @@ -148,7 +148,7 @@ export class ClientGame { const owner = tile.owner() const targetID = owner.isPlayer() ? owner.id() : null if (tile.owner() != this.myPlayer) { - if (this.myPlayer.sharesBorderWith(tile.owner())) { + if (this.myPlayer.sharesBorderWith(tile.owner())) { this.sendAttackIntent(targetID, cell) } else { // TODO verify on ocean diff --git a/src/client/GameRenderer.ts b/src/client/GameRenderer.ts index e15b8a93a..3c9619cd9 100644 --- a/src/client/GameRenderer.ts +++ b/src/client/GameRenderer.ts @@ -193,15 +193,15 @@ export class GameRenderer { tileUpdate(event: TileEvent) { this.paintTile(event.tile) - this.gs.neighbors(event.tile.cell()).forEach(c => this.paintTile(this.gs.tile(c))) + event.tile.neighbors().forEach(t => this.paintTile(t)) } playerEvent(event: PlayerEvent) { } boatEvent(event: BoatEvent) { - this.paintCell(event.boat.cell(), new Colord({r: 255, g: 255, b: 255})) - this.gs.neighbors(event.boat.cell()).map(c => this.gs.tile(c)).forEach(t => this.paintTile(t)) + this.paintCell(event.boat.tile().cell(), new Colord({r: 255, g: 255, b: 255})) + this.gs.neighbors(event.boat.tile()).forEach(t => this.paintTile(t)) } resize(width: number, height: number): void { diff --git a/src/core/Game.ts b/src/core/Game.ts index 904eb0f06..1a119b936 100644 --- a/src/core/Game.ts +++ b/src/core/Game.ts @@ -75,13 +75,13 @@ export interface Tile { export interface Boat { troops(): number - cell(): Cell + tile(): Tile owner(): Player target(): Player | TerraNullius } export interface MutableBoat extends Boat { - move(cell: Cell): void + move(tile: Tile): void owner(): MutablePlayer target(): MutablePlayer | TerraNullius setTroops(troops: number): void @@ -115,7 +115,7 @@ export interface MutablePlayer extends Player { executions(): Execution[] neighbors(): (MutablePlayer | TerraNullius)[] boats(): MutableBoat[] - addBoat(troops: number, cell: Cell, target: Player | TerraNullius): MutableBoat + addBoat(troops: number, tile: Tile, target: Player | TerraNullius): MutableBoat } export interface Game { @@ -124,7 +124,7 @@ export interface Game { players(): Player[] tile(cell: Cell): Tile isOnMap(cell: Cell): boolean - neighbors(cell: Cell): Cell[] + neighbors(cell: Cell | Tile): Tile[] width(): number height(): number forEachTile(fn: (tile: Tile) => void): void diff --git a/src/core/GameImpl.ts b/src/core/GameImpl.ts index a07766db7..ca97c6ad2 100644 --- a/src/core/GameImpl.ts +++ b/src/core/GameImpl.ts @@ -9,6 +9,8 @@ type CellString = string class TileImpl implements Tile { + public _isBorder = false + constructor( private readonly gs: GameImpl, public _owner: PlayerImpl | TerraNulliusImpl, @@ -24,13 +26,13 @@ class TileImpl implements Tile { hasOwner(): boolean {return this._owner != this.gs._terraNullius} owner(): MutablePlayer | TerraNullius {return this._owner} - isBorder(): boolean {return this.gs.isBorder(this)} + isBorder(): boolean {return this._isBorder} isInterior(): boolean {return this.hasOwner() && !this.isBorder()} cell(): Cell {return this._cell} terrain(): TerrainType {return this._terrain} neighbors(): Tile[] { - return this.gs.neighbors(this._cell).map(c => this.gs.tile(c)) + return this.gs.neighbors(this) } game(): Game {return this.gs} @@ -40,14 +42,14 @@ export class BoatImpl implements MutableBoat { constructor( private g: GameImpl, - private _cell: Cell, + private _tile: Tile, private _troops: number, private _owner: PlayerImpl, private _target: PlayerImpl | TerraNulliusImpl ) { } - move(cell: Cell): void { - this._cell = cell + move(tile: Tile): void { + this._tile = tile this.g.fireBoatUpdateEvent(this) } setTroops(troops: number): void { @@ -56,8 +58,8 @@ export class BoatImpl implements MutableBoat { troops(): number { return this._troops } - cell(): Cell { - return this._cell + tile(): Tile { + return this._tile } owner(): PlayerImpl { return this._owner @@ -77,8 +79,8 @@ export class PlayerImpl implements MutablePlayer { constructor(private gs: GameImpl, public readonly _id: PlayerID, public readonly playerInfo: PlayerInfo, private _troops) { } - addBoat(troops: number, cell: Cell, target: Player | TerraNullius): BoatImpl { - const b = new BoatImpl(this.gs, cell, troops, this, target as PlayerImpl | TerraNulliusImpl) + addBoat(troops: number, tile: Tile, target: Player | TerraNullius): BoatImpl { + const b = new BoatImpl(this.gs, tile, troops, this, target as PlayerImpl | TerraNulliusImpl) this._boats.push(b) this.gs.fireBoatUpdateEvent(b) return b @@ -184,6 +186,7 @@ export class GameImpl implements MutableGame { private _height: number _terraNullius: TerraNulliusImpl + constructor(terrainMap: TerrainMap, private eventBus: EventBus) { this._terraNullius = new TerraNulliusImpl(this) this._width = terrainMap.width(); @@ -281,21 +284,26 @@ export class GameImpl implements MutableGame { && cell.y < this._height } - neighbors(cell: Cell): Cell[] { - this.assertIsOnMap(cell) - const ns = [ - new Cell(cell.x + 1, cell.y), - new Cell(cell.x - 1, cell.y), - new Cell(cell.x, cell.y + 1), - new Cell(cell.x, cell.y - 1) - ].filter(c => this.isOnMap(c)) + neighbors(tile: Tile): Tile[] { + this.assertIsOnMap(tile.cell()) + const x = tile.cell().x + const y = tile.cell().y + const ns: TileImpl[] = [] + if (y > 0) { + ns.push(this.map[x][y - 1]) + } + if (y < this._height - 1) { + ns.push(this.map[x][y + 1]) + } + if (x > 0) { + ns.push(this.map[x - 1][y]) + } + if (x < this._width - 1) { + ns.push(this.map[x + 1][y]) + } return ns } - tileNeighbors(tile: Tile): Tile[] { - return this.neighbors(tile.cell()).map(c => this.tile(c)) - } - private assertIsOnMap(cell: Cell) { if (!this.isOnMap(cell)) { throw new Error(`cell ${cell.toString()} is not on map`) @@ -318,35 +326,37 @@ export class GameImpl implements MutableGame { previousOwner.tiles.delete(cell.toString()) previousOwner._borderTiles.delete(cell.toString()) previousOwner._borderTileSet.delete(tile) + tile._isBorder = false } tile._owner = owner owner.tiles.set(cell.toString(), tile) - this.updateBorders(cell) + this.updateBorders(tile) this.eventBus.emit(new TileEvent(tile)) } - private updateBorders(cell: Cell) { - const cells: Cell[] = [] - cells.push(cell) - this.neighbors(cell).forEach(c => cells.push(c)) - cells.map(c => this.tile(c)).filter(c => c.hasOwner()).forEach(t => { + private updateBorders(tile: Tile) { + const tiles: Tile[] = [] + tiles.push(tile) + tile.neighbors().forEach(t => tiles.push(t)) + tiles.filter(t => t.hasOwner()).forEach(t => { if (this.isBorder(t)) { (t.owner() as PlayerImpl)._borderTiles.set(t.cell().toString(), t); - (t.owner() as PlayerImpl)._borderTileSet.add(t) + (t.owner() as PlayerImpl)._borderTileSet.add(t); + (t as TileImpl)._isBorder = true } else { (t.owner() as PlayerImpl)._borderTiles.delete(t.cell().toString()); - (t.owner() as PlayerImpl)._borderTileSet.delete(t) + (t.owner() as PlayerImpl)._borderTileSet.delete(t); + (t as TileImpl)._isBorder = false } }) } isBorder(tile: Tile): boolean { - this.assertIsOnMap(tile.cell()) if (!tile.hasOwner()) { return false } - for (const neighbor of this.neighbors(tile.cell())) { - let bordersEnemy = this.tile(neighbor).owner() != tile.owner() + for (const neighbor of tile.neighbors()) { + let bordersEnemy = tile.owner() != neighbor.owner() if (bordersEnemy) { return true } diff --git a/src/core/execution/AttackExecution.ts b/src/core/execution/AttackExecution.ts index e1dbefa60..5abed3e12 100644 --- a/src/core/execution/AttackExecution.ts +++ b/src/core/execution/AttackExecution.ts @@ -5,7 +5,7 @@ import {manhattanDist} from "../Util"; export class AttackExecution implements Execution { private active: boolean = true; - private toConquer: PriorityQueue = new PriorityQueue(11, (a: TileContainer, b: TileContainer) => a.priority - b.priority); + private toConquer: PriorityQueue = new PriorityQueue(1000, (a: TileContainer, b: TileContainer) => a.priority - b.priority); private random = new PseudoRandom(123) private _owner: MutablePlayer @@ -50,7 +50,7 @@ export class AttackExecution implements Execution { return } - if (this.toConquer.size() < 10) { + if (this.toConquer.size() < 5) { this.calculateToConquer() } if (this.toConquer.size() == 0) { @@ -130,7 +130,7 @@ export class AttackExecution implements Execution { // .filter(t => t.terrain() == TerrainTypes.Land) // .filter(t => t.owner() == this._owner) // .length - this.toConquer.add(new TileContainer(neighbor, + this.random.nextInt(0, 4))) + this.toConquer.add(new TileContainer(neighbor, 1)) } } // } diff --git a/src/core/execution/BoatAttackExecution.ts b/src/core/execution/BoatAttackExecution.ts index d7597009a..5f8307933 100644 --- a/src/core/execution/BoatAttackExecution.ts +++ b/src/core/execution/BoatAttackExecution.ts @@ -50,7 +50,7 @@ export class BoatAttackExecution implements Execution { this.path = this.computePath(this.src, this.dst) if (this.path != null) { console.log(`got path ${this.path.map(t => t.cell().toString())}`) - this.boat = this.attacker.addBoat(1000, this.src.cell(), this.target) + this.boat = this.attacker.addBoat(1000, this.src, this.target) } else { console.log('got null path') this.active = false @@ -80,7 +80,7 @@ export class BoatAttackExecution implements Execution { } const nextTile = this.path[this.currTileIndex] - this.boat.move(nextTile.cell()) + this.boat.move(nextTile) } owner(): MutablePlayer { diff --git a/src/core/execution/BotExecution.ts b/src/core/execution/BotExecution.ts index d3e091526..0a4f94a25 100644 --- a/src/core/execution/BotExecution.ts +++ b/src/core/execution/BotExecution.ts @@ -12,7 +12,7 @@ export class BotExecution implements Execution { constructor(private bot: MutablePlayer) { this.random = new PseudoRandom(bot.id()) - this.attackRate = this.random.nextInt(50, 200) + this.attackRate = this.random.nextInt(10, 50) } init(gs: MutableGame, ticks: number) { @@ -35,7 +35,7 @@ export class BotExecution implements Execution { const toAttack = ns[this.random.nextInt(0, ns.length)] this.gs.addExecution(new AttackExecution( - this.bot.troops() / 5, + this.bot.troops() / 100, this.bot.id(), toAttack.isPlayer() ? toAttack.id() : null, null