Reputation: 511
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.
Upvotes: 0
Views: 175
Reputation: 8096
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))
Upvotes: 2
Reputation: 6088
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). ;)
Upvotes: 2