Draw freight on the card, and teach the bot to build a railroad

This commit is contained in:
Jesse
2026-08-04 04:59:23 -04:00
parent e23d81eade
commit 982952fd6c
11 changed files with 1288 additions and 89 deletions
+18 -4
View File
@@ -149,9 +149,23 @@ export function hasFreightAgentOption(s: GameState, player: PlayerIndex): boolea
* for an empty coach to be spotted on a hopper siding, and because a load parked on MEN|AT|WORK
* strips the industry track of Operational Rail status (§9.3), the facility would jam permanently.
*/
/**
* EVERY commodity a facility handles, not just the first one printed.
*
* Two of the six industries take two: a Power Plant burns coal OR oil (`['hopper','tank']`) and a
* Grocer's Warehouse receives dry goods OR perishables (`['boxcar','reefer']`). This used to return
* `carTypes[0]`, and because `freightAgent.stockOutbound` gates on it, the engine rejected the
* second commodity as WRONG_CAR_TYPE — the sheet said a Power Plant takes tank cars and the code
* said it did not. Measured effect: tank cars were dropped 0 times in 100 games.
*/
export function facilityCarTypes(f: Facility): readonly CarType[] {
if (f.kind !== 'freight') return f.kind === 'passenger' ? ['coach'] : [];
return FREIGHT_PROFILES.find((p) => p.kind === f.subtype)?.carTypes ?? [];
}
/** The commodity to NAME a facility by, where one word is wanted. Legality must use the full set. */
export function facilityCarType(f: Facility): CarType | null {
if (f.kind !== 'freight') return f.kind === 'passenger' ? 'coach' : null;
return FREIGHT_PROFILES.find((p) => p.kind === f.subtype)?.carTypes[0] ?? null;
return facilityCarTypes(f)[0] ?? null;
}
export function hasSwitchOption(s: GameState, player: PlayerIndex): boolean {
@@ -433,8 +447,8 @@ export function check(s: GameState, player: PlayerIndex, i: Intent): RejectionCo
if (!f) return 'NO_SUCH_FACILITY';
if (!f.allows.outbound) return 'NO_SUCH_FACILITY';
if (f.outboundBox.length >= f.capacity.outbound) return 'BOX_FULL';
// §9.1 — the green box takes only this facility's commodity.
if (facilityCarType(f) !== i.carType) return 'WRONG_CAR_TYPE';
// §9.1 — the green box takes only this facility's commodities, of which it may have two.
if (!facilityCarTypes(f).includes(i.carType)) return 'WRONG_CAR_TYPE';
if (!s.yards.divisionYard.some((c) => c.type === i.carType && c.loaded)) {
return 'NO_SUITABLE_CAR';
}