Representing playing cards as specifications
A playing card has a face value and a suit. There are 4 suits in a card deck.
A specification for the possible suits can be defined using literal values
(spec/def ::suits #{:clubs :diamonds :hearts :spades})
As the set is a predicate then it could just be bound to a name, i.e. (def suits? #{:clubs :diamonds :hearts :spades})
Representing different aspects of card game decks
Suits from different regions are called by different names. Each of these suits can be their own spec.
(spec/def ::suits-french #{:hearts :tiles :clovers :pikes})
(spec/def ::suits-german #{:hearts :bells :acorns :leaves})
(spec/def ::suits-spanish #{:cups :coins :clubs :swords})
(spec/def ::suits-italian #{:cups :coins :clubs :swords})
(spec/def ::suits-swiss-german #{:roses :bells :acorns :shields})
A composite specification called ::card-suits
provides a simple abstraction over all the variations of suits. Using ::card-suits
will be satisfied with any region specific suits.
(spec/def ::card-suits
(spec/or :french ::suits-french
:german ::suits-german
:spanish ::suits-spanish
:italian ::suits-italian
:swiss-german ::suits-swiss-german
:international ::suits-international))
Define an alias for a specification
Jack queen king are called face cards in the USA and occasionally referred to as court cards in the UK.
Define a spec for ::face-cards and then make ::court-cards and alias for ::face-cards
(spec/def ::face-cards #{:jack :queen :king :ace})
(spec/def ::court-cards ::face-cards)
Any value that conforms to the ::face-card
specification also conforms to the ::court-cards
specification.
(spec/conform ::court-cards :ace)
Playing card rank
Each suit in the deck has the same rank of cards explicitly defining a rank
(spec/def ::rank #{:ace 2 3 4 5 6 7 8 9 10 :jack :queen :king})
rank can be defined more succinctly with the clojure.core/range
function. The expression (range 2 11)
will generates a sequence of integer numbers from 2 to 10 (the end number is exclusive, so 11 is not in the sequence).
Using clojure.core/into
this range of numbers can be added to the face card values.
(into #{:ace :jack :queen :king} (range 2 11))
The ::rank
specification now generates all the possible values for playing cards.
(spec/def ::rank (into #{:ace :jack :queen :king} (range 2 11)))
The specification only checks to see if a value is in the set, the order of the values in the set is irrelevant.
Playing Cards
A playing card is a combination of suit and face value, a pair of values, referred to as a tuple.
Clojure spec has a tuple
function, however, we need to define some predicates first
(spec/def ::playing-card (spec/tuple ::rank ::suits ))
Use the spec with values to see if they conform. Try you own values for a playing card.
(spec/conform ::playing-card [:ace :spades])