Let the player pick the opposition: today src/client/bots.ts:113 derives every bot's skill from its id (0.25 + ((id * 37) % 100) / 130), so a first-timer and someone who has played CS for years get exactly the same five opponents and neither can do anything about it.
Done looks like:
[ ] A Difficulty select in the menu beside Side — three settings — each one a band of skills rather than a single number, so a team still runs from fodder to uncomfortable and the ladder the README describes survives.
[ ] The band is an argument that travels: createWorld takes it and hands it to makeBrain; bots.ts goes on deciding what a skill means and no other module learns the word "difficulty".
[ ] It persists in src/client/settings.ts beside mute, volume and sensitivity, and is validated at the same boundary — a missing, malformed or unknown value in storage falls back to the default and never reaches the game as undefined or NaN.
[ ] Changeable mid-match from the pause overlay, taking effect from the next round, with the overlay saying so — the person being crushed should not have to lose the match to fix it.
[ ] The scoreboard shows which difficulty is being played, so a screenshot of a scoreline means something.
[ ] Tests: parseSettings for a missing, garbage and out-of-range difficulty; the band mapping (easy hands are strictly slower and shakier than hard ones); createWorld at each setting producing brains whose skill lies inside the band; and the mid-match change applying at the next startRound and not before.
[ ] bun test green, README's Playing and The bots sections say what the settings mean.
Not in this issue: anything in the request payload, src/result.ts, src/db.ts or the leaderboard — issue #34 is changing that boundary and this must not collide with it. The difficulty stays client-side for now, and the standings stay exactly as they are.
Files I expect to change:src/client/settings.ts, bots.ts, world.ts, main.ts, hud.ts, src/pages/game.ts, README.md, and the tests beside each.
Risks:createWorld's signature is used by src/rl/arena.ts and by a good many tests — add the argument last with a default so every existing call keeps meaning what it means today. Do not touch policy.ts or the weights: skill is a handicap on the hands, and bots.test.ts has a test that says so. Bots made mid-match must not lose their path or their plan when their brain is rebuilt.
Crew: scout — one small knob, one file of state, wired end to end.
Let the player pick the opposition: today
src/client/bots.ts:113derives every bot's skill from its id (0.25 + ((id * 37) % 100) / 130), so a first-timer and someone who has played CS for years get exactly the same five opponents and neither can do anything about it.Done looks like:
createWorldtakes it and hands it tomakeBrain;bots.tsgoes on deciding what a skill means and no other module learns the word "difficulty".src/client/settings.tsbeside mute, volume and sensitivity, and is validated at the same boundary — a missing, malformed or unknown value in storage falls back to the default and never reaches the game asundefinedorNaN.parseSettingsfor a missing, garbage and out-of-range difficulty; the band mapping (easy hands are strictly slower and shakier than hard ones);createWorldat each setting producing brains whoseskilllies inside the band; and the mid-match change applying at the nextstartRoundand not before.bun testgreen, README's Playing and The bots sections say what the settings mean.Not in this issue: anything in the request payload,
src/result.ts,src/db.tsor the leaderboard — issue #34 is changing that boundary and this must not collide with it. The difficulty stays client-side for now, and the standings stay exactly as they are.Files I expect to change:
src/client/settings.ts,bots.ts,world.ts,main.ts,hud.ts,src/pages/game.ts,README.md, and the tests beside each.Risks:
createWorld's signature is used bysrc/rl/arena.tsand by a good many tests — add the argument last with a default so every existing call keeps meaning what it means today. Do not touchpolicy.tsor the weights: skill is a handicap on the hands, andbots.test.tshas a test that says so. Bots made mid-match must not lose their path or their plan when their brain is rebuilt.Crew: scout — one small knob, one file of state, wired end to end.