Classes_and_Ignorance
#!/usr/bin/env ruby
# frozen_string_literal: true
#############
# CONSTANTS # TODO: See if I need these... or put them in Deck
#############
CONSTANTS = [
SUITE = {H: 'Hearts', D: 'Diamonds', C: 'Clubs', S: 'Spades'},
RANK = [*2..10].push(*%i(J Q K)).unshift(:A)
# NOTE: Do I need translation :J => 'Jack' etc. ?
]
##########
# STRUCT #
##########
Card = Struct.new(:rank, :suite) do
def s = ( SUITE[suite] )
def r = ( RANK.index(rank) +1 ) # numeric rank
def to_s = ( '%s of %s' % [rank, SUITE[suite]] )
end
Sum = Struct.new(:sum, :aces) do
def low = ( sum )
def high = ( ((ret = (sum + (aces? ? 10 : 0))) > 21) ? :bust : ret )
def aces? = ( aces != 0 )
def blackjack? = (self.low == 21 || self.high == 21)
end
##############
# Deck Class #
##############
class Deck
def initialize(no_decks: 1)
@deck = []
no_decks.times { RANK.product(SUITE.keys).each {|c|
@deck.append(Card.new(c.first, c.last))
}}
end
def shuffle = @deck.shuffle!
def deal = @deck.pop
def cards = @deck.length
end
##############
# Hand Class #
##############
class Hand
attr_reader :hand
def initialize(decks = 1)
@hand = [] # hold Card (is a Struct)
@@deck_obj ||= Deck.new(no_decks: decks)
@@deck_obj.shuffle
end
def deal(no_cards = 1) = ( no_cards.times { @hand.push @@deck_obj.deal } )
def sum = ( Sum.new(@hand.inject(0) {|s, h| s += ((h.r > 10) ? 10 : h.r) },
@hand.select {|h| h.r == 1}.size) )
end
# -----------------------------------------------------------------------------
p1 = Hand.new
p1.deal(2)
p2 = Hand.new
p2.deal(2)
[p1, p2].each {|p|
p.hand.each { puts _1.to_s }
sm = p.sum
if sm.blackjack?
puts 'Blackjack!'
else
print 'sum: '
puts sm.aces? ? 'lo: %s, hi: %s' % [sm.low, sm.high] : sm.sum
puts '-'*80
end
}
I just hade the urge to revisit Blackjack. It’s such a great start for working with classes. I’m not that good with classes..
But a Card is a part of a Deck that can form a Hand.. so I just wanted to fit myself in that seat.
I’m semi-ok with this code. I don’t like the CONSTANTS.. should I move them to Deck?
What more demands will be put upon this deck of cards? It’s a lot to think about for a very, very small idea and concept.
I just feel I want to put as little responsibility as possible onto the running code. I can demand you send a symbol and not a string.. but I can’t demand off you to “either receive an Integer OR an Array”.. that’s not fair.