简体   繁体   中英

Using assoc-in to permanently change a value in a map Clojure

sorry about the huge amount of questions.

I have a map of cards:

    (def cards
  {
    :card1 {:name "Wisp"              :type "Monster"     :damage 1   :health 1   :cost 0   :ability 0 :active true}
    :card2 {:name "Spider Tank"       :type "Monster"     :damage 3   :health 4   :cost 3   :ability 0 :active true}
    :card3 {:name "Boulder Fist Ogre" :type "Monster"     :damage 6   :health 7   :cost 6   :ability 0 :active true}
    :card4 {:name "Bloodfen Raptor"   :type "Monster"     :damage 3   :health 2   :cost 2   :ability 0 :active true}
    :card5 {:name "Chillwind Yeti"    :type "Monster"     :damage 4   :health 5   :cost 4   :ability 0 :active true}
    :card6 {:name "Magma Rager"       :type "Monster"     :damage 5   :health 1   :cost 3   :ability 0 :active true}
    :card7 {:name "War Golem"         :type "Monster"     :damage 7   :health 7   :cost 7   :ability 0 :active true}
    :card8 {:name "Oasis Snapjaw"     :type "Monster"     :damage 2   :health 7   :cost 4   :ability 0 :active true}
    :card9 {:name "River Crocolisk"   :type "Monster"     :damage 2   :health 3   :cost 2   :ability 0 :active true}
    :card10 {:name "Murloc Raider"    :type "Monster"     :damage 2   :health 1   :cost 1   :ability 0 :active true}
    :card11 {:name "Northshire Cleric":type "Monster"     :damage 1   :health 3   :cost 1   :ability 2 :active true}
    :card12 {:name "Nat Peagle"       :type "Monster"     :damage 0   :health 4   :cost 2   :ability 4 :active true}
    :card13 {:name "Molten Giant"     :type "Monster"     :damage 8   :health 8   :cost 20  :ability 0 :active true}
    }
 )

These cards are in a list that makes up my board:

(def board1 (list (:card3 cards) (:card4 cards) (:card11 cards) nil nil nil nil))

What I want to do is change the active flag on a card to false from true.

I know that I can do this to my cards collection directly by:

user=> (assoc-in (:card11 cards) [:active] false)
{:ability 2, :name "Northshire Cleric", :type "Monster", :damage 1, :active false, :health 3, :cost 1}

I'm trying to build a function which, when given a collection (the board) and a number (nth) card. Makes this card in this board be false permanently.

I've been trying with atoms but had no joy so far.

(test-function board1 1)

(defn test-function [coll number]
  (let [test (atom coll)]
    (swap! test assoc-in (get (nth @test number)) [:active] false)
    (println test)))

I'm wondering what I'm doing wrong and whether there is a cleaner way to do this without using atoms.

You need to declare your atom outside your let block. The way you have it, you are re-binding it each time. The atom is a good choice for stateful things, so declare your atom like so:

(def cards (atom
  {:card1 {:name "Wisp" :active true}
   :card2 {:name "Spider Tank" :active true}}))

Then you can write your function to swap in false like so:

(defn myfunc [coll number]
  (swap! coll assoc-in [(str :card number) :active] false ))

You don't want two different functions, one for setting to true and one for setting to false though. You should take this the next step and make it read the current boolean value, then assoc-in the opposite value. (Also notice, I kept the sample data sample very small). ;)

JT93

As per your comment, you want to do away with the atom and have a clean update approach.

If you can clarify what you mean by permanently with more information in your question. For example: Do you want to maintain the board state of cards throughout the lifetime of the execution? If so, you may need to use an atom although Clojure has a few different approaches in addition.

First, consider changing the definition of board1 to a vector and not a list. You can then do away with arcane logic and just use assoc-in with very little fanfare:

(def board1 [(:card3 cards) (:card4 cards) (:card11 cards) nil nil nil nil])

(defn test-function [coll number]
    (assoc-in coll [number :active] false))

(clojure.pprint/pprint (test-function board1 0))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM