Skip to content

Commit

Permalink
Blackjack
Browse files Browse the repository at this point in the history
  • Loading branch information
alzapiedi committed Dec 5, 2015
0 parents commit c26c754
Show file tree
Hide file tree
Showing 15 changed files with 819 additions and 0 deletions.
Binary file added .DS_Store
Binary file not shown.
2 changes: 2 additions & 0 deletions .rspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
--color
--format documentation
6 changes: 6 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
source "https://rubygems.org"

ruby '2.0.0'

gem 'rspec', "~> 3.1.0"
gem 'byebug'
30 changes: 30 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
GEM
remote: https://rubygems.org/
specs:
byebug (3.5.1)
columnize (~> 0.8)
debugger-linecache (~> 1.2)
slop (~> 3.6)
columnize (0.8.9)
debugger-linecache (1.2.0)
diff-lcs (1.2.5)
rspec (3.1.0)
rspec-core (~> 3.1.0)
rspec-expectations (~> 3.1.0)
rspec-mocks (~> 3.1.0)
rspec-core (3.1.7)
rspec-support (~> 3.1.0)
rspec-expectations (3.1.2)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.1.0)
rspec-mocks (3.1.3)
rspec-support (~> 3.1.0)
rspec-support (3.1.2)
slop (3.6.0)

PLATFORMS
ruby

DEPENDENCIES
byebug
rspec (~> 3.1.0)
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Blackjack

## Rules

* You have **1 hour** for the assessment. Do not worry if you do not
complete all the assessment; finish as much as you can.
* Descriptions of each method to implement are written into the `lib/`
files. For each `lib/` file, there is a corresponding `spec/` file.
* Run the specs as you solve the assessment. Solve the assessment in
this order:

```
bundle exec rspec spec/deck_spec.rb
bundle exec rspec spec/hand_spec.rb
bundle exec rspec spec/player_spec.rb
bundle exec rspec spec/dealer_spec.rb
```

* Wait until you finish to run `rspec spec`, which will run all the
tests. Do this as a final check that you have them all passing.

## Game Rules

* Players play against the dealer; multiple players can win each
round.
* Players win if they don't "bust" and either:
1. their hand is worth more points than the dealer's hand.
2. the dealer busts.
* To compute a hand's value, add the value of each numbered card, and
ten for face cards. An ace is worth 11 if the total score would be
<= 21. If an ace value of 11 would result in a bust, it is worth 1.
* A score of >21 is a bust.
* Players are first dealt two cards; they can request additional cards
("hit") until they pass ("stay") or bust.
* The dealer must hit on a hand worth <17, otherwise he must stay.
64 changes: 64 additions & 0 deletions lib/blackjack.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
require_relative 'hand'
require_relative 'deck'
require_relative 'player'
require_relative 'dealer'
require_relative 'card'

class Blackjack

def initialize(players, dealer, deck)
@players = players
@dealer = dealer
@deck = deck
end

def deal_hand
@deck.shuffle
@players.each { |player| player.place_bet(@dealer, player.get_bet )}
@players.each { |player| player.hand = Hand.deal_from(@deck) }
@dealer.hand = Hand.deal_from(@deck)
@dealer.hand.cards[0].up = false
end

def play_turn(player)
action = nil
until player.hand.busted? || action == "stay"
action = player.get_action
if action == "hit"
player.hand.hit(@deck)
end
puts "#{player.name} - #{player.hand}"
end
puts "BUSTED!" if player.hand.busted?
end

def play_hand
@players.each { |player| play_turn(player) }
puts @dealer.hand
@dealer.play_hand(@deck)
@dealer.pay_bets
end


end


if __FILE__ == $PROGRAM_NAME
nick = Player.new("Nick", 1000)
krawldad = Player.new("Krawldad", 1000)
georgus = Player.new("Georgus", 1000)
mogul = Player.new("Mogul", 100000)
henry = Dealer.new
shoe = Deck.new

players = [nick, krawldad, georgus, mogul]
game = Blackjack.new(players, henry, shoe)

game.deal_hand
puts "Henry - #{henry.display_hand}"
players.each { |player| puts "#{player.name} - #{player.hand}" }
game.play_hand

players.each { |player| puts player.bankroll}

end
83 changes: 83 additions & 0 deletions lib/card.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# -*- coding: utf-8 -*-

# Represents a playing card.
class Card
SUIT_STRINGS = {
:clubs => "♣",
:diamonds => "♦",
:hearts => "♥",
:spades => "♠"
}

VALUE_STRINGS = {
:deuce => "2",
:three => "3",
:four => "4",
:five => "5",
:six => "6",
:seven => "7",
:eight => "8",
:nine => "9",
:ten => "10",
:jack => "J",
:queen => "Q",
:king => "K",
:ace => "A"
}

BLACKJACK_VALUE = {
:deuce => 2,
:three => 3,
:four => 4,
:five => 5,
:six => 6,
:seven => 7,
:eight => 8,
:nine => 9,
:ten => 10,
:jack => 10,
:queen => 10,
:king => 10
}

# Returns an array of all suits.
def self.suits
SUIT_STRINGS.keys
end


# Returns an array of all values.
def self.values
VALUE_STRINGS.keys
end

attr_reader :suit, :value
attr_accessor :up

def initialize(suit, value)
unless Card.suits.include?(suit) and Card.values.include?(value)
raise "illegal suit (#{suit}) or value (#{value})"
end

@suit, @value, @up = suit, value
end

def blackjack_value
raise "ace has special value" if value == :ace

BLACKJACK_VALUE[value]
end

# Compares two cards to see if they're equal in suit & value.
def ==(other_card)
return false if other_card.nil?

[:suit, :value].all? do |attr|
self.send(attr) == other_card.send(attr)
end
end

def to_s
VALUE_STRINGS[value] + SUIT_STRINGS[suit]
end
end
38 changes: 38 additions & 0 deletions lib/dealer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
require_relative 'player'

class Dealer < Player
attr_reader :bets
attr_accessor :hand
def initialize
super("dealer", 0)

@bets = {}
end

def place_bet(dealer, amt)
raise "Dealer doesn't bet"
end

def display_hand
hand.cards[1]
end

def play_hand(deck)
until hand.busted? || hand.points >= 17
hand.hit(deck)
sleep(1)
puts "Henry - #{hand}"
end

end

def take_bet(player, amt)
@bets[player] = amt
end

def pay_bets
@bets.each do |player, amt|
player.pay_winnings(2*amt) if player.hand.beats?(self.hand)
end
end
end
45 changes: 45 additions & 0 deletions lib/deck.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
require_relative 'card'

# Represents a deck of playing cards.
class Deck
# Returns an array of all 52 playing cards.
def self.all_cards
deck = []
Card.suits.each do |suit|
Card.values.each do |value|
deck << Card.new(suit, value)
end
end
deck
end

def removes
@cards.pop
end

def shuffle
@cards.shuffle!
end

def initialize(deck = Deck.all_cards)
@cards = deck
end

# Returns the number of cards in the deck.
def count
@cards.count
end

# Takes `n` cards from the top of the deck.
def take(n)
raise "not enough cards" if n > @cards.count
result = []
n.times { result << @cards.shift}
result
end

# Returns an array of cards to the bottom of the deck.
def return(return_cards)
return_cards.each { |card| @cards << card }
end
end
61 changes: 61 additions & 0 deletions lib/hand.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
class Hand
# This is called a *factory method*; it's a *class method* that
# takes the a `Deck` and creates and returns a `Hand`
# object. This is in contrast to the `#initialize` method that
# expects an `Array` of cards to hold.
def self.deal_from(deck)
Hand.new(deck.take(2))
end

attr_accessor :cards

def initialize(cards)
@cards = cards
end

def points
points = 0
aces = 0
@cards.each do |card|
if card.value == :ace
points += 11
aces += 1
else
points += card.blackjack_value
end
end
aces.times { points -= 10 if points > 21 }
points
end

def busted?
points > 21
end

def hit(deck)
raise "already busted" if busted?
new_card = deck.take(1)
@cards += new_card

end

def beats?(other_hand)
case points <=> other_hand.points
when -1
other_hand.busted? && !busted?
when 0
false
when 1
!busted?
end
end

def return_cards(deck)
deck.return(@cards)
@cards = []
end

def to_s
@cards.join(",") + " (#{points})"
end
end
Loading

0 comments on commit c26c754

Please sign in to comment.