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.