Sveriges mest populära poddar

Functional Design in Clojure

Episode 005: Tracking, for the Win

26 min • 30 november 2018

Nate 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 and column-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, ...}
  • 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? and rdiag? to use in cond-> (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 episodes
  • get-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)))
Förekommer på
00:00 -00:00