Search code examples
clojure

Is this code idiomatic? Are there better or more concise ways to write this?


i'm trying to model a game of poker.

My game state representation is in a map, for this question i'm only interested in the players.

{:players {:1 {:money 200} :2 {money 400}}}

Every function takes in a game state and some other parameters and return a new game state, for example:

(defn update-player-money
  "Returns new game state where player has added amount to his money"
  [game-state player amount]
  (assoc-in game-state [:players player :money]
            (+ (-> game-state :players player :money)
               amount)))

Now i want a function that removes a certain amount of money from each player while passing down the new game state. To make it clear, something that for two players would do:

(update-player-money (update-player-money game-state :1 (- 20)) :2 (-20))

This is what i came up with:

(defn phase-1-blind
  "Removes blind from all players."
  [game-state blind-amount]
  (letfn [(blind-helper [game-state player-list amount]
            (if (seq player-list)
              (blind-helper (update-player-money game-state
                                                 (first player-list)
                                                 (- amount))
                            (rest player-list)
                            amount)
              game-state))]
  (blind-helper game-state (keys (:players game-state)) blind-amount)))

This works but i was wondering if there was a more idiomatic or concise way to achieve the same effect.


Solution

  • If you want to implement phase-1-blind using update-player-money, reduce is useful here:

    (defn update-player-money
      "Returns new game state where player has added amount to his money"
      [game player-id amt]
      (update-in game [:players player-id :money] (fnil + 0) amt))
    
    (defn phase-1-blind
      "Removes blind from all players."
      [game blind]
      (reduce #(update-player-money % %2 blind)
              game
              (keys (:players game))))
    

    In update-player-money, fnil makes sure things don't break, even if a player doesn't have the :money key in it.