<!-- canonical: https://efficientnewlanguage.org/eml-p/projects/P100-mastermind/ | updated: 2026-10-15 -->

# P100 Mastermind

Codes of 4 colours from 6, scored black and white by counting colours: play against a secret code with the codes still possible counted after each answer, watch the computer's rule solve any code, or see how one guess is scored.

EML-P project `projects/mastermind` in the EML language repo: 2 module(s), entry `main.eml`, terminal UI. There, `eml project run projects/mastermind` runs it and `eml project verify projects/mastermind` replays every session under CPython (two hash seeds) and in the interpreter; the site build replays every session in the interpreter again and publishes a session only if its screen matches.

Built on verified corpus cases: char-frequency-table (https://efficientnewlanguage.org/cases/157-char-frequency-table/).

## Sessions

### bad-input - interpreter: byte-equal to the golden

Input:

```text
0
x
1
x

1
0
123
12345
1237
abcd
1111
1111
1111
1111
1111
1111
1111
1111
1111
1111
2

2
777
2
random

3
12
1234
3

3
1234

4
```

Screen:

```text
== Mastermind ==
Codes of 4 colours, each 1 to 6: black for right colour, right place; white for right colour, wrong place.

1) play  2) watch the computer  3) score a guess  4) quit
choice> 0
Pick a number from 1 to 4.

1) play  2) watch the computer  3) score a guess  4) quit
choice> x
Pick a number from 1 to 4.

1) play  2) watch the computer  3) score a guess  4) quit
choice> 1
seed (0 to 999999)> x
Type a whole number from 0 to 999999.
seed (0 to 999999)> 
Cancelled.

1) play  2) watch the computer  3) score a guess  4) quit
choice> 1
seed (0 to 999999)> 0
I have picked a code: 4 colours, each 1 to 6, repeats allowed. You have 10 guesses.
guess 1 (4 colours 1 to 6, ? for a hint)> 123
Type 4 colours, each 1 to 6, like 1234.
guess 1 (4 colours 1 to 6, ? for a hint)> 12345
Type 4 colours, each 1 to 6, like 1234.
guess 1 (4 colours 1 to 6, ? for a hint)> 1237
Type 4 colours, each 1 to 6, like 1234.
guess 1 (4 colours 1 to 6, ? for a hint)> abcd
Type 4 colours, each 1 to 6, like 1234.
guess 1 (4 colours 1 to 6, ? for a hint)> 1111
0 black, 0 white. 625 codes still fit every answer.
guess 2 (4 colours 1 to 6, ? for a hint)> 1111
0 black, 0 white. 625 codes still fit every answer. (That guess could not have been the code: it did not fit an earlier answer.)
guess 3 (4 colours 1 to 6, ? for a hint)> 1111
0 black, 0 white. 625 codes still fit every answer. (That guess could not have been the code: it did not fit an earlier answer.)
guess 4 (4 colours 1 to 6, ? for a hint)> 1111
0 black, 0 white. 625 codes still fit every answer. (That guess could not have been the code: it did not fit an earlier answer.)
guess 5 (4 colours 1 to 6, ? for a hint)> 1111
0 black, 0 white. 625 codes still fit every answer. (That guess could not have been the code: it did not fit an earlier answer.)
guess 6 (4 colours 1 to 6, ? for a hint)> 1111
0 black, 0 white. 625 codes still fit every answer. (That guess could not have been the code: it did not fit an earlier answer.)
guess 7 (4 colours 1 to 6, ? for a hint)> 1111
0 black, 0 white. 625 codes still fit every answer. (That guess could not have been the code: it did not fit an earlier answer.)
guess 8 (4 colours 1 to 6, ? for a hint)> 1111
0 black, 0 white. 625 codes still fit every answer. (That guess could not have been the code: it did not fit an earlier answer.)
guess 9 (4 colours 1 to 6, ? for a hint)> 1111
0 black, 0 white. 625 codes still fit every answer. (That guess could not have been the code: it did not fit an earlier answer.)
guess 10 (4 colours 1 to 6, ? for a hint)> 1111
0 black, 0 white. 625 codes still fit every answer. (That guess could not have been the code: it did not fit an earlier answer.)
No guesses left. The code was 3536.

1) play  2) watch the computer  3) score a guess  4) quit
choice> 2
your code (4 colours 1 to 6), or random> 
Cancelled.

1) play  2) watch the computer  3) score a guess  4) quit
choice> 2
your code (4 colours 1 to 6), or random> 777
Type 4 colours, each 1 to 6, like 1234, or random.

1) play  2) watch the computer  3) score a guess  4) quit
choice> 2
your code (4 colours 1 to 6), or random> random
seed (0 to 999999)> 
Cancelled.

1) play  2) watch the computer  3) score a guess  4) quit
choice> 3
guess (4 colours 1 to 6)> 12
code (4 colours 1 to 6)> 1234
Type 4 colours, each 1 to 6, like 1234.

1) play  2) watch the computer  3) score a guess  4) quit
choice> 3
guess (4 colours 1 to 6)> 
Cancelled.

1) play  2) watch the computer  3) score a guess  4) quit
choice> 3
guess (4 colours 1 to 6)> 1234
code (4 colours 1 to 6)> 
Cancelled.

1) play  2) watch the computer  3) score a guess  4) quit
choice> 4
Bye.
```

### basic - interpreter: byte-equal to the golden

Input:

```text
1
7
1122
3344
?
1311
?
1511
1
42
1234
5566

2
3456
2
random
7
2
6543
3
1234
1325
3
1122
2211
3
6666
6616
4
```

Screen:

```text
== Mastermind ==
Codes of 4 colours, each 1 to 6: black for right colour, right place; white for right colour, wrong place.

1) play  2) watch the computer  3) score a guess  4) quit
choice> 1
seed (0 to 999999)> 7
I have picked a code: 4 colours, each 1 to 6, repeats allowed. You have 10 guesses.
guess 1 (4 colours 1 to 6, ? for a hint)> 1122
1 black, 1 white. 208 codes still fit every answer.
guess 2 (4 colours 1 to 6, ? for a hint)> 3344
0 black, 0 white. 56 codes still fit every answer. (That guess could not have been the code: it did not fit an earlier answer.)
guess 3 (4 colours 1 to 6, ? for a hint)> ?
A code that fits every answer so far: 1255.
guess 3 (4 colours 1 to 6, ? for a hint)> 1311
3 black, 0 white. 2 codes still fit every answer. (That guess could not have been the code: it did not fit an earlier answer.)
guess 4 (4 colours 1 to 6, ? for a hint)> ?
A code that fits every answer so far: 1511.
guess 4 (4 colours 1 to 6, ? for a hint)> 1511
4 black: that is the code, in 4 guesses.

1) play  2) watch the computer  3) score a guess  4) quit
choice> 1
seed (0 to 999999)> 42
I have picked a code: 4 colours, each 1 to 6, repeats allowed. You have 10 guesses.
guess 1 (4 colours 1 to 6, ? for a hint)> 1234
1 black, 2 white. 132 codes still fit every answer.
guess 2 (4 colours 1 to 6, ? for a hint)> 5566
1 black, 0 white. 36 codes still fit every answer. (That guess could not have been the code: it did not fit an earlier answer.)
guess 3 (4 colours 1 to 6, ? for a hint)> 
You stopped. The code was 2436.

1) play  2) watch the computer  3) score a guess  4) quit
choice> 2
your code (4 colours 1 to 6), or random> 3456
The rule: guess 1122, then the first code, in order, that fits every answer so far.
  guess  code  answer             codes left
      1  1122  0 black, 0 white          256
      2  3333  1 black, 0 white          108
      3  3444  2 black, 0 white           12
      4  3455  3 black, 0 white            2
      5  3456  4 black, 0 white            1
Solved in 5 guesses. Over all 1,296 codes this rule never needs more than 8: 6,508 guesses in all, 5.02 a code.

1) play  2) watch the computer  3) score a guess  4) quit
choice> 2
your code (4 colours 1 to 6), or random> random
seed (0 to 999999)> 7
The code is 1511.
The rule: guess 1122, then the first code, in order, that fits every answer so far.
  guess  code  answer             codes left
      1  1122  1 black, 1 white          208
      2  1233  1 black, 0 white           45
      3  1411  3 black, 0 white            8
      4  1414  2 black, 0 white            2
      5  1511  4 black, 0 white            1
Solved in 5 guesses. Over all 1,296 codes this rule never needs more than 8: 6,508 guesses in all, 5.02 a code.

1) play  2) watch the computer  3) score a guess  4) quit
choice> 2
your code (4 colours 1 to 6), or random> 6543
The rule: guess 1122, then the first code, in order, that fits every answer so far.
  guess  code  answer             codes left
      1  1122  0 black, 0 white          256
      2  3333  1 black, 0 white          108
      3  3444  1 black, 1 white           24
      4  5345  1 black, 2 white            6
      5  5436  0 black, 4 white            2
      6  6354  1 black, 3 white            1
      7  6543  4 black, 0 white            1
Solved in 7 guesses. Over all 1,296 codes this rule never needs more than 8: 6,508 guesses in all, 5.02 a code.

1) play  2) watch the computer  3) score a guess  4) quit
choice> 3
guess (4 colours 1 to 6)> 1234
code (4 colours 1 to 6)> 1325
  colour  in guess  in code  in both
       1         1        1        1
       2         1        1        1
       3         1        1        1
       4         1        0        0
       5         0        1        0
Colours in both: 3. Right colour in the right place: 1 black. The rest, 3 - 1: 2 white.

1) play  2) watch the computer  3) score a guess  4) quit
choice> 3
guess (4 colours 1 to 6)> 1122
code (4 colours 1 to 6)> 2211
  colour  in guess  in code  in both
       1         2        2        2
       2         2        2        2
Colours in both: 4. Right colour in the right place: 0 black. The rest, 4 - 0: 4 white.

1) play  2) watch the computer  3) score a guess  4) quit
choice> 3
guess (4 colours 1 to 6)> 6666
code (4 colours 1 to 6)> 6616
  colour  in guess  in code  in both
       1         0        1        0
       6         4        3        3
Colours in both: 3. Right colour in the right place: 3 black. The rest, 3 - 3: 0 white.

1) play  2) watch the computer  3) score a guess  4) quit
choice> 4
Bye.
```

## Modules

### main.eml

```eml
# P100 Mastermind: guess the computer's code, watch the computer guess
# yours, or see how one guess is scored.
import pegs

def plain(s):
    0 => i
    len(s) => j
    while i < j and s[i] == " ":
        i + 1 => i
    while j > i and s[j - 1] == " ":
        j - 1 => j
    return s[i:j]

def number(s, most):
    if len(s) == 0 or len(s) > most:
        return -1
    0 => n
    for c in s:
        if not (c >= "0" and c <= "9"):
            return -1
        n * 10 + int(c) => n
    return n

def lpad(s, n):
    while len(s) < n:
        " " + s => s
    return s

def answer(r):
    return str(r[0]) + " black, " + str(r[1]) + " white"

def still(n):
    if n == 1:
        return "1 code still fits every answer."
    return str(n) + " codes still fit every answer."

def ask_seed():
    while True:
        plain(input("seed (0 to 999999)> ")) => a
        if a == "":
            return -1
        number(a, 6) => n
        if n >= 0:
            return n
        "Type a whole number from 0 to 999999." ^0

def play():
    ask_seed() => seed
    if seed == -1:
        "Cancelled." ^0
        return
    pegs.secret(seed) => code
    "I have picked a code: 4 colours, each 1 to 6, repeats allowed. You have 10 guesses." ^0
    pegs.all_codes() => left
    1 => turn
    while turn <= 10:
        plain(input("guess " + str(turn) + " (4 colours 1 to 6, ? for a hint)> ")) => g
        if g == "":
            ("You stopped. The code was " + code + ".") ^0
            return
        if g == "?":
            ("A code that fits every answer so far: " + left[0] + ".") ^0
        elif not pegs.valid(g):
            "Type 4 colours, each 1 to 6, like 1234." ^0
        else:
            pegs.score(g, code) => r
            False => fitted
            for c in left:
                if c == g:
                    True => fitted
            pegs.fits(left, g, r) => left
            if r[0] == 4:
                ("4 black: that is the code, in " + str(turn) + " guesses.") ^0
                return
            if fitted:
                (answer(r) + ". " + still(len(left))) ^0
            else:
                (answer(r) + ". " + still(len(left)) + " (That guess could not have been the code: it did not fit an earlier answer.)") ^0
            turn + 1 => turn
    ("No guesses left. The code was " + code + ".") ^0

def watch():
    plain(input("your code (4 colours 1 to 6), or random> ")) => s
    if s == "":
        "Cancelled." ^0
        return
    if s == "random":
        ask_seed() => seed
        if seed == -1:
            "Cancelled." ^0
            return
        pegs.secret(seed) => s
        ("The code is " + s + ".") ^0
    elif not pegs.valid(s):
        "Type 4 colours, each 1 to 6, like 1234, or random." ^0
        return
    "The rule: guess 1122, then the first code, in order, that fits every answer so far." ^0
    "  guess  code  answer             codes left" ^0
    pegs.solve(s) => rows
    for k in [0:len(rows) - 1]:
        rows[k] => row
        ("  " + lpad(str(k + 1), 5) + "  " + row[0] + "  " + answer(row[1]) + lpad(str(row[2]), 13)) ^0
    ("Solved in " + str(len(rows)) + " guesses. Over all 1,296 codes this rule never needs more than 8: 6,508 guesses in all, 5.02 a code.") ^0

def score_two():
    plain(input("guess (4 colours 1 to 6)> ")) => g
    if g == "":
        "Cancelled." ^0
        return
    plain(input("code (4 colours 1 to 6)> ")) => c
    if c == "":
        "Cancelled." ^0
        return
    if not pegs.valid(g) or not pegs.valid(c):
        "Type 4 colours, each 1 to 6, like 1234." ^0
        return
    pegs.counts(g) => cg
    pegs.counts(c) => cc
    "  colour  in guess  in code  in both" ^0
    0 => both
    for k in ["1", "2", "3", "4", "5", "6"]:
        0 => a
        0 => b
        if k in cg:
            cg[k] => a
        if k in cc:
            cc[k] => b
        if a > 0 or b > 0:
            a => m
            if b < a:
                b => m
            both + m => both
            ("  " + lpad(k, 6) + lpad(str(a), 10) + lpad(str(b), 9) + lpad(str(m), 9)) ^0
    pegs.score(g, c) => r
    ("Colours in both: " + str(both) + ". Right colour in the right place: " + str(r[0]) + " black. The rest, " + str(both) + " - " + str(r[0]) + ": " + str(r[1]) + " white.") ^0

"== Mastermind ==" ^0
"Codes of 4 colours, each 1 to 6: black for right colour, right place; white for right colour, wrong place." ^0
True => running
while running:
    "" ^0
    "1) play  2) watch the computer  3) score a guess  4) quit" ^0
    plain(input("choice> ")) => choice
    if choice == "1":
        play()
    elif choice == "2":
        watch()
    elif choice == "3":
        score_two()
    elif choice == "4":
        False => running
    else:
        "Pick a number from 1 to 4." ^0
"Bye." ^0
```

Python projection of main.eml:

```python
import pegs

def plain(s):
    i = 0
    j = len(s)
    while i < j and s[i] == " ":
        i = i + 1
    while j > i and s[j - 1] == " ":
        j = j - 1
    return s[i:j]

def number(s, most):
    if len(s) == 0 or len(s) > most:
        return -1
    n = 0
    for c in s:
        if not (c >= "0" and c <= "9"):
            return -1
        n = n * 10 + int(c)
    return n

def lpad(s, n):
    while len(s) < n:
        s = " " + s
    return s

def answer(r):
    return str(r[0]) + " black, " + str(r[1]) + " white"

def still(n):
    if n == 1:
        return "1 code still fits every answer."
    return str(n) + " codes still fit every answer."

def ask_seed():
    while True:
        a = plain(input("seed (0 to 999999)> "))
        if a == "":
            return -1
        n = number(a, 6)
        if n >= 0:
            return n
        print("Type a whole number from 0 to 999999.")

def play():
    seed = ask_seed()
    if seed == -1:
        print("Cancelled.")
        return
    code = pegs.secret(seed)
    print("I have picked a code: 4 colours, each 1 to 6, repeats allowed. You have 10 guesses.")
    left = pegs.all_codes()
    turn = 1
    while turn <= 10:
        g = plain(input("guess " + str(turn) + " (4 colours 1 to 6, ? for a hint)> "))
        if g == "":
            print("You stopped. The code was " + code + ".")
            return
        if g == "?":
            print("A code that fits every answer so far: " + left[0] + ".")
        elif not pegs.valid(g):
            print("Type 4 colours, each 1 to 6, like 1234.")
        else:
            r = pegs.score(g, code)
            fitted = False
            for c in left:
                if c == g:
                    fitted = True
            left = pegs.fits(left, g, r)
            if r[0] == 4:
                print("4 black: that is the code, in " + str(turn) + " guesses.")
                return
            if fitted:
                print(answer(r) + ". " + still(len(left)))
            else:
                print(answer(r) + ". " + still(len(left)) + " (That guess could not have been the code: it did not fit an earlier answer.)")
            turn = turn + 1
    print("No guesses left. The code was " + code + ".")

def watch():
    s = plain(input("your code (4 colours 1 to 6), or random> "))
    if s == "":
        print("Cancelled.")
        return
    if s == "random":
        seed = ask_seed()
        if seed == -1:
            print("Cancelled.")
            return
        s = pegs.secret(seed)
        print("The code is " + s + ".")
    elif not pegs.valid(s):
        print("Type 4 colours, each 1 to 6, like 1234, or random.")
        return
    print("The rule: guess 1122, then the first code, in order, that fits every answer so far.")
    print("  guess  code  answer             codes left")
    rows = pegs.solve(s)
    for k in range(0, len(rows)):
        row = rows[k]
        print("  " + lpad(str(k + 1), 5) + "  " + row[0] + "  " + answer(row[1]) + lpad(str(row[2]), 13))
    print("Solved in " + str(len(rows)) + " guesses. Over all 1,296 codes this rule never needs more than 8: 6,508 guesses in all, 5.02 a code.")

def score_two():
    g = plain(input("guess (4 colours 1 to 6)> "))
    if g == "":
        print("Cancelled.")
        return
    c = plain(input("code (4 colours 1 to 6)> "))
    if c == "":
        print("Cancelled.")
        return
    if not pegs.valid(g) or not pegs.valid(c):
        print("Type 4 colours, each 1 to 6, like 1234.")
        return
    cg = pegs.counts(g)
    cc = pegs.counts(c)
    print("  colour  in guess  in code  in both")
    both = 0
    for k in ["1", "2", "3", "4", "5", "6"]:
        a = 0
        b = 0
        if k in cg:
            a = cg[k]
        if k in cc:
            b = cc[k]
        if a > 0 or b > 0:
            m = a
            if b < a:
                m = b
            both = both + m
            print("  " + lpad(k, 6) + lpad(str(a), 10) + lpad(str(b), 9) + lpad(str(m), 9))
    r = pegs.score(g, c)
    print("Colours in both: " + str(both) + ". Right colour in the right place: " + str(r[0]) + " black. The rest, " + str(both) + " - " + str(r[0]) + ": " + str(r[1]) + " white.")

print("== Mastermind ==")
print("Codes of 4 colours, each 1 to 6: black for right colour, right place; white for right colour, wrong place.")
running = True
while running:
    print("")
    print("1) play  2) watch the computer  3) score a guess  4) quit")
    choice = plain(input("choice> "))
    if choice == "1":
        play()
    elif choice == "2":
        watch()
    elif choice == "3":
        score_two()
    elif choice == "4":
        running = False
    else:
        print("Pick a number from 1 to 4.")
print("Bye.")
```

### pegs.eml

```eml
# P100 Mastermind - codes of 4 colours, 1 to 6, repeats allowed: 1,296 of
# them. A guess is answered with black (right colour, right place) and
# white (right colour, wrong place), counted colour by colour with a dict
# as in the corpus case char-frequency-table. The computer's rule: guess
# 1122, then the first code, in order, that fits every answer so far.

def all_codes():
    [] => out
    for a in [1:6]:
        for b in [1:6]:
            for c in [1:6]:
                for d in [1:6]:
                    out + [str(a) + str(b) + str(c) + str(d)] => out
    return out

def valid(s):
    if len(s) != 4:
        return False
    for c in s:
        if not (c >= "1" and c <= "6"):
            return False
    return True

def counts(s):
    {} => out
    for c in s:
        if c in out:
            out[c] + 1 => out[c]
        else:
            1 => out[c]
    return out

def score(guess, code):
    # [black, white]: black counts the places that match; every colour
    # matches as often as it is in both, the fewer of the two counts, and
    # white is what that leaves beyond black.
    0 => black
    for i in [0:3]:
        if guess[i] == code[i]:
            black + 1 => black
    counts(guess) => g
    counts(code) => k
    0 => both
    for c in g:
        if c in k:
            if g[c] < k[c]:
                both + g[c] => both
            else:
                both + k[c] => both
    return [black, both - black]

def fits(codes, guess, answer):
    # the codes that would have given this answer to this guess
    [] => out
    for c in codes:
        score(guess, c) => r
        if r[0] == answer[0] and r[1] == answer[1]:
            out + [c] => out
    return out

def solve(code):
    # [[guess, answer, codes still fitting], ...] until 4 black
    all_codes() => left
    "1122" => guess
    [] => out
    True => going
    while going:
        score(guess, code) => r
        fits(left, guess, r) => left
        out + [[guess, r, len(left)]] => out
        if r[0] == 4:
            False => going
        else:
            left[0] => guess
    return out

def secret(seed):
    # 4 colours from a linear congruential generator, top 16 bits
    seed => x
    "" => out
    for i in [1:4]:
        (1664525 * x + 1013904223) % 4294967296 => x
        # x is below 2 ** 32, so the division is exact
        out + str(int((x - x % 65536) / 65536) % 6 + 1) => out
    return out
```

Python projection of pegs.eml:

```python
def all_codes():
    out = []
    for a in range(1, 7):
        for b in range(1, 7):
            for c in range(1, 7):
                for d in range(1, 7):
                    out = out + [str(a) + str(b) + str(c) + str(d)]
    return out

def valid(s):
    if len(s) != 4:
        return False
    for c in s:
        if not (c >= "1" and c <= "6"):
            return False
    return True

def counts(s):
    out = {}
    for c in s:
        if c in out:
            out[c] = out[c] + 1
        else:
            out[c] = 1
    return out

def score(guess, code):
    black = 0
    for i in range(0, 4):
        if guess[i] == code[i]:
            black = black + 1
    g = counts(guess)
    k = counts(code)
    both = 0
    for c in g:
        if c in k:
            if g[c] < k[c]:
                both = both + g[c]
            else:
                both = both + k[c]
    return [black, both - black]

def fits(codes, guess, answer):
    out = []
    for c in codes:
        r = score(guess, c)
        if r[0] == answer[0] and r[1] == answer[1]:
            out = out + [c]
    return out

def solve(code):
    left = all_codes()
    guess = "1122"
    out = []
    going = True
    while going:
        r = score(guess, code)
        left = fits(left, guess, r)
        out = out + [[guess, r, len(left)]]
        if r[0] == 4:
            going = False
        else:
            guess = left[0]
    return out

def secret(seed):
    x = seed
    out = ""
    for i in range(1, 5):
        x = (1664525 * x + 1013904223) % 4294967296
        out = out + str(int((x - x % 65536) / 65536) % 6 + 1)
    return out
```

## README

# P100 - Mastermind

Codes of 4 colours, each from 1 to 6, repeats allowed: 1,296 of them.
You can guess the computer's code, watch the computer guess yours, or see
how one guess is scored.

- `main.eml` - the menu, playing, watching and scoring
- `pegs.eml` - every code, scoring, the codes that fit an answer, the
  computer's rule and the secret code

How each part works:

- A guess is answered with black (the right colour in the right place)
  and white (the right colour in the wrong place). Colours are counted
  with a dict, as in the corpus case `char-frequency-table`. Each colour
  is in both codes as often as the smaller of its two counts. The total
  of those, minus black, is white.
- After each answer, the codes still possible are the ones that would
  have given the same answer to the same guess. The program counts them
  and can give one as a hint. It also says when a guess could not have
  been the code.
- The computer's rule: guess 1122, then the first code, in order, that
  fits every answer so far. Over all 1,296 codes it never needs more than
  8 guesses: 6,508 in all, 5.02 a code.
- The secret code comes from a seed, through a linear congruential
  generator.

What is checked: menu choices 1 to 4; a seed from 0 to 999999; codes of
4 colours, each from 1 to 6. An empty answer cancels. While playing, it
stops the game and shows the code.

Sessions: `sessions/basic.in` gives:
- a game (seed 7): two guesses that could not have been the code, two
  hints, and the code found in 4 guesses;
- a game given up after two guesses (seed 42);
- the computer solving 3456 and 1511 in 5 guesses, and 6543 in 7;
- three scores: 1234 against 1325, 1122 against 2211, and 6666 against
  6616.

`sessions/bad-input.in` gives:
- menu choices 0 and x; the seed x, then a cancel;
- the guesses 123, 12345, 1237 and abcd; then 1111 ten times, until no
  guesses are left;
- a cancel, 777, and a random code whose seed is cancelled;
- scores with 12, and two cancels.

Built on the verified corpus case `char-frequency-table` (counting with
a dict, one character at a time).
