Worked on my game loop today which I find challenging but incredibly rewarding once I had completed it.
I wanted to have an idea of where I wanted to get to, so I decided to spike my solution, which raised a couple of questions.
How do I effectiely recursed so a user can take multiple turns?, how do I switch the current player on each turn? how do pass a new state of the board if there's only immutable state to handle?

I spent an hour pairing with Jim, he showed me the best way to approach testing my game loop, while I didn't understand everything 100%, it was enough to get me moving forward.

I learnt that it's okay to keep state of the next board as long as it doesn't leave the scope of the function. Using let allows you to bind the result of a function, which you can then use later.
It really is about data flow. Letting the input into a function, which then outputs a result, which in turn could become an input in another function. Data flows through your systems, no dealing with side effects and side causes.

Below is my solution to the game loop

[code lang="clojure"]
(def a-empty-board ["-" "-" "-" "-" "-" "-" "-" "-" "-"])

(defn play-turn [board]
(let [next-state-board (board/make-move board (console/get-move-choice)
(board/current-player board))]
(console/print-board next-state-board)
(if (board/game-over? next-state-board)
(console/print-board next-state-board)
(recur next-state-board))))

(defn play-game []
(console/print-board a-empty-board)
(play-turn a-empty-board))