Episode 005: Tracking, for the Win
► Play EpisodeNate tries to figure out who actually won this never-ending game of tic-tac-toe.
- Tic-tac-toe is "just boring enough, just interesting enough."
- How do we know who won the game? Inspect the board.
- If you can track progress toward the win, you check for the win quickly
- "Tic-tac-toe at scale!"
- Tracer bullet: go simple, just examine the 8 options for winning
- "In that case,
nil
has won...which is nobody." - Keep detection logic out of the high-level
winner
function--should read like a process description of steps. - Make new "verbs" like
row-winner
andcolumn-winner
and use those. - "You're just adding new verbs to raise Clojure up to the level of your problem. You can speak about your problem using those verbs."
- Let's make it faster! Need incremental detection to be efficient.
- Tracking structure with win condition totals
- keys like:
[
player case index]
- value is a counter for that case
- eg.
{ [:x :row 0] 1, [:y :row 0] 0, [:x :diag] 2, ...}
- keys like:
- The win tracker is a "nested model" of the game state
- Put the tracker it its own namespace
app.game.tracker
- Use
[:x 1 0]
as the play - Nested updates:
(update game-state :tracking tracker/update [:x 1 0])
- How do we handle diagonals? Not all moves will increment those totals.
- Make helpers for
diag?
andrdiag?
to use incond->
(see code below) - High-level functions describe the process. Low-level functions describe the steps.
- "You can see the animal, not the intestines."
- "If you see a word that's a higher level concept, it allows you to stay at that higher level and be able to view the algorithm instead of viewing the implementation. That's the point of lifting up all these little functions."
- Bonus: the tracker tells us all the ways a player won.
Clojure in this episode:
nil
punning streak: 3 episodesget-in
update
,update-in
or
short circuits,=
does not->
,cond->
,some->
frequencies
- lists as "tuples" and "triples"
Code sample from this episode:
(ns app.game.tracker)
(defn update
[tracking [player row column]]
(cond-> tracking
true (record row column player)
(diag? row column) (record-diag player)
(rdiag? row column) (record-rdiag player)))