Fork me on GitHub
#architecture
<
2023-03-06
>
Michael W19:03:14

I am writing a tic-tac-toe game as a toy to learn how to program in a more functional way. I have settled on a board that is a vector of 9 cells, 1 for each tile on the screen.

(def board [:empty :x :o :empty :empty :empty :empty :empty :x])
I think history for the game could be a vector of up to 9 vectors that show each move for a turn. Here is the history for the board shown above for the first three turns:
(def history [[1 :x][2 :o][8 :x]])
I am wondering if there are better ways to do this? For instance the history doesn't include time, so I am strictly relying on the index to provide the order of turns. Should I prefer maps for the history over vectors? Should I even add a time component or is that just added complexity for no gain? Any pointers to docs on modeling state? I'm exploring using a https://github.com/fulcrologic/statecharts to model the game, and that is working nicely. I'm curious how others would model this very simple game.

Rupert (All Street)20:03:33

You could model the state like this:

(def state
  (atom
    {:board [[:x     :empty :empty]
             [:empty :o     :empty]
             [:empty :empty :empty]]
     :turns [[:x 0 0]
             [:o 1 1]
             ...]
     :current-turn :x
     :status :in-progress ;;other states: :draw,:x-win,:o-win
 }))
• The :board can show the current state of the board and looks more like a real board compared to a one dimensional vector. • Board can be updated like this: ◦ (assoc-in state [:board 0 0] :x) • The amount of data you have is so small that you don't need to be conservative about memory - e.g. you could keep a copy of the whole board for every turn - rather than just the action from the user if that was helpful. > For instance the history doesn't include time, so I am strictly relying on the index to provide the order of turns. • Vectors and list will maintain their order (it's part of their API/Contract) so it can be relied upon. > Should I prefer maps for the history over vectors? • Choose the datastructure that feels most natural. I think for a list of action a sequence or vector feels more natural than a map. > Should I even add a time component or is that just added complexity for no gain? • You can certainly add time or any other data that you wish into your datastructures.

Michael W21:03:26

I left it flat because you can just (pprint (partition 3 board)) to get the same structure you have there. It also simplifies the application of the history to the board to just an index and keyword instead of a compound index like [0 0]. Is adding the compound index any benefit compared to the flatter structure? I like the :current-turn :x that simplifies the statechart quite a bit compared to how I have it working now. Also going to use the :x-win and :o-win. Thanks!

👍 4
Rupert (All Street)08:03:41

> Is adding the compound index any benefit compared to the flatter structure? Nope, there's no particular benefit - I just thought it made the datastructure more similar to the game and therefor easier to work with. However you should go with whatever datastructure you find easiest to reason about or use. You can always refactor code later.