Enhance train count management and congestion tracking in Railroad

- Update increment and decrement methods in Railroad to accept current tick for congestion calculations.
- Implement exponential moving average for congestion to adjust fare based on train density.
- Modify TrainExecution to pass tick information when managing train counts.
This commit is contained in:
scamiv
2025-11-21 18:56:51 +01:00
parent e6736e4698
commit 5d87c2189c
2 changed files with 52 additions and 8 deletions
+8 -2
View File
@@ -109,7 +109,8 @@ export class TrainExecution implements Execution {
private enterRailroad(railroad: OrientedRailroad) {
const rail = railroad.getRailroad();
rail.incrementTrainCount();
const ticks = this.mg ? this.mg.ticks() : 0;
rail.incrementTrainCount(ticks);
const fare = rail.getFare();
const tiles = railroad.getTiles();
const midTile =
@@ -124,7 +125,12 @@ export class TrainExecution implements Execution {
return;
}
const rail = this.currentRailroad.getRailroad();
rail.decrementTrainCount();
const ticks = this.mg ? this.mg.ticks() : 0;
rail.decrementTrainCount(ticks);
// Update client-side coloring when fare changes significantly
if (this.mg !== null) {
rail.updateFare(this.mg);
}
}
init(mg: Game, ticks: number): void {
+44 -6
View File
@@ -1,10 +1,18 @@
import { Game } from "./Game";
import { Game, Tick } from "./Game";
import { TileRef } from "./GameMap";
import { GameUpdateType, RailTile, RailType } from "./GameUpdates";
import { TrainStation } from "./TrainStation";
const CONGESTION_EMA_ALPHA = 0.2;
export class Railroad {
private trainCount: number = 0;
private congestionEma: number = 0;
private lastCongestionTick: Tick | null = null;
// Geometry of this railroad once construction is computed
private railTiles: RailTile[] | null = null;
// Last fare used for client-side coloring
private lastFare: bigint | null = null;
constructor(
public from: TrainStation,
@@ -26,12 +34,39 @@ export class Railroad {
this.to.removeRailroad(this);
}
incrementTrainCount(): void {
incrementTrainCount(currentTick: Tick): void {
this.trainCount++;
this.updateCongestionEma(currentTick);
}
decrementTrainCount(): void {
decrementTrainCount(currentTick: Tick): void {
this.trainCount = Math.max(0, this.trainCount - 1);
this.updateCongestionEma(currentTick);
}
private updateCongestionEma(currentTick: Tick): void {
if (this.lastCongestionTick === null) {
this.lastCongestionTick = currentTick;
this.congestionEma = this.trainCount;
return;
}
const deltaTicks = currentTick - this.lastCongestionTick;
this.lastCongestionTick = currentTick;
if (deltaTicks <= 0) {
// Fallback to single-step EMA if ticks didn't advance
const alpha = CONGESTION_EMA_ALPHA;
this.congestionEma =
alpha * this.trainCount + (1 - alpha) * this.congestionEma;
return;
}
const base = 1 - CONGESTION_EMA_ALPHA;
const decay = Math.pow(base, deltaTicks);
const alpha = 1 - decay;
this.congestionEma = alpha * this.trainCount + decay * this.congestionEma;
}
getLength(): number {
@@ -39,10 +74,13 @@ export class Railroad {
}
getFare(): bigint {
const lengthFare = BigInt(this.getLength() * 100); // Base fare proportional to length
const baseLengthFare = 10;
const baseCongestionFare = BigInt(1000);
const lengthFare = BigInt(this.getLength() * baseLengthFare); // Base fare proportional to length
// Busy railroads should be more expensive: each train adds a congestion premium
const congestionFactor = BigInt(1 + this.trainCount); // 1,2,3,...
const congestionFare = (lengthFare * congestionFactor) / 10n;
const effectiveCongestion = Math.max(0, Math.round(this.congestionEma));
const congestionFactor = BigInt(1 + effectiveCongestion); // 1,2,3,...
const congestionFare = baseCongestionFare * congestionFactor;
return lengthFare + congestionFare;
}
}