This commit is contained in:
icslucas
2025-10-25 19:37:40 +02:00
parent 565b1345ad
commit b10cadff20
13 changed files with 405 additions and 22 deletions
+95
View File
@@ -37,6 +37,13 @@ export class SpawnExecution implements Execution {
player = this.mg.addPlayer(this.playerInfo);
}
<<<<<<< Updated upstream
=======
const spawnTile = this.isNukeWarsAndBaikal(player)
? this.findBestNukeWarsSpawn(player)
: this.tile;
>>>>>>> Stashed changes
player.tiles().forEach((t) => player.relinquish(t));
getSpawnTiles(this.mg, this.tile).forEach((t) => {
player.conquer(t);
@@ -58,4 +65,92 @@ export class SpawnExecution implements Execution {
activeDuringSpawnPhase(): boolean {
return true;
}
private isNukeWarsAndBaikal(player: Player): boolean {
const gc = this.mg.config().gameConfig();
return (
gc.gameMode === GameMode.NukeWars && gc.gameMap === GameMapType.Baikal
);
}
private findBestNukeWarsSpawn(player: Player): TileRef {
const mapWidth = this.mg.width();
const midpoint = Math.floor(mapWidth / 2);
const wantLeft = player.smallID() % 2 === 1;
let bestTile: TileRef | null = null;
let bestScore = Infinity;
this.mg.forEachTile((t) => {
const xt = this.mg.x(t);
const onCorrectHalf = wantLeft ? xt < midpoint : xt >= midpoint;
if (onCorrectHalf && !this.mg.hasOwner(t) && this.mg.isLand(t)) {
const distToOriginal = this.mg.manhattanDist(this.tile, t);
const distToMidpoint = Math.abs(xt - midpoint);
const distToTeam = this.minDistToTeam(player, t);
// Score combines distance from original tile, distance from midpoint, and distance from team members.
// We want to be close to the original spawn, but also spread out from teammates.
const score =
distToOriginal +
distToMidpoint * -0.5 + // Bias towards the center
(isFinite(distToTeam) ? -distToTeam * 0.9 : 0) + // Bias away from teammates
this.bandScore(player, t); // Bias towards a vertical band to spread out spawns
if (score < bestScore) {
bestScore = score;
bestTile = t;
}
}
});
return bestTile ?? this.tile;
}
private minDistToTeam(player: Player, tile: TileRef): number {
let minDist = Infinity;
const team = player.team();
if (!team) {
return minDist;
}
for (const p of this.mg.players()) {
if (p.team() !== team || p === player) {
continue;
}
for (const owned of p.tiles()) {
const d = this.mg.manhattanDist(owned, tile);
if (d < minDist) {
minDist = d;
}
if (minDist === 0) {
return 0;
}
}
}
return minDist;
}
private bandScore(player: Player, tile: TileRef): number {
const team = player.team();
if (!team) {
return 0;
}
const teamPlayers = this.mg
.players()
.filter((pp) => pp.team() === team)
.sort((a, b) => a.smallID() - b.smallID());
const teamIndex = teamPlayers.findIndex((pp) => pp === player);
const teamCount = Math.max(1, teamPlayers.length);
const numBands = Math.max(1, Math.round(Math.sqrt(teamCount)));
const desiredBand = Math.floor((teamIndex / teamCount) * numBands);
const y = this.mg.y(tile);
const bandIndex = Math.floor((y / this.mg.height()) * numBands);
const bandPenalty = 24; // tunes vertical spread strength
return Math.abs(bandIndex - desiredBand) * bandPenalty;
}
}