HiveBrain v1.2.0
Get Started
← Back to all entries
snippetMinor

Generate a deck of cards in Clojure / Clojurescript

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
clojurecardsdeckgenerateclojurescript

Problem

I would like to generate a deck of cards:

{:card-id 1 :suit :spade :rank 1}
{:card-id 2 :suit :spade :rank 2}
...
{:card-id 52 :suit :club :rank 13}


And here is my attempt:

(defn new-deck []
  (let [cards (flatten
                 (for [suit [:spade :heart :diamond :club]]
                    (for [rank [1 2 3 4 5 6 7 8 9 10 11 12 13]]
                      {:suit suit :rank rank} )))]
     (map-indexed (fn [idx itm] {:card-id (inc idx)
                                 :suit    (:suit itm)
                                 :rank    (:rank itm)})
                  cards)))


The code works but I think it is awkward. Especially the part where I use map-indexed function to add :card-id to each card.

Any suggestions to improve the code snippet?

Solution

There are a few minor improvements you can make here that lead to a fairly elegant implementation.

First, using flatten is rarely a good idea, because rather than just dealing with the top-level structure of the thing you hand it, it reaches down into its inner structure, thus making it brittle when you change the representation of your data. Therefore, you should instead use apply concat in place of flatten in your code.

However, as @ChrisMurphy points out, the for macro already supports list products, so you can replace the usage of flatten or apply concat and the two usages of for with a single usage of for that produces a flat sequence.

Then, instead of writing out the full range of numbers from 1 to 13, you can use the range function to replace that vector with (range 1 (inc 13)) or something equivalent.

Finally, rather than manually deconstructing and reconstructing each map in your lambda that you pass to map-indexed, you can use the assoc function to simply add the :card-id mapping.

With these changes, you end up with a solution that looks like this:

(defn new-deck []
  (map-indexed
   #(assoc %2 :card-id (inc %1))
   (for [suit [:spade :heart :diamond :club]
         rank (range 1 (inc 13))]
     {:suit suit :rank rank})))

Code Snippets

(defn new-deck []
  (map-indexed
   #(assoc %2 :card-id (inc %1))
   (for [suit [:spade :heart :diamond :club]
         rank (range 1 (inc 13))]
     {:suit suit :rank rank})))

Context

StackExchange Code Review Q#157827, answer score: 7

Revisions (0)

No revisions yet.