Tic-tac-toe, one network

You play X. The computer plays O, and it never loses.

You always start.
Your moveYour turnThe network winsYou win?!Draw

No rule is written in the CSS: the network decides everything, including when the game is over.

How it works (for the curious)

The player, layer by layer

1,243 units and 5,434 nonzero weights. The trained layers come first; everything after the logits was written by hand. Each layer only reads the one before, so values needed later pass down through carry units, max(0, x) = x.

layer 1
83
layer 2
389
layer 3
515
layer 4
227
layer 5
20
layer 6
9
output
9
learnedhand-writtencarry (passes a value down a layer)

How a rule becomes weights

RuleAs ReLU
x ≥ t, for an integer xrelu(x − t + 1) − relu(x − t)
a AND b AND crelu(a + b + c − 2)
a OR b OR …s − relu(s − 1), with s = a + b + …
a line of three Xrelu(x₀ + x₁ + x₂ − 2)
square c is the best free onerelu(1 − Σ_d beats(d, c)), where d beats c if it is free and c isn't, or both are and d's score is higher
O moves only if you moved, didn't win, and the board isn't fullrelu(best_c + moved − x_won − full − 1)
Checked in numpy on all 5,478 reachable boards: the network's move equals the original demo's integer model on all 2,097 positions where O is to move, and the judge net's winner, draw and free squares are right on every board. The browser test replays the original fixture games in Chromium, Firefox and WebKit. Built by handwired/scripts/rules.py and build_games.py.