Last active
August 26, 2017 17:05
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Suit | |
# instance variables | |
# pip: club, heart, spade diamond | |
# rank: two, three, four... jack, queen... | |
# instance methods | |
# to_s | |
# Card | |
# instance variables | |
# suit: a Card has one Suit | |
# instance methods | |
# to_s | |
# Deck | |
# has 52 Cards | |
# instance methods | |
# type (show different versions eg: standard French, for children) | |
# cards_for_suit | |
# 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. | |
# Ideas: make Deck a linked list, is there a good use case for a binary search tree. | |
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}" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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?"