import InfoBox from '../components/InfoBox.astro';
import Figure from '../components/Figure.astro';

The four letters that steer the snake used to be the same every day. English turned on u, d, l and r, Norwegian on o, n, v and h, and those letters applied in every mode. Words built around them became the good words, so players learned a stock of turn words that worked forever. Each day now draws a new set of four for each language, and every game plays on the set of the day it started.

## One set for a day and a language

Every day, each language gets a random set of four direction letters, and each letter in the set gets a random direction. The author set the rules: the set changes daily, every mode plays on it, and it never moves under a player mid-game. The agent wrote the draw, the pool and the migration against those rules.

The draw runs on its own random stream, separate from the one that places fruit, so fruit for every existing day is unchanged. Once a day's set is drawn, it is saved on that day's challenge record, so a later change to the pool cannot redraw a day that players have already seen.

<Figure caption="Each day's seed drives two separate draws. Fruit placement is unchanged, and the letter draw is saved on the day's challenge record, so every game started that day copies the same set.">

```mermaid
flowchart LR
  accTitle: How a day's direction letters reach each game
  accDescr: The day seed drives two separate draws. Fruit placement is unchanged. The direction-letter draw is saved on the daily challenge record, and each game created that day copies the set when it starts.
  seed[Day seed] --> fruit[Fruit placement]
  seed --> draw[Direction-letter draw]
  draw --> record[Saved on the daily challenge record]
  record --> daily[Daily Challenge]
  record --> duel[AI duel and friend duel created that day]
```

</Figure>

## Drawn from a pool, not from the alphabet

A uniform draw over the alphabet would sometimes produce a set nobody could play with. Letters like q, x and z almost never turn up in a word, so they steer very few words, while e sits in nearly every word, so turning on it forces a turn at almost every step. Deciding which letters are too rare or too common to steer with is the question the [earlier post on letter rarity](/posts/letter-rarity-scoring#what-rarity-was-supposed-to-mean) had to answer, and the pool leaves out letters at both ends of that scale. The draw takes its letters from that pool, and the direction assigned to each letter is random as well, so no set hints at a shape that suits one language better than another.

Measured on the branch, the pool holds a large number of distinct sets for each language:

```text
pool, English     1,580 sets   19 eligible letters
pool, Norwegian   1,634 sets   19 eligible letters
```

## A game keeps the letters it started with

An AI duel or a friend duel takes the set of its creator's day when it is created, and keeps that set for its whole life. A daily attempt that starts before midnight and finishes after it plays on yesterday's letters, and a friend-duel guest adopts the host's set. The rule is simple: the letters never change under a player, and "today's letters" means the letters of the day's challenge, not whatever the clock says at the moment of a keystroke.

<InfoBox title="The migration is one-way" variant="warning">

Every existing challenge and game was backfilled with the old default letters, so saved games still replay on the letters they were played on. Drawn letters start with the first challenge created after the deploy. Older code cannot represent a drawn set, so a rollback would have to be a forward fix, not a revert.

</InfoBox>

## Telling players without nagging them

Players learn the day's letters from a card on the main menu, and from one dialog on the first game of the day, whichever mode that game is in. The dialog appears once per day, so it does not interrupt every game after that. On the board, the coloured edges of the keyboard show each letter's direction, and a short ripple on those keys draws the eye whenever a board appears. With reduced motion turned on, the ripple becomes a fade. Screen-reader users hear the set as a plain sentence, one clause per letter, on both the menu card and the dialog.

## What the test runs had to change

End-to-end tests run on a fresh database, so every run draws its own set. A test that typed a fixed list of u, d, l and r words would fail on most days. The tests now read the set the test server actually served and pick words that steer safely under it. Previews and the end-to-end database also seed a generated list of 5,000 words per language, so they play on a realistic vocabulary.

Each piece of the work landed through its own pull request into a feature branch, and the author checked each one by hand before it merged. The same stretch of history also holds a small test assertion fix and several dependency updates. Neither is part of this story.

The stats page now breaks results down by set, so whether some sets play harder in practice than the pool's rules predict can be checked against real games.