perf(game): optimize border tile updates (#3124)

## Description

Optimize border-tile maintenance in `GameImpl` to reduce per-conquest
overhead.

Border tiles are updated whenever ownership changes; this PR trims
allocations and avoids unnecessary iteration in the hot path.

## Changes

- `src/core/game/GameImpl.ts`
- `updateBorders(tile)` no longer allocates an array of tiles; it
updates the changed tile and its 4-neighbors directly via
`forEachNeighbor`.
- `calcIsBorder(tile)` no longer calls `neighbors(tile)` / loops an
array; it checks the four cardinal neighbors via `x/y` bounds and
`ownerID`.

## Affected Functions

- `GameImpl.updateBorders(tile: TileRef)`
- `GameImpl.calcIsBorder(tile: TileRef): boolean`
- Call sites impacted by behavior/perf:
  - `GameImpl.conquer(owner, tile)`
  - `GameImpl.relinquish(tile)`

## Please complete the following:

- [ ] I have added screenshots for all UI updates
- [ ] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [ ] I have added relevant tests to the test directory
- [ ] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced

## Please put your Discord username so you can be contacted if a bug or
regression is found:

DISCORD_USERNAME
This commit is contained in:
scamiv
2026-02-05 05:19:50 +01:00
committed by GitHub
parent ec5fb4fa22
commit d40923fc18
+29 -14
View File
@@ -622,31 +622,46 @@ export class GameImpl implements Game {
}
private updateBorders(tile: TileRef) {
const tiles: TileRef[] = [];
tiles.push(tile);
this.neighbors(tile).forEach((t) => tiles.push(t));
for (const t of tiles) {
const updateBorderStatus = (t: TileRef) => {
if (!this.hasOwner(t)) {
continue;
return;
}
const owner = this.owner(t) as PlayerImpl;
if (this.calcIsBorder(t)) {
(this.owner(t) as PlayerImpl)._borderTiles.add(t);
owner._borderTiles.add(t);
} else {
(this.owner(t) as PlayerImpl)._borderTiles.delete(t);
owner._borderTiles.delete(t);
}
}
};
updateBorderStatus(tile);
this.forEachNeighbor(tile, updateBorderStatus);
}
private calcIsBorder(tile: TileRef): boolean {
if (!this.hasOwner(tile)) {
return false;
}
for (const neighbor of this.neighbors(tile)) {
const bordersEnemy = this.owner(tile) !== this.owner(neighbor);
if (bordersEnemy) {
return true;
}
const ownerId = this.ownerID(tile);
const x = this.x(tile);
const y = this.y(tile);
if (x > 0 && this.ownerID(this._map.ref(x - 1, y)) !== ownerId) {
return true;
}
if (
x + 1 < this._width &&
this.ownerID(this._map.ref(x + 1, y)) !== ownerId
) {
return true;
}
if (y > 0 && this.ownerID(this._map.ref(x, y - 1)) !== ownerId) {
return true;
}
if (
y + 1 < this._height &&
this.ownerID(this._map.ref(x, y + 1)) !== ownerId
) {
return true;
}
return false;
}