Skip to content

Instantly share code, notes, and snippets.

@LauraKirby
Last active August 26, 2017 17:05
Show Gist options
  • Save LauraKirby/bfe987743f04d36e3fe6a7c125bdb9d4 to your computer and use it in GitHub Desktop.
Save LauraKirby/bfe987743f04d36e3fe6a7c125bdb9d4 to your computer and use it in GitHub Desktop.
Deck of Cards: Design the data structures for a generic deck of cards. Explain how you would subclass the data structures.
# Suit
# instance variables
# pip
# rank
# instance methods
# to_s
# Card
# instance variables
# suit: a Card has one Suit
# instance methods
# to_s
# Deck
# has 52 Cards
# instance method
# type (show different versions eg: standard French, for children)
# Currently, Card has the attribute "type". Since this restates information
# provided by Deck, I believe that Card should inherit from Deck. However,
# this would mean that a Card could not be created without a Deck. This
# is how playing cards are usually purchased, so I guess this is ok.
STANDARD_PIPS = [ :club, :diamond, :heart, :spade ]
STANDARD_RANKS = [ :two, :three, :four, :five, :six, :seven, :eight,
:nine, :ten, :jack, :queen, :king, :ace ]
class Suit
attr_accessor :pip, :rank
def initialize(pip, rank)
@pip = pip
@rank = rank
end
def to_s
"#{self.pip} of #{self.rank}"
end
end
class Card
attr_accessor :suit, :type
def initialize(type, pip, rank)
@suit = Suit.new(pip, rank)
@type = type
end
def to_s
"#{self.type}, #{self.suit.pip} of #{self.suit.rank}"
end
end
class Deck
attr_accessor :cards, :type, :dealt_index
@@types = [:standard]
def initialize(create_type)
if @@types.include? create_type
@type = create_type
@cards = self.send(create_type)
else
puts "Deck type must be one of #{@@types}"
end
@dealt_index = 0 # marks the first undealt card
end
def cards_for_suit(rank)
self.cards.lazy.select { |card| card.suit.rank == rank }.first(13)
end
def self.types
@@types
end
def standard
STANDARD_RANKS.flat_map {|rank| STANDARD_PIPS.map {|pip| Card.new(:standard, rank, pip)}}
end
end
# Create a Suit
# suit = Suit.new(STANDARD_PIPS[0], STANDARD_RANKS[0])
# Create a Card
# card = Card.new(:standard, STANDARD_PIPS[0], STANDARD_RANKS[0])
# Create a "standard" Deck of Cards
deck = Deck.new(:standard)
puts deck.cards_for_suit(:club)
puts "first card in deck: #{deck.cards[0].to_s}"
@sideshowbandana
Copy link

https://gist.github.com/LauraKirby/bfe987743f04d36e3fe6a7c125bdb9d4/ce74862d8e8ebda4febffe4596e27bd0a8f8440e#file-deck-of-cards-L24-L26
Don't make these global constants, put them within one of your classes

https://gist.github.com/LauraKirby/bfe987743f04d36e3fe6a7c125bdb9d4/ce74862d8e8ebda4febffe4596e27bd0a8f8440e#file-deck-of-cards-L28-L39
I think creating a suit class might be overkill. Also, I don't think a suit object has a rank. That's more of an attribute of an actual card. Plus your doing the heavy lifting with the card class anyway. If you really want to have a container for pip and rank, you could make a tuple or a struct within card named "value" or something.

https://gist.github.com/LauraKirby/bfe987743f04d36e3fe6a7c125bdb9d4/ce74862d8e8ebda4febffe4596e27bd0a8f8440e#file-deck-of-cards-L76
I would use more of a factory pattern for Deck. Change standard into a class method that returns a Deck instance with all the standard cards. Then the initializer just needs to take in a list of cards and set the dealt index. That way there's nothing preventing people from making up their own decks, but you know for a fact when you call Deck.standard, you're going to get a standard deck. You could probably encapsulate the STANDARD_PIPS and STANDARD_RANKS inside this as well.

https://gist.github.com/LauraKirby/bfe987743f04d36e3fe6a7c125bdb9d4/ce74862d8e8ebda4febffe4596e27bd0a8f8440e#file-deck-of-cards-L90
You don't need to call #to_s, #{} calls #to_s implicitly.

https://gist.github.com/LauraKirby/bfe987743f04d36e3fe6a7c125bdb9d4/ce74862d8e8ebda4febffe4596e27bd0a8f8440e#file-deck-of-cards-L55
You're not currently using dealt_index anywhere other than setting it.

Random thought:

Instead of putting type on card and forcing it to be a certain type, instead have a card belong to a deck. The deck knows what type it is and a card knows what deck it belongs to. So to do this you would have a attr_accessor :current_deck on card, and set it when the deck is initialized. It's a bit out there and it all depends on how you view the system to work. You basically have to answer this question: "is a card always a certain type?"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment