mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-08-18 17:53:29 +00:00
Adjust city gold production and fix defense post bug
This commit is contained in:
@@ -642,7 +642,7 @@ export class DefaultConfig implements Config {
|
|||||||
(adjustedCityPopulation * totalWorkers) / totalPopulation;
|
(adjustedCityPopulation * totalWorkers) / totalPopulation;
|
||||||
const ruralWorkers = totalWorkers - cityWorkers;
|
const ruralWorkers = totalWorkers - cityWorkers;
|
||||||
|
|
||||||
const cityGold = cityWorkers / 1000;
|
const cityGold = cityWorkers / 2500;
|
||||||
const tileGold = (Math.sqrt(ruralWorkers) * Math.sqrt(numTiles)) / 300;
|
const tileGold = (Math.sqrt(ruralWorkers) * Math.sqrt(numTiles)) / 300;
|
||||||
|
|
||||||
const totalGold = cityGold + tileGold;
|
const totalGold = cityGold + tileGold;
|
||||||
|
|||||||
@@ -44,10 +44,10 @@ export class FakeHumanExecution implements Execution {
|
|||||||
private lastNukeSent: [Tick, TileRef][] = [];
|
private lastNukeSent: [Tick, TileRef][] = [];
|
||||||
private embargoMalusApplied = new Set<PlayerID>();
|
private embargoMalusApplied = new Set<PlayerID>();
|
||||||
|
|
||||||
private portTargetRatio: number = 0.0003; // desired ports per tile
|
private portTargetRatio: number = 0.0001; // desired ports per tile
|
||||||
private cityTargetRatio: number = 0.0006; // desired cities per tile
|
private cityTargetRatio: number = 0.0002; // desired cities per tile
|
||||||
private defensePostSpacing: number = 50; // minimum distance between defense posts
|
private defensePostSpacing: number = 60; // minimum distance between defense posts
|
||||||
private defensePostTargetRatio: number = 0.0002; // desired defense posts per tile
|
private defensePostTargetRatio: number = 0.005; // desired defense posts per border length
|
||||||
private lastDefensePostTick: number = -9999;
|
private lastDefensePostTick: number = -9999;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@@ -416,12 +416,12 @@ export class FakeHumanExecution implements Execution {
|
|||||||
|
|
||||||
const portDeficit = Math.max(
|
const portDeficit = Math.max(
|
||||||
(this.portTargetRatio - portRatio) / this.portTargetRatio,
|
(this.portTargetRatio - portRatio) / this.portTargetRatio,
|
||||||
portsCount < 1 ? 1 : 0,
|
portsCount < 1 ? 1 : -1,
|
||||||
);
|
);
|
||||||
|
|
||||||
const cityDeficit = Math.max(
|
const cityDeficit = Math.max(
|
||||||
(this.cityTargetRatio - cityRatio) / this.cityTargetRatio,
|
(this.cityTargetRatio - cityRatio) / this.cityTargetRatio,
|
||||||
citiesCount < 3 ? 1 : 0,
|
citiesCount < 2 ? 1 : -1,
|
||||||
);
|
);
|
||||||
|
|
||||||
const canAffordPort = this.player.gold() >= this.cost(UnitType.Port);
|
const canAffordPort = this.player.gold() >= this.cost(UnitType.Port);
|
||||||
@@ -441,6 +441,7 @@ export class FakeHumanExecution implements Execution {
|
|||||||
this.mg.addExecution(
|
this.mg.addExecution(
|
||||||
new ConstructionExecution(this.player.id(), tile, UnitType.City),
|
new ConstructionExecution(this.player.id(), tile, UnitType.City),
|
||||||
);
|
);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -450,48 +451,55 @@ export class FakeHumanExecution implements Execution {
|
|||||||
this.mg.addExecution(
|
this.mg.addExecution(
|
||||||
new ConstructionExecution(this.player.id(), tile, UnitType.Port),
|
new ConstructionExecution(this.player.id(), tile, UnitType.Port),
|
||||||
);
|
);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// fallback: if port was preferred but unbuildable, try city
|
// fallback: if port was preferred but unbuildable, try city
|
||||||
if (portDeficit > cityDeficit && !canBuildPort && canBuildCity) {
|
if (
|
||||||
|
portDeficit > cityDeficit &&
|
||||||
|
!canBuildPort &&
|
||||||
|
canBuildCity &&
|
||||||
|
cityDeficit > 0
|
||||||
|
) {
|
||||||
const tile = this.randTerritoryTile(this.player);
|
const tile = this.randTerritoryTile(this.player);
|
||||||
if (tile) {
|
if (tile) {
|
||||||
this.mg.addExecution(
|
this.mg.addExecution(
|
||||||
new ConstructionExecution(this.player.id(), tile, UnitType.City),
|
new ConstructionExecution(this.player.id(), tile, UnitType.City),
|
||||||
);
|
);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (currentTick - this.lastDefensePostTick >= 10) {
|
if (currentTick - this.lastDefensePostTick >= 100) {
|
||||||
this.lastDefensePostTick = currentTick;
|
this.lastDefensePostTick = currentTick;
|
||||||
const defensePostsCount = this.player.units(UnitType.DefensePost).length;
|
const defensePostsCount = this.player.units(UnitType.DefensePost).length;
|
||||||
const defensePostRatio = defensePostsCount / tilesCount;
|
const borderTiles = new Set(this.player.borderTiles());
|
||||||
|
const defensePostRatio = defensePostsCount / borderTiles.size;
|
||||||
const defensePostDeficit = this.defensePostTargetRatio - defensePostRatio;
|
const defensePostDeficit = this.defensePostTargetRatio - defensePostRatio;
|
||||||
|
|
||||||
const canAffordDefensePost =
|
const canAffordDefensePost =
|
||||||
this.player.gold() >= this.cost(UnitType.DefensePost);
|
this.player.gold() >= this.cost(UnitType.DefensePost);
|
||||||
// consolex.log(`[${this.playerInfo.name}] can afford: ${canAffordDefensePost}, deficit: ${defensePostDeficit}`);
|
|
||||||
|
|
||||||
if (defensePostDeficit > 0 && canAffordDefensePost) {
|
if (defensePostDeficit > 0 && canAffordDefensePost) {
|
||||||
consolex.log("creating defense post");
|
|
||||||
const borderTiles = new Set(this.player.borderTiles());
|
const borderTiles = new Set(this.player.borderTiles());
|
||||||
const existingPosts = this.player
|
const existingPosts = this.player
|
||||||
.units(UnitType.DefensePost)
|
.units(UnitType.DefensePost)
|
||||||
.map((u) => u.tile());
|
.map((u) => u.tile());
|
||||||
const candidateTiles: TileRef[] = [];
|
|
||||||
|
|
||||||
const radius = 10;
|
const radius = 10;
|
||||||
|
|
||||||
const borderTileArray = Array.from(borderTiles);
|
const borderTileArray = Array.from(borderTiles);
|
||||||
this.random.shuffleArray(borderTileArray);
|
this.random.shuffleArray(borderTileArray);
|
||||||
const sampledBorderTiles = borderTileArray.slice(0, 5); // <-- scan 3 border tiles only
|
const sampledBorderTiles = borderTileArray.slice(0, 5); // <-- scan 5 border tiles only
|
||||||
|
let builtDefensePost = false;
|
||||||
|
|
||||||
for (const borderTile of sampledBorderTiles) {
|
for (const borderTile of sampledBorderTiles) {
|
||||||
const x0 = this.mg.x(borderTile);
|
const x0 = this.mg.x(borderTile);
|
||||||
const y0 = this.mg.y(borderTile);
|
const y0 = this.mg.y(borderTile);
|
||||||
|
|
||||||
tileScan: for (let dx = -radius; dx <= radius; dx++) {
|
for (let dx = -radius; dx <= radius; dx++) {
|
||||||
for (let dy = -radius; dy <= radius; dy++) {
|
for (let dy = -radius; dy <= radius; dy++) {
|
||||||
const x = x0 + dx;
|
const x = x0 + dx;
|
||||||
const y = y0 + dy;
|
const y = y0 + dy;
|
||||||
@@ -505,14 +513,12 @@ export class FakeHumanExecution implements Execution {
|
|||||||
let tooCloseToBorder = false;
|
let tooCloseToBorder = false;
|
||||||
for (const borderTile of borderTiles) {
|
for (const borderTile of borderTiles) {
|
||||||
const distSq = this.mg.euclideanDistSquared(tile, borderTile);
|
const distSq = this.mg.euclideanDistSquared(tile, borderTile);
|
||||||
if (distSq < 25) {
|
if (distSq < 36) {
|
||||||
// must be at least 5 tiles away
|
|
||||||
tooCloseToBorder = true;
|
tooCloseToBorder = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (tooCloseToBorder) continue;
|
if (tooCloseToBorder) continue;
|
||||||
|
|
||||||
let nearOtherPost = false;
|
let nearOtherPost = false;
|
||||||
for (const postTile of existingPosts) {
|
for (const postTile of existingPosts) {
|
||||||
const distSq = this.mg.euclideanDistSquared(tile, postTile);
|
const distSq = this.mg.euclideanDistSquared(tile, postTile);
|
||||||
@@ -527,26 +533,26 @@ export class FakeHumanExecution implements Execution {
|
|||||||
if (nearOtherPost) continue;
|
if (nearOtherPost) continue;
|
||||||
|
|
||||||
if (this.player.canBuild(UnitType.DefensePost, tile)) {
|
if (this.player.canBuild(UnitType.DefensePost, tile)) {
|
||||||
candidateTiles.push(tile);
|
this.mg.addExecution(
|
||||||
if (candidateTiles.length >= 5) break tileScan;
|
new ConstructionExecution(
|
||||||
|
this.player.id(),
|
||||||
|
tile,
|
||||||
|
UnitType.DefensePost,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
builtDefensePost = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (builtDefensePost) break;
|
||||||
}
|
}
|
||||||
if (candidateTiles.length > 0) {
|
if (builtDefensePost) break;
|
||||||
const tile = this.random.randElement(candidateTiles);
|
}
|
||||||
this.mg.addExecution(
|
|
||||||
new ConstructionExecution(
|
if (!builtDefensePost) {
|
||||||
this.player.id(),
|
consolex.log(
|
||||||
tile,
|
`[${this.playerInfo.name}] no valid tile found for Defense Post`,
|
||||||
UnitType.DefensePost,
|
);
|
||||||
),
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
consolex.log(
|
|
||||||
`[${this.playerInfo.name}] no valid tile found for Defense Post`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user