Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
217 changes: 151 additions & 66 deletions blackjack.rb
Original file line number Diff line number Diff line change
@@ -1,20 +1,35 @@
require 'rspec'

class Card

attr_reader :suit, :value
def initialize(suit, value)
@suit = suit
@value = value

end

def value
return 10 if ["J", "Q", "K"].include?(@value)
return 11 if @value == "A"
return 11 if @value.eql? "A"
return @value
end

def abbr_suit

if @suit.eql? :hearts
return "H"
elsif @suit.eql? :diamonds
return "D"
elsif @suit.eql? :clubs
return "C"
elsif @suit.eql? :spades
return "S"
end
end

def to_s
"#{@value}-#{suit}"
return abbr_suit + "#{value}"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I only like to use return for early returns. Not a huge deal, obviously, but I think it s a decent enough convention

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is an early return? is it when you do
return :something if something == 2

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

regarding using the ".eql?" method call over the "=="...I am not sure why I did that. is there a rule of when we should use one over the other one?

thanks for your feedback.
-j

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an example of an early return:

def average(objects)
  return 0 if objects.length == 0
  objects.inject(:+) / objects.length
end

The return causes an early exit from the method. In Ruby, you do not need to add a "return" at the end of a method. It's implicity and you don't want to break this convention.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't use the .eql? method is my recommendation.

end

end
Expand All @@ -28,16 +43,18 @@ def initialize
end

def self.build_cards
cards = []
[:clubs, :diamonds, :spades, :hearts].each do |suit|
(2..10).each do |number|
cards << Card.new(suit, number)
end
["J", "Q", "K", "A"].each do |facecard|
cards << Card.new(suit, facecard)
end
end
cards.shuffle
cards = []
[:clubs, :diamonds, :spades, :hearts].each do |suit|
(2..10).each do |number|
cards << Card.new(suit, number) # << means add to the end of the array
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI: "<<" is referred to as the "shovel" operator.

end
["J", "Q", "K", "A"].each do |facecard|
cards << Card.new(suit, facecard)
end
end

cards.shuffle

end
end

Expand All @@ -47,34 +64,42 @@ class Hand
def initialize
@cards = []
end

def hit!(deck)
@cards << deck.cards.shift
end

def value
cards.inject(0) {|sum, card| sum += card.value }
cards.inject(0) { |sum, card| sum += card.value }
end

def play_as_dealer(deck)
if value < 16
hit!(deck)
play_as_dealer(deck)
end
hit!(deck) while value < 16
end

end

class Game
attr_reader :player_hand, :dealer_hand

def initialize
@deck = Deck.new
@player_hand = Hand.new
@dealer_hand = Hand.new
2.times { @player_hand.hit!(@deck) }
2.times { @dealer_hand.hit!(@deck) }
@player_hand.hit!(@deck)
@dealer_hand.hit!(@deck)
@player_hand.hit!(@deck)
@dealer_hand.hit!(@deck)
end

def hit
@player_hand.hit!(@deck)
@dealer_hand.play_as_dealer(@deck)
if @player_hand.value >= 21 || @dealer_hand.value >= 21
return stand
else
return status
end
end

def stand
Expand All @@ -83,65 +108,81 @@ def stand
end

def status
{:player_cards=> @player_hand.cards,
@winner = :player if @player_hand.value == 21
@winner = :dealer if @dealer_hand.value == 21

if @winner.nil?
@display_dealer_cards = "XX"
@display_dealer_value = "--"
else
@display_dealer_cards = @dealer_hand.cards
@display_dealer_value = @dealer_hand.value
end

{:player_cards => @player_hand.cards,
:player_value => @player_hand.value,
:dealer_cards => @dealer_hand.cards,
:dealer_value => @dealer_hand.value,
:winner => @winner}
:dealer_cards => @display_dealer_cards,
:dealer_value => @display_dealer_value,
:winner => @winner
}
end

def determine_winner(player_value, dealer_value)
return :dealer if dealer_value == 21
return :player if player_value == 21
return :dealer if player_value > 21
return :player if dealer_value > 21
if player_value == dealer_value
:push
elsif player_value > dealer_value
:player
else
:dealer
return :push if player_value == dealer_value
if player_value > dealer_value
return :player
else
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The alignment here of the if/else seems off.. it was a bit hard to read (obviously not a big deal).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think i was working on this part at 4 in the morning. my bad.

return :dealer
end
end
end

def inspect
status
end
end

end


describe Card do

it "should accept suit and value when building" do
it "should accept a suit and value when building" do
card = Card.new(:clubs, 10)
card.suit.should eq(:clubs)
card.value.should eq(10)
end

it "should have a value of 10 for facecards" do
facecards = ["J", "Q", "K"]
facecards.each do |facecard|
card = Card.new(:hearts, facecard)
facecards.each do |facecard|
card = Card.new(:hearts, facecard)
card.value.should eq(10)
end
end
it "should have a value of 4 for the 4-clubs" do
card = Card.new(:clubs, 4)
card.value.should eq(4)
end
end

it "should return 11 for Ace" do
card = Card.new(:diamonds, "A")
card.value.should eq(11)
end

it "should abbreviate the suit" do
card = Card.new(:hearts, 5)
card.abbr_suit.should eq("H")
end

it "should be formatted nicely" do
card = Card.new(:diamonds, "A")
card.to_s.should eq("A-diamonds")
#card = Card.new(:diamonds, "A")
#card.to_s.should eq("A-diamonds")
card = Card.new(:hearts, 5)
card.to_s.should eq("H5")
end
end

end

describe Deck do

it "should build 52 cards" do
Deck.build_cards.length.should eq(52)
end
Expand All @@ -152,9 +193,7 @@ def inspect

end


describe Hand do

it "should calculate the value correctly" do
deck = mock(:deck, :cards => [Card.new(:clubs, 4), Card.new(:diamonds, 10)])
hand = Hand.new
Expand All @@ -164,55 +203,58 @@ def inspect

it "should take from the top of the deck" do
club4 = Card.new(:clubs, 4)
diamond7 = Card.new(:diamonds, 7)
diamond7 = Card.new(:diamonds, 7)
clubK = Card.new(:clubs, "K")

deck = mock(:deck, :cards => [club4, diamond7, clubK])
deck = mock(:deck, :cards => [club4, diamond7, clubK])
hand = Hand.new
2.times { hand.hit!(deck) }
hand.cards.should eq([club4, diamond7])

end


describe "#play_as_dealer" do
it "should hit blow 16" do
it "should hit below 16" do
deck = mock(:deck, :cards => [Card.new(:clubs, 4), Card.new(:diamonds, 4), Card.new(:clubs, 2), Card.new(:hearts, 6)])
hand = Hand.new
2.times { hand.hit!(deck) }
hand.play_as_dealer(deck)
hand.value.should eq(16)
end
it "should not hit above" do

it "should not hit above 16" do
deck = mock(:deck, :cards => [Card.new(:clubs, 8), Card.new(:diamonds, 9)])
hand = Hand.new
2.times { hand.hit!(deck) }
hand.play_as_dealer(deck)
hand.value.should eq(17)
end

it "should stop on 21" do
deck = mock(:deck, :cards => [Card.new(:clubs, 4),
Card.new(:diamonds, 7),
Card.new(:clubs, "K")])
deck = mock(:deck, :cards => [Card.new(:clubs, 4), Card.new(:diamonds, 7),
Card.new(:clubs, "K")])
hand = Hand.new
2.times { hand.hit!(deck) }
hand.play_as_dealer(deck)
hand.value.should eq(21)
end

end
end

end

describe Game do

it "should have a players hand" do
it "should have a player hand" do
Game.new.player_hand.cards.length.should eq(2)
end
it "should have a dealers hand" do

it "should have a dealer hand" do
Game.new.dealer_hand.cards.length.should eq(2)
end

it "should have a status" do
Game.new.status.should_not be_nil
end

it "should hit when I tell it to" do
game = Game.new
game.hit
Expand All @@ -225,18 +267,61 @@ def inspect
game.status[:winner].should_not be_nil
end

it "should stand if player busts" do
game = Game.new
game.hit until game.player_hand.value > 21
puts Game.new.determine_winner(game.player_hand.value,15)
Game.new.determine_winner(game.player_hand.value,15).should eq(:dealer)
end

it "should stand if dealer busts" do
game = Game.new
5.times {game.hit} #5 hits should potentially cause dealer to bust
if game.dealer_hand.value > 21 #only running test if dealer pushes
Game.new.determine_winner(15, game.dealer_hand.value).should eq(:player)
end
end

it "should not show me the dealer cards until player stands" do
game = Game.new
game.status[:dealer_cards].should eq("XX")
end

it "should not show me the dealer value until player stands" do
game = Game.new
game.status[:dealer_value].should eq("--")
end

it "should show me the dealer cards when player stands" do
game = Game.new
game.stand
game.status[:dealer_cards].should_not eq("XX")
end

it "should show me the dealer value when player stands" do
game = Game.new
game.stand
game.status[:dealer_value].should_not eq("--")
end


describe "#determine_winner" do
it "should have dealer win when player busts" do
Game.new.determine_winner(22, 15).should eq(:dealer)
Game.new.determine_winner(22,15).should eq(:dealer)
end
it "should player win if dealer busts" do
Game.new.determine_winner(18, 22).should eq(:player)

it "should have player win if dealer busts" do
Game.new.determine_winner(15,22).should eq(:player)
end
it "should have player win if player > dealer" do
Game.new.determine_winner(18, 16).should eq(:player)

it "should have player win if player greater than dealer" do
Game.new.determine_winner(20,15).should eq(:player)
end
it "should have push if tie" do
Game.new.determine_winner(16, 16).should eq(:push)

it "should push if tie" do
Game.new.determine_winner(19,19).should eq(:push)
end

end
end

end