Ok, I will not provide you with complete code, but better with high-level design with regards to functional programming and in particular looping/recursion in Clojure.
Let's start with a very important concept in functional programming - immutability. Functional programs try to avoid any change of state of the system. Rather than changing the state, programs are to produce new state. For example, if you have vector v1 = [1, 2, 3, 4]
and want to insert 5 at the end of it, you don't destroy v1
, but rather produce v2 = [1, 2, 3, 4, 5]
(v1
stays in the memory unchanged). See this question for more details on immutability in functional programming.
Having this, the best way to go is to create special variable state
, that will hold overall state of the game.
Next thing to consider is looping. Again, in functional programming loop concept is almost replaced with recursion. Loops and recursion are very often similar - both allow you to repeat some code many times before it terminates. In most imperative programming languages (e.g. Python, Java) recursion leads to stack growth, but in functional languages there's very popular conception of tail recursion. If you are not familiar with this concept, I highly recommend you learning it. For now I only say, that tail recursion can occur only at tail position (last statement in control flow) and it doesn't lead to stack growth and thus may be used as loop construct.
In Clojure tail recursion is organized with recur
keyword:
(defn play [state ...]
...
(recur new-state ...))
Here, we define play
function with parameter state
and call it recursively with keyword recur
at the last line (we can call it as (play new-state ...)
too, but in this case JVM won't optimize code to be tail recursive). new-state
is defined somewhere in the function body and stands exactly for what it means - new state of a game.
Finally, you want to make your game multiplayer, that is, change current player after each iteration. With loop/recursion it may be easily achieved just by interchanging players:
(defn play [state current-player next-player]
;; do play with current-player and compute new-state
(recur new-state next-player current-player))
Notice, that in recur call players interchanged their positions, and thus next player became current player and vice versa in the new call of play
.
Having this, you should be able to translate your code to a new version.