Wiki · variants-and-wild-market-climates

Variants and wild-market climates

Last edited by · ·

Variants and wild-market climates

Every variant runs the same vendored simulator. What differs is the configuration handed to it at episode creation.

VariantWhat changes
defaultThe Kaggle competition exactly: 30 days of 24 turns, 10×10 farm, default market.
short-seasonTen days. Fast feedback; slow crops never pay back.
wild-market-glutPremium goods (strawberry, melon, milk, wool) crash twice as hard on overproduction.
wild-market-scarcityStaples (wheat, carrot, tomato, egg, fertilizer) spike twice as hard when the town drains them.
wild-market-invertedCheap and premium curves swapped: wheat trades like melon, carrot like strawberry, egg like milk, and vice versa.
wild-market-randomEvery product's base price, target moves and curve shapes sampled per episode from the seed.

Why wild markets

Kaggriculture's price curves are fixed and documented in RULES.md, so a policy can carry the default price table as constants and never look at the market it is actually in. That works — the ladder's top bots do it — but it means the league selects for memorizing a table rather than for reading a market. A wild-market season changes the table. A bot that infers curve shapes from observed price movement, or reads the resolved parameters out of its observation, keeps working; a bot that hard-coded the defaults sells into floors it did not expect.

The climates are deliberately ordered from mild to hostile. glut and scarcity keep every crop's rank; only the punishment for over- or under-supplying changes. inverted reverses the crop economy, so the default plan (wheat for feed, melon for money) is backwards. random is different every episode.

How it works — configuration only

Upstream's simulator already accepts sparse per-resource marketParams overrides at episode creation (see "The Price Function" in RULES.md). A climate is nothing more than a specific override set:

{"marketClimate": "glut"}

resolves, before the simulator sees the config, to

{"marketParams": {
  "STRAWBERRY": {"above_target": 3.2}, "MELON": {"above_target": 7.2},
  "MILK": {"above_target": 3.2}, "WOOL": {"above_target": 6.4}}}

and upstream's own _resolve_market_params merges that onto its defaults. cogriculture/climates.py holds the sets; sim.sim_configuration does the resolution. No rule is reimplemented, the observation and action contract is unchanged, and a bot stays a plain Kaggle agent.

An explicit marketParams in the same config layers on top of the climate, per resource and per key, so a league can start from a climate and tweak it.

random and the seed

The random climate samples, for each product, a base price (×0.5–2.0 of the default, log-uniform), a target move on each side of equilibrium (×0.5–2.5), and with probability 0.3 per side a different curve shape from the family upstream's defaults use. I0 and T are never touched: T is a field's production capacity and I0 the equilibrium inventory, facts about the farm rather than the market.

Sampling is a pure function of the episode seed. If the config supplies a seed, that one is used; otherwise the game draws one and hands it to the simulator, which records it as info.seed in the replay. Either way a replay reproduces its market. The seed itself is scrubbed from the configuration before any agent sees it, as upstream does for every seed.

What bots can see

Two things are visible to a bot, in every climate:

  • the resolved marketParams, in the configuration passed as the agent's second argument (and in the handshake message);
  • market.params, which upstream adds to the market observation whenever overrides are in effect.

So a bot does not have to infer the curves blind: reading market.params is the intended adaptation. What a climate punishes is not looking — treating the rulebook table as the world. A bot that ignores both fields and infers shape from the price track is playing on hard mode by choice.

Running one locally

python tools/eval.py bots/baseline.py bots/starter.py --climate inverted --episodes 5
python tools/run_local_episode.py --steps 720 --climate random --seed 7

Adding a climate

Add an entry to NAMED_CLIMATES in cogriculture/climates.py, then rebuild the manifest (python tools/build_manifest.py): the config-schema enum and the wild-market-* variants are generated from climates.CLIMATES. tests/test_climates.py runs every climate through a real episode.