5 ms·
So the Scala solution for this is: http://ideone.com/Vussjh http://ideone.com/Vussjh object Cards { sealed trait Suit case object Spades extends Suit
by octo_t 13y ago
So the Scala solution for this is: http://ideone.com/Vussjh http://ideone.com/Vussjh
object Cards {
sealed trait Suit
case object Spades extends Suit
case object Clubs extends Suit
case object Hearts extends Suit
case object Diamonds extends Suit
sealed trait Rank
trait FaceCard extends Rank
case object Jack extends FaceCard
case object Queen extends FaceCard
case object King extends FaceCard
case object Ace extends FaceCard
case class ValueCard(n: Int) extends Rank
case class Card(rank: Rank, suit: Suit)
type Deck = IndexedSeq[Card]
def numberToRank(n: Int): Rank = n match {
case 1 => Ace
case x if x <= 10 => ValueCard(x)
case 11 => Jack
case 12 => Queen
case 13 => King
case 14 => Ace
case _ => throw new IllegalArgumentException
}
def numberToSuit(n: Int): Suit = n match {
case 0 => Spades
case 1 => Clubs
case 2 => Hearts
case 3 => Diamonds
}
def apply(): Deck = for(rank <- 1 to 13; suit <- 0 to 3) yield Card(numberToRank(rank), numberToSuit(suit))
}
Now I have: normal operations bound to Deck (head, take, drop etc) and the ability to pattern match on cards. Also strongly typed. This took about 5 minutes top to write.
edit: I'd say the 'numberToRank' parts are probably code smells, but given that its Christmas Eve, I really can't be bothered to think of a better solution right now. Implementing ordering etc can be done on the traits very easily too, but that is game specific (for example are aces high or low, is a King ranked higher than a Jack etc).
- brudgers 13y agoSome things are strongly typed and playing cards are among them. It is just that playing cards are strongly typed as playing cards, not integers or pairs of integers. In blackjack: case 10 => Jack or Queen or King or 10 and case Ace => 1 or 11 and poker with "Dr Pepper" case 10 => ace or 2 or 3 or 4 or 5 or 6 or 7 or 8 or 9 or 10 or jack or queen or king case 2 => ace or 2 or 3 or 4 or 5 or 6 or 7 or 8 or 9 or 10 or jack or queen or king case 4 => ace or 2 or 3 or 4 or 5 or 6 or 7 or 8 or 9 or 10 or jack or queen or king It is sometimes better if the data type provides abstractions over the messy details of the world rather than adding another one to it and planning for the possibility of a Joker in the deck might make sense.
- octo_t 13y agoHeh, same time as my edit. Those methods should be private (i.e. they just exist for building the deck, its the consumers responsibility to shuffle / split into multiple decks etc, as well as assigning value to each card).
- drewhk 13y agoYep, valuation can be simply a function, but wrapping in a typeclass might work as well.
- brudgers 13y agoSo what then does 13=king get me over king=king? And does forgetting to privatise implementation details suggest that the necessary language idioms make the data structure complex in a way that is orthogonal to the real world complexity of the objects it represents, and wasn't the opportunity to avoid that complexity the advantage suggested by the author. To put it another way, private and sealed and trait don't reflect characteristics of a deck of playing cards. They are overhead from the language. It is a case where a static type system, because it is biased toward it's and strings and objects, makes it more difficult to reason about our code - leaving jokers aside, how much of the Scala code makes sense if I want to play Pinnocle versus the data approach advanced by the author? Now I'll admit that Lisp has shaped the way I see the two approaches to representing cards. and this may be why I see implementation of jokers and pinnocle as easy extensions of lists and rather more complex under an object system with static type checking. But I will point out that this model got me to thinking about card games rather than card data types pretty quickly, and card games are probably the reason we're draining the swamp.
- necrobrit 13y agoDoes that 'or' method actually exist in a library somewhere or was it just for illustration?
- brudgers 13y agoJust for illustration. But to the author of the article's point that programming languages structure our thinking, the idea that "or" must be either in the core language or part of some library illustrates the constraints imposed on expressing our ideas absent the ability to introduce new syntax via a lisp-style macro facility. In a sense, Clojure's light weight data structures can be seen as extending up into the language.
- dragonwriter 13y ago> I'd say the 'numberToRank' parts are probably code smells, but given that its Christmas Eve, I really can't be bothered to think of a better solution right now. object Cards { sealed trait Suit case object Spades extends Suit case object Clubs extends Suit case object Hearts extends Suit case object Diamonds extends Suit sealed trait Rank trait FaceCard extends Rank case object Jack extends FaceCard case object Queen extends FaceCard case object King extends FaceCard case object Ace extends FaceCard case class ValueCard(n: Int) extends Rank case class Card(rank: Rank, suit: Suit) type Deck = IndexedSeq[Card] val faceCardRanks = IndexedSeq(Jack,Queen,King,Ace) val valueCardRanks = for (rank <- 2 to 10) yield ValueCard(rank) val ranks = IndexedSeq.concat(valueCardRanks,faceCardRanks) val suits = IndexedSeq(Spades,Clubs,Diamonds,Hearts) def apply(): Deck = for(rank <- ranks; suit <- suits) yield Card(rank, suit) }