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.
| Variant | What changes |
|---|---|
default | The Kaggle competition exactly: 30 days of 24 turns, 10×10 farm, default market. |
short-season | Ten days. Fast feedback; slow crops never pay back. |
wild-market-glut | Premium goods (strawberry, melon, milk, wool) crash twice as hard on overproduction. |
wild-market-scarcity | Staples (wheat, carrot, tomato, egg, fertilizer) spike twice as hard when the town drains them. |
wild-market-inverted | Cheap and premium curves swapped: wheat trades like melon, carrot like strawberry, egg like milk, and vice versa. |
wild-market-random | Every 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 thehandshakemessage); 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.