From 1ef42850e1ce022c44bb31ac68d553a5fa8de5bd Mon Sep 17 00:00:00 2001 From: Morgan Martin Date: Fri, 22 Jul 2016 13:04:10 -0400 Subject: [PATCH 1/9] basic setup --- Gemfile | 9 ++ Gemfile.lock | 32 +++++++ app.rb | 25 +++++ helpers/README.md | 2 + helpers/blackjack_helper.rb | 18 ++++ helpers/lib/.ace.rb.swp | Bin 0 -> 12288 bytes helpers/lib/ace.rb | 20 ++++ helpers/lib/bet.rb | 2 + helpers/lib/blackjack.rb | 12 +++ helpers/lib/card.rb | 64 +++++++++++++ helpers/lib/dealer.rb | 17 ++++ helpers/lib/deck.rb | 49 ++++++++++ helpers/lib/deck_empty_error.rb | 5 + helpers/lib/game.rb | 146 ++++++++++++++++++++++++++++++ helpers/lib/game_view.rb | 115 +++++++++++++++++++++++ helpers/lib/hand.rb | 78 ++++++++++++++++ helpers/lib/human_player.rb | 80 ++++++++++++++++ helpers/lib/player.rb | 35 +++++++ helpers/lib/player_view.rb | 24 +++++ helpers/lib/t.rb | 5 + helpers/lib/view.rb | 13 +++ helpers/spec/ace_spec.rb | 20 ++++ helpers/spec/card_spec.rb | 48 ++++++++++ helpers/spec/dealer_spec.rb | 29 ++++++ helpers/spec/deck_spec.rb | 34 +++++++ helpers/spec/hand_spec.rb | 48 ++++++++++ helpers/spec/human_player_spec.rb | 32 +++++++ helpers/spec/player_spec.rb | 27 ++++++ helpers/spec/spec_helper.rb | 103 +++++++++++++++++++++ views/blackjack.erb | 7 ++ views/blackjackhit.erb | 1 + views/layout.erb | 12 +++ views/welcome.erb | 3 + 33 files changed, 1115 insertions(+) create mode 100644 Gemfile create mode 100644 Gemfile.lock create mode 100644 app.rb create mode 100644 helpers/README.md create mode 100644 helpers/blackjack_helper.rb create mode 100644 helpers/lib/.ace.rb.swp create mode 100644 helpers/lib/ace.rb create mode 100644 helpers/lib/bet.rb create mode 100644 helpers/lib/blackjack.rb create mode 100644 helpers/lib/card.rb create mode 100644 helpers/lib/dealer.rb create mode 100644 helpers/lib/deck.rb create mode 100644 helpers/lib/deck_empty_error.rb create mode 100644 helpers/lib/game.rb create mode 100644 helpers/lib/game_view.rb create mode 100644 helpers/lib/hand.rb create mode 100644 helpers/lib/human_player.rb create mode 100644 helpers/lib/player.rb create mode 100644 helpers/lib/player_view.rb create mode 100644 helpers/lib/t.rb create mode 100644 helpers/lib/view.rb create mode 100644 helpers/spec/ace_spec.rb create mode 100644 helpers/spec/card_spec.rb create mode 100644 helpers/spec/dealer_spec.rb create mode 100644 helpers/spec/deck_spec.rb create mode 100644 helpers/spec/hand_spec.rb create mode 100644 helpers/spec/human_player_spec.rb create mode 100644 helpers/spec/player_spec.rb create mode 100644 helpers/spec/spec_helper.rb create mode 100644 views/blackjack.erb create mode 100644 views/blackjackhit.erb create mode 100644 views/layout.erb create mode 100644 views/welcome.erb diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..18fd4cf --- /dev/null +++ b/Gemfile @@ -0,0 +1,9 @@ +# frozen_string_literal: true +# A sample Gemfile +source "https://rubygems.org" + +gem 'sinatra' + +group :development do + gem 'pry-byebug' +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..e53c1fb --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,32 @@ +GEM + remote: https://rubygems.org/ + specs: + byebug (9.0.5) + coderay (1.1.1) + method_source (0.8.2) + pry (0.10.4) + coderay (~> 1.1.0) + method_source (~> 0.8.1) + slop (~> 3.4) + pry-byebug (3.4.0) + byebug (~> 9.0) + pry (~> 0.10) + rack (1.6.4) + rack-protection (1.5.3) + rack + sinatra (1.4.7) + rack (~> 1.5) + rack-protection (~> 1.4) + tilt (>= 1.3, < 3) + slop (3.6.0) + tilt (2.0.5) + +PLATFORMS + ruby + +DEPENDENCIES + pry-byebug + sinatra + +BUNDLED WITH + 1.12.5 diff --git a/app.rb b/app.rb new file mode 100644 index 0000000..bff2f30 --- /dev/null +++ b/app.rb @@ -0,0 +1,25 @@ +require 'sinatra' +require 'pry-byebug' +require 'sinatra/reloader' if development? +require './helpers/blackjack_helper.rb' + +enable :sessions + +helpers BlackjackHelper + +get '/' do + erb :welcome +end + +get '/blackjack' do + turn = session['turn'] = 'player' + deck = session['deck'] = new_deck.shuffle + player_cards = session['player_cards'] = deal(deck, 2) + dealer_cards = session['dealer_cards'] = deal(deck, 2) + erb :blackjack, locals: { deck: deck, player_cards: player_cards, + dealer_cards: dealer_cards } +end + + + +# welcome -> form :player_name, creates a game instance, assigns the player name diff --git a/helpers/README.md b/helpers/README.md new file mode 100644 index 0000000..90bc16d --- /dev/null +++ b/helpers/README.md @@ -0,0 +1,2 @@ +# Morgan Martin's project_cli_blackjack +Hit me! diff --git a/helpers/blackjack_helper.rb b/helpers/blackjack_helper.rb new file mode 100644 index 0000000..cb24bc9 --- /dev/null +++ b/helpers/blackjack_helper.rb @@ -0,0 +1,18 @@ +module BlackjackHelper + def deal(deck, num) + deck.pop(num) + end + + def new_deck + return_array = [] + ranks.product(suits) + end + + def ranks + (2..10).to_a << :ace << :jack << :queen << :king + end + + def suits + [:spade, :heart, :diamond, :club] + end +end diff --git a/helpers/lib/.ace.rb.swp b/helpers/lib/.ace.rb.swp new file mode 100644 index 0000000000000000000000000000000000000000..6806a8185976733a6c1ee8bf4f544012a2a6bb8f GIT binary patch literal 12288 zcmeI&O)mpM7zgm-B*aVb0Ujh?l2S!N8ubz<2O$w0H?zCbW_9guW@ixx5;x)GBRKmM zK7lJ=!le#QJZrZXRGcK_Kgqw-?mY9%?(f#L_Vn)h2F*{+2_AhybgZ23-E}p@{k9MX zp{~gwUHE<+*x~W_71`=(*06XK>UtbWM-?L-?kmT{%{P|gdzS4>r@qfA`kr0nvMFu< zq&;dN0D)EliK$L5bnnd0l%~^?k>Md4=-+8ojq4DA00bZa0SG_<0uX?}KNK)gn>gd= zYR{i-FrV8#%=t%55P$##AOHafKmY;|fB*y_009X6K>_IsanU2hGbjE1zxn`jG4lqBx0^&QJ3K&v?@JPSkjuc&0$`s gq9)Qik;Z6CE9ojt @player.hand_value ? @dealer : @player + end + + #This could be moved to the player class + def hit_loop(competitor) + until competitor.bust? || competitor.twenty_one? + sleep 2 + competitor.hit? ? deal_player_cards(competitor, 1) : break + break if competitor.doubled_down? + @view.print_busted if competitor.bust? + @view.print_player_hand(competitor) + end + handle_double_down(competitor) if competitor.doubled_down? + end + + def handle_double_down(competitor) + deal_player_cards(competitor, 1) + @view.print_player_hand(competitor) + sleep 2 + @view.output("About to double bet") + competitor.double_bet + competitor.reset_doubled_down + end + + # This could be moved to the main view class + def render_cards(cards, message = nil) + @view.output(message) if message + @view.render_cards(cards) + end + + # Perhaps move to a deck view? + def deal + @view.print_dealing_message + deal_player_cards(@player, 2) + deal_player_cards(@dealer, 2) + @dealer.make_last_card_facedown + print_dealt_cards + end + + def print_dealt_cards + @view.print_dealt_cards(@player.cards_in_hand, @dealer.cards_in_hand) + end + + def deal_player_cards(player, num_of_cards) + cards = get_cards_from_deck(num_of_cards) + add_cards_to_players_hand(player, cards) + end + + def add_cards_to_players_hand(player, cards) + cards.each { |card| player.add_card_to_hand(card) } + end + + def get_cards_from_deck(num_of_cards) + cards = [] + num_of_cards.times { cards << @deck.get_card } + cards + end +end diff --git a/helpers/lib/game_view.rb b/helpers/lib/game_view.rb new file mode 100644 index 0000000..c812e81 --- /dev/null +++ b/helpers/lib/game_view.rb @@ -0,0 +1,115 @@ +class GameView < View + + def print_resetting_hands + print 'resetting hands' + 3.times do + sleep 1 + print '.' + end + output + end + + def print_dealing_message + print 'dealing' + 3.times do + sleep 1 + print '.' + end + output + end + + def print_game_results(purse_amount) + if purse_amount > 0 + output("You leave the game with #{purse_amount} left over.") + else + output("You went broke...") + end + end + + def print_player_hand(player) + if player.is_a?(HumanPlayer) + output("Your hand:") + render_cards(player.cards_in_hand) + else + output("The Dealer's Cards:") + render_cards(player.cards_in_hand) + end + end + + def print_dealt_cards(player_cards, dealer_cards) + output("Your cards:") + render_cards(player_cards) + output("The Dealer's Cards:") + render_cards(dealer_cards) + output + end + + def print_player_win(name = nil) + if name + output("Congratulations #{name} you win this round!") + else + output("Congrats player you win this round!") + end + end + + def print_blackjack + output("WINNER WINNER CHICKEN DINNER YOU GOT BLACKJACK") + end + + def print_tie + output("It was a draw.") + end + + def print_busted + output("BUSTED") + end + + def print_score_results(player_score, dealer_score) + output("Player's Score: #{player_score}") + output("Dealer's Score: #{dealer_score}") + end + + def print_player_loss + output("The dealer won this round...") + end + + def render_cards(cards) + return_string = '' + cards = cards.map { |card| convert_card_to_render_string(card).split("\n") } + card_render_string_length.times do + cards.each { |card| return_string << (card.shift + " ") } + return_string << "\n" + end + output(return_string) + end + + private + + def card_render_string_length + 7 + end + + def convert_card_to_render_string(card) + if card.face_down? + face_down_card + else + "----------\n" + + "|#{card.rank_symbol}#{' ' * (7 - card.rank_symbol.length)}#{card.suit_symbol}|\n" + + "| |\n" + + "| |\n" + + "| |\n" + + "|#{card.suit_symbol}#{' ' * (7 - card.rank_symbol.length)}#{card.rank_symbol}|\n" + + "----------" + end + end + + def face_down_card + "----------\n" + + "| ** ** |\n" + + "| ** ** |\n" + + "| |\n" + + "|\\ /|\n" + + "| ****** |\n" + + "----------" + end +end diff --git a/helpers/lib/hand.rb b/helpers/lib/hand.rb new file mode 100644 index 0000000..31bf026 --- /dev/null +++ b/helpers/lib/hand.rb @@ -0,0 +1,78 @@ +class Hand + attr_reader :cards + def initialize(cards = []) + @cards = cards + end + + def bust? + if contains_aces? && total_value_over_twenty_one? + toggle_ace if contains_untoggled_aces? + total_value_over_twenty_one? + else + total_value_over_twenty_one? + end + end + + def remove_card + @cards.pop + end + + def total_value + return 0 if @cards.empty? + @cards.map { |card| card.value }.reduce(:+) + end + + def last_card + @cards.last + end + + def flip_last_card + @cards.last.flip + end + + def num_of_cards + @cards.size + end + + def add_card(card) + card.is_a?(Ace) ? add_ace(card) : @cards << card + end + + def blackjack? + num_of_cards == 2 && total_value == 21 + end + + private + + def add_ace(ace) + if total_value + 11 > 21 + ace.toggle_value + @cards << ace + else + @cards << ace + end + end + + def toggle_ace + get_first_untoggled_ace.toggle_value + end + + def get_first_untoggled_ace + @cards.each do |card| + return card if card.is_a?(Ace) && card.untoggled? + end + nil + end + + def contains_untoggled_aces? + @cards.select { |card| card.is_a?(Ace) }.any? { |ace| ace.untoggled? } + end + + def contains_aces? + @cards.any? { |card| card.is_a?(Ace) } + end + + def total_value_over_twenty_one? + total_value > 21 + end +end diff --git a/helpers/lib/human_player.rb b/helpers/lib/human_player.rb new file mode 100644 index 0000000..9375778 --- /dev/null +++ b/helpers/lib/human_player.rb @@ -0,0 +1,80 @@ +class HumanPlayer < Player + def initialize(options = {}) + super + @view = PlayerView.new + @purse = options[:purse] ? options[:purse] : 100 + @bet = 0 + end + + def double_bet + @bet = 2 * @bet + end + + def doubled_down + @doubled_down + end + + def reset_doubled_down + @doubled_down = false + end + + def possible_to_dd + @bet * 2 < @purse + end + + def hit? + result = @view.ask_for_hit_or_dd(possible_to_dd) + case result + when 'y' + true + when 'n' + false + when 'dd' + @doubled_down = true + false + end + end + + def handle_blackjack_bet + @purse += (@bet * (1.5)).round(0) + @bet + @bet = 0 + end + + def handle_winning_bet + @purse += (@bet * 2) + @bet = 0 + end + + def regain_bet + @purse += @bet + @bet = 0 + end + + def lose_bet + @bet = 0 + end + + def blackjack? + @hand.blackjack? + end + + def make_bet + @bet = nil + until !@bet.nil? && @bet <= @purse + @bet = @view.ask_for_bet_amount(purse_amount) + end + @purse -= @bet + end + + def purse_amount + @purse + end + + def purse_empty? + @purse <= 0 + end + + def assign_name + @name = @view.ask_for_name + end +end diff --git a/helpers/lib/player.rb b/helpers/lib/player.rb new file mode 100644 index 0000000..b518fc4 --- /dev/null +++ b/helpers/lib/player.rb @@ -0,0 +1,35 @@ +class Player + attr_reader :name + def initialize(options = {}) + @hand = Hand.new + @doubled_down = false + end + + def doubled_down? + @doubled_down + end + + def bust? + @hand.bust? + end + + def remove_card_from_hand + @hand.remove_card + end + + def add_card_to_hand(card) + @hand.add_card(card) + end + + def twenty_one? + @hand.total_value == 21 + end + + def hand_value + @hand.total_value + end + + def cards_in_hand + @hand.cards + end +end diff --git a/helpers/lib/player_view.rb b/helpers/lib/player_view.rb new file mode 100644 index 0000000..b5dd856 --- /dev/null +++ b/helpers/lib/player_view.rb @@ -0,0 +1,24 @@ +class PlayerView < View + + def ask_for_hit_or_dd(possible_to_dd) + input = nil + until input == 'n' || input == 'y' || + (input == 'dd' && possible_to_dd == true) + output("Can't double down") if input == 'dd' + + output("Would you like to hit (or double down)? dd/y/n") + input = get_input + end + input + end + + def ask_for_name + output("What is your name?") + get_input + end + + def ask_for_bet_amount(purse_amount) + output("How much would you like to bet? Purse Amount: #{purse_amount}") + get_input.to_i + end +end diff --git a/helpers/lib/t.rb b/helpers/lib/t.rb new file mode 100644 index 0000000..2f6537e --- /dev/null +++ b/helpers/lib/t.rb @@ -0,0 +1,5 @@ +require './blackjack' + +g = Game.new + +g.play diff --git a/helpers/lib/view.rb b/helpers/lib/view.rb new file mode 100644 index 0000000..3201cc0 --- /dev/null +++ b/helpers/lib/view.rb @@ -0,0 +1,13 @@ +class View + def get_input(label = nil) + puts label if label + print '> ' + input = gets.chomp + exit if input.start_with?('q') || input == "exit" + input + end + + def output(info = nil) + puts info + end +end diff --git a/helpers/spec/ace_spec.rb b/helpers/spec/ace_spec.rb new file mode 100644 index 0000000..c7c9110 --- /dev/null +++ b/helpers/spec/ace_spec.rb @@ -0,0 +1,20 @@ +require 'card' +require 'ace' + +describe Ace do + + let(:ace_of_spades) { Ace.new(:spade, :ace)} + + describe '#toggle_value' do + it "toggles an ace's value" do + ace_of_spades.toggle_value + expect(ace_of_spades.value).to eq(1) + end + end + + describe '#rank_symbol' do + it 'works for aces' do + expect(ace_of_spades.rank_symbol).to eq('A') + end + end +end diff --git a/helpers/spec/card_spec.rb b/helpers/spec/card_spec.rb new file mode 100644 index 0000000..efa86a7 --- /dev/null +++ b/helpers/spec/card_spec.rb @@ -0,0 +1,48 @@ +require 'card' + +describe Card do + + let(:ten_of_spades) { Card.new(:spade, 10) } + let(:king_of_spades) { Card.new(:spade, :king)} + + describe 'a ten of spades' do + it 'returns its rank' do + expect(ten_of_spades.rank).to eq(10) + end + + it 'returns its suit' do + expect(ten_of_spades.suit).to eq(:spade) + end + + it 'is showing by default' do + expect(ten_of_spades.face_up?).to eq(true) + end + end + + describe '#flip' do + it 'flips the card over' do + ten_of_spades.flip + expect(ten_of_spades.face_up?).to eq(false) + end + end + + describe '#value' do + it "returns a value matching the card's rank if 10 or under" do + expect(ten_of_spades.value).to eq(10) + end + + it 'returns 10 if it is a face card' do + expect(king_of_spades.value).to eq(10) + end + end + + describe '#rank_symbol' do + it 'returns the value if not a face card' do + expect(ten_of_spades.rank_symbol).to eq('10') + end + + it 'returns a capital letter if it is a face card' do + expect(king_of_spades.rank_symbol).to eq('K') + end + end +end diff --git a/helpers/spec/dealer_spec.rb b/helpers/spec/dealer_spec.rb new file mode 100644 index 0000000..afc59ba --- /dev/null +++ b/helpers/spec/dealer_spec.rb @@ -0,0 +1,29 @@ +require 'player' +require 'dealer' +describe Dealer do + + let(:dealer) { Dealer.new } + let(:king_of_spades) { Card.new(:spade, :king) } + let(:seven_of_spades) { Card.new(:spade, 7) } + + describe '#make_last_card_facedown' do + it 'flips the last card' do + dealer.add_card_to_hand(king_of_spades) + dealer.make_last_card_facedown + expect(dealer.last_card_in_hand.face_up?).to eq(false) + end + end + + describe '#hit?' do + it 'returns true if hand value is less than 17' do + dealer.add_card_to_hand(king_of_spades) + expect(dealer.hit?).to eq(true) + end + + it 'returns false if hand value is 17 or greater' do + dealer.add_card_to_hand(king_of_spades) + dealer.add_card_to_hand(seven_of_spades) + expect(dealer.hit?).to eq(false) + end + end +end diff --git a/helpers/spec/deck_spec.rb b/helpers/spec/deck_spec.rb new file mode 100644 index 0000000..ccaf1ee --- /dev/null +++ b/helpers/spec/deck_spec.rb @@ -0,0 +1,34 @@ +require 'deck_empty_error' +require 'deck' + +describe Deck do + + let(:deck) { Deck.new } + let(:card) { Card.new(:spade, :king) } + + describe '#size' do + it 'returns 52' do + expect(deck.size).to eq(52) + end + end + + describe '#get_card' do + it 'returns a card' do + expect(deck.get_card).to be_an_instance_of(Card) + end + + it 'raises an exception if deck is empty' do + 52.times { deck.get_card} + expect { deck.get_card }.to raise_error(DeckEmptyError) + end + end + + describe '#add_card' do + it 'adds a card to the deck' do + deck.add_card(card) + expect(deck.size).to eq(53) + end + end +end + + diff --git a/helpers/spec/hand_spec.rb b/helpers/spec/hand_spec.rb new file mode 100644 index 0000000..e3e17db --- /dev/null +++ b/helpers/spec/hand_spec.rb @@ -0,0 +1,48 @@ +require 'hand' +require 'ace' + +describe Hand do + + let(:hand) { Hand.new } + let(:king_of_spades) { Card.new(:spade, :king) } + let(:ace_of_spades) { Ace.new(:spade, :ace) } + let(:ace_of_hearts) { Ace.new(:heart, :ace) } + + describe '#add_card' do + it 'adds a card' do + hand.add_card(king_of_spades) + expect(hand.num_of_cards).to eq(1) + end + end + + describe '#bust?' do + it 'returns false for a hand totalling less than 21' do + hand.add_card(king_of_spades) + expect(hand.bust?).to eq(false) + end + + it 'returns true for a hand totalling greater than 21' do + 3.times { hand.add_card(king_of_spades) } + expect(hand.bust?).to eq(true) + end + + it 'returns false if aces can be toggled' do + hand.add_card(ace_of_spades) + hand.add_card(ace_of_hearts) + expect(hand.bust?).to eq(false) + end + end + + describe '#total_value' do + + it 'returns 0 if there are no cards' do + expect(hand.total_value).to eq(0) + end + + it 'toggles the min number of aces required to be less than 21' do + hand.add_card(ace_of_spades) + hand.add_card(ace_of_hearts) + expect(hand.total_value).to eq(12) + end + end +end diff --git a/helpers/spec/human_player_spec.rb b/helpers/spec/human_player_spec.rb new file mode 100644 index 0000000..d9fcb7e --- /dev/null +++ b/helpers/spec/human_player_spec.rb @@ -0,0 +1,32 @@ +require 'human_player' +require 'view' +require 'player_view' + +describe HumanPlayer do + + let(:human) { HumanPlayer.new } + let(:poor_human) { HumanPlayer.new( { purse: 0 } )} + + + describe '#purse_amount' do + it 'starts out at 100' do + expect(human.purse_amount).to eq(100) + end + end + + describe '#purse_empty?' do + it 'returns false if purse is not empty' do + expect(human.purse_empty?).to eq(false) + end + + it 'returns true if purse is empty' do + expect(poor_human.purse_empty?).to eq(true) + end + end + + describe '#double_bet' do + it 'doubles winnings' do + #expect(human.) + end + end +end diff --git a/helpers/spec/player_spec.rb b/helpers/spec/player_spec.rb new file mode 100644 index 0000000..10a874e --- /dev/null +++ b/helpers/spec/player_spec.rb @@ -0,0 +1,27 @@ +require 'player' + +describe Player do + + let(:player) { Player.new } + let(:ace_of_spades) { Ace.new(:spade, :ace) } + let(:ten_of_spades) { Card.new(:spade, 10) } + + describe '#twenty_one?' do + it 'returns true if hand values twenty one' do + player.add_card_to_hand(ace_of_spades) + player.add_card_to_hand(ten_of_spades) + expect(player.twenty_one?).to eq(true) + end + + it 'returns false if hand does not value twenty one' do + expect(player.twenty_one?).to eq(false) + end + end + + describe '#hand_value' do + it "returns the value of the player's hand" do + player.add_card_to_hand(ace_of_spades) + expect(player.hand_value).to eq(11) + end + end +end diff --git a/helpers/spec/spec_helper.rb b/helpers/spec/spec_helper.rb new file mode 100644 index 0000000..47b39ce --- /dev/null +++ b/helpers/spec/spec_helper.rb @@ -0,0 +1,103 @@ +# This file was generated by the `rspec --init` command. Conventionally, all +# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. +# The generated `.rspec` file contains `--require spec_helper` which will cause +# this file to always be loaded, without a need to explicitly require it in any +# files. +# +# Given that it is always loaded, you are encouraged to keep this file as +# light-weight as possible. Requiring heavyweight dependencies from this file +# will add to the boot time of your test suite on EVERY test run, even for an +# individual file that may not need all of that loaded. Instead, consider making +# a separate helper file that requires the additional dependencies and performs +# the additional setup, and require it from the spec files that actually need +# it. +# +# The `.rspec` file also contains a few flags that are not defaults but that +# users commonly want. +# +# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration +RSpec.configure do |config| + # rspec-expectations config goes here. You can use an alternate + # assertion/expectation library such as wrong or the stdlib/minitest + # assertions if you prefer. + config.expect_with :rspec do |expectations| + # This option will default to `true` in RSpec 4. It makes the `description` + # and `failure_message` of custom matchers include text for helper methods + # defined using `chain`, e.g.: + # be_bigger_than(2).and_smaller_than(4).description + # # => "be bigger than 2 and smaller than 4" + # ...rather than: + # # => "be bigger than 2" + expectations.include_chain_clauses_in_custom_matcher_descriptions = true + end + + # rspec-mocks config goes here. You can use an alternate test double + # library (such as bogus or mocha) by changing the `mock_with` option here. + config.mock_with :rspec do |mocks| + # Prevents you from mocking or stubbing a method that does not exist on + # a real object. This is generally recommended, and will default to + # `true` in RSpec 4. + mocks.verify_partial_doubles = true + end + + # This option will default to `:apply_to_host_groups` in RSpec 4 (and will + # have no way to turn it off -- the option exists only for backwards + # compatibility in RSpec 3). It causes shared context metadata to be + # inherited by the metadata hash of host groups and examples, rather than + # triggering implicit auto-inclusion in groups with matching metadata. + config.shared_context_metadata_behavior = :apply_to_host_groups + +# The settings below are suggested to provide a good initial experience +# with RSpec, but feel free to customize to your heart's content. +=begin + # This allows you to limit a spec run to individual examples or groups + # you care about by tagging them with `:focus` metadata. When nothing + # is tagged with `:focus`, all examples get run. RSpec also provides + # aliases for `it`, `describe`, and `context` that include `:focus` + # metadata: `fit`, `fdescribe` and `fcontext`, respectively. + config.filter_run_when_matching :focus + + # Allows RSpec to persist some state between runs in order to support + # the `--only-failures` and `--next-failure` CLI options. We recommend + # you configure your source control system to ignore this file. + config.example_status_persistence_file_path = "spec/examples.txt" + + # Limits the available syntax to the non-monkey patched syntax that is + # recommended. For more details, see: + # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ + # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ + # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode + config.disable_monkey_patching! + + # This setting enables warnings. It's recommended, but in some cases may + # be too noisy due to issues in dependencies. + config.warnings = true + + # Many RSpec users commonly either run the entire suite or an individual + # file, and it's useful to allow more verbose output when running an + # individual spec file. + if config.files_to_run.one? + # Use the documentation formatter for detailed output, + # unless a formatter has already been configured + # (e.g. via a command-line flag). + config.default_formatter = 'doc' + end + + # Print the 10 slowest examples and example groups at the + # end of the spec run, to help surface which specs are running + # particularly slow. + config.profile_examples = 10 + + # Run specs in random order to surface order dependencies. If you find an + # order dependency and want to debug it, you can fix the order by providing + # the seed, which is printed after each run. + # --seed 1234 + config.order = :random + + # Seed global randomization in this process using the `--seed` CLI option. + # Setting this allows you to use `--seed` to deterministically reproduce + # test failures related to randomization by passing the same `--seed` value + # as the one that triggered the failure. + Kernel.srand config.seed +=end +end diff --git a/views/blackjack.erb b/views/blackjack.erb new file mode 100644 index 0000000..0ae2859 --- /dev/null +++ b/views/blackjack.erb @@ -0,0 +1,7 @@ +

Player hand: <%= player_cards %>

+

Dealer hand: <%= dealer_cards %>

+

Player bankroll:

+

Bet amounts:

+ + +

Deck: <%= deck %> diff --git a/views/blackjackhit.erb b/views/blackjackhit.erb new file mode 100644 index 0000000..3245c4b --- /dev/null +++ b/views/blackjackhit.erb @@ -0,0 +1 @@ +hit diff --git a/views/layout.erb b/views/layout.erb new file mode 100644 index 0000000..3a15e52 --- /dev/null +++ b/views/layout.erb @@ -0,0 +1,12 @@ + + + + + + + Sinatra Blackjack + + + <%= yield %> + + diff --git a/views/welcome.erb b/views/welcome.erb new file mode 100644 index 0000000..94a3f5a --- /dev/null +++ b/views/welcome.erb @@ -0,0 +1,3 @@ +

Welcome to Sinatra Blackjack!!

+ +Let's play! From 62758670ffbae059438648767b3cc2a9326330fb Mon Sep 17 00:00:00 2001 From: Morgan Martin Date: Fri, 22 Jul 2016 13:09:07 -0400 Subject: [PATCH 2/9] two views --- views/blackjackhit.erb | 8 +++++++- views/{blackjack.erb => blackjackstay.erb} | 0 2 files changed, 7 insertions(+), 1 deletion(-) rename views/{blackjack.erb => blackjackstay.erb} (100%) diff --git a/views/blackjackhit.erb b/views/blackjackhit.erb index 3245c4b..30a6167 100644 --- a/views/blackjackhit.erb +++ b/views/blackjackhit.erb @@ -1 +1,7 @@ -hit +

Player hand: <%= player_cards %>

+

Dealer hand: <%= dealer_cards.first %>

+

Player bankroll:

+

Bet amounts:

+ + +

Deck: <%= deck %> diff --git a/views/blackjack.erb b/views/blackjackstay.erb similarity index 100% rename from views/blackjack.erb rename to views/blackjackstay.erb From 747b09aaf3dc439db2fb3c5fa871322cc70c5db3 Mon Sep 17 00:00:00 2001 From: essian Date: Fri, 22 Jul 2016 18:29:56 +0100 Subject: [PATCH 3/9] adds hit route --- app.rb | 19 ++++++++++++++++++- views/blackjack.erb | 13 +++++++++++++ views/blackjackhit.erb | 7 ------- views/blackjackstay.erb | 7 ------- 4 files changed, 31 insertions(+), 15 deletions(-) create mode 100644 views/blackjack.erb delete mode 100644 views/blackjackhit.erb delete mode 100644 views/blackjackstay.erb diff --git a/app.rb b/app.rb index bff2f30..f7b7cce 100644 --- a/app.rb +++ b/app.rb @@ -17,9 +17,26 @@ player_cards = session['player_cards'] = deal(deck, 2) dealer_cards = session['dealer_cards'] = deal(deck, 2) erb :blackjack, locals: { deck: deck, player_cards: player_cards, - dealer_cards: dealer_cards } + dealer_cards: dealer_cards.first } end +post '/blackjack/hit' do +player_cards = session['player_cards'] +dealer_cards = session['dealer_cards'] +deck = session['deck'] +player_cards << deck.pop + +erb :blackjack, locals: {player_cards: player_cards, + dealer_cards: dealer_cards.first} + + end + # welcome -> form :player_name, creates a game instance, assigns the player name +get 'blackjack/stay' do +#do stuff + + erb :blackjack, locals: {player_cards: player_cards, dealer_cards: dealer_cards, message: message} + +end \ No newline at end of file diff --git a/views/blackjack.erb b/views/blackjack.erb new file mode 100644 index 0000000..01eb3ac --- /dev/null +++ b/views/blackjack.erb @@ -0,0 +1,13 @@ +

Player hand: <%= player_cards %>

+

Dealer hand: <%= dealer_cards %>

+

Player bankroll:

+

Bet amounts:

+ +
+ +
+
+ + + +
diff --git a/views/blackjackhit.erb b/views/blackjackhit.erb deleted file mode 100644 index 30a6167..0000000 --- a/views/blackjackhit.erb +++ /dev/null @@ -1,7 +0,0 @@ -

Player hand: <%= player_cards %>

-

Dealer hand: <%= dealer_cards.first %>

-

Player bankroll:

-

Bet amounts:

- - -

Deck: <%= deck %> diff --git a/views/blackjackstay.erb b/views/blackjackstay.erb deleted file mode 100644 index 0ae2859..0000000 --- a/views/blackjackstay.erb +++ /dev/null @@ -1,7 +0,0 @@ -

Player hand: <%= player_cards %>

-

Dealer hand: <%= dealer_cards %>

-

Player bankroll:

-

Bet amounts:

- - -

Deck: <%= deck %> From 56451132f90962c28c6d3e3ac5561b22d86da68a Mon Sep 17 00:00:00 2001 From: Morgan Martin Date: Fri, 22 Jul 2016 13:55:25 -0400 Subject: [PATCH 4/9] stuff --- app.rb | 26 +++++++++++++------------- helpers/blackjack_helper.rb | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 13 deletions(-) diff --git a/app.rb b/app.rb index f7b7cce..113abd2 100644 --- a/app.rb +++ b/app.rb @@ -16,27 +16,27 @@ deck = session['deck'] = new_deck.shuffle player_cards = session['player_cards'] = deal(deck, 2) dealer_cards = session['dealer_cards'] = deal(deck, 2) - erb :blackjack, locals: { deck: deck, player_cards: player_cards, + erb :blackjack, locals: { player_cards: player_cards, dealer_cards: dealer_cards.first } end -post '/blackjack/hit' do -player_cards = session['player_cards'] -dealer_cards = session['dealer_cards'] -deck = session['deck'] -player_cards << deck.pop - -erb :blackjack, locals: {player_cards: player_cards, - dealer_cards: dealer_cards.first} - +post '/blackjack/hit' do + session['player_cards'] << deal(session['deck'], 1) + player_cards = session['player_cards'] + if bust?(player_cards) + redirect('/blackjack/stay') + else + erb :blackjack, locals: {player_cards: session['player_cards'], + dealer_cards: session['dealer_cards'].first } end +end # welcome -> form :player_name, creates a game instance, assigns the player name -get 'blackjack/stay' do -#do stuff +get '/blackjack/stay' do + #do stuff erb :blackjack, locals: {player_cards: player_cards, dealer_cards: dealer_cards, message: message} -end \ No newline at end of file +end diff --git a/helpers/blackjack_helper.rb b/helpers/blackjack_helper.rb index cb24bc9..2dfb40b 100644 --- a/helpers/blackjack_helper.rb +++ b/helpers/blackjack_helper.rb @@ -3,6 +3,41 @@ def deal(deck, num) deck.pop(num) end + + def calc_value(cards) + cards.map do |card| + if card[0].is_a?(Integer) + card[0] + elsif card[0] == :ace + 11 + else + 10 + end + end.reduce(:+) + end + + def bust?(cards) + total_value = calc_value(cards) + if total_value > 21 && no_aces?(cards) + true + elsif total_value < 21 + false + else + num_of_aces.times do + total_value -= 10 + end + total_value > 21 + end + end + + def no_aces?(cards) + !cards.map { |card| card[0] }.any? { |card| card == :ace } + end + + def num_of_aces(cards) + cards.select { |cards| card[0] == :ace }.length + end + def new_deck return_array = [] ranks.product(suits) From 66c569d6cc6409191c98a21f832d93c9501f2df7 Mon Sep 17 00:00:00 2001 From: essian Date: Fri, 22 Jul 2016 19:43:48 +0100 Subject: [PATCH 5/9] corrects for aces --- app.rb | 17 +++++++++++++---- helpers/blackjack_helper.rb | 26 +++++++++++++++++--------- views/blackjack.erb | 5 +++++ 3 files changed, 35 insertions(+), 13 deletions(-) diff --git a/app.rb b/app.rb index 113abd2..80123e0 100644 --- a/app.rb +++ b/app.rb @@ -17,17 +17,18 @@ player_cards = session['player_cards'] = deal(deck, 2) dealer_cards = session['dealer_cards'] = deal(deck, 2) erb :blackjack, locals: { player_cards: player_cards, - dealer_cards: dealer_cards.first } + dealer_cards: dealer_cards.first, wording: nil } end post '/blackjack/hit' do session['player_cards'] << deal(session['deck'], 1) player_cards = session['player_cards'] + # player_cards = [[:ace,:spade],[:ace, :club],[10, :spade]] if bust?(player_cards) redirect('/blackjack/stay') else erb :blackjack, locals: {player_cards: session['player_cards'], - dealer_cards: session['dealer_cards'].first } + dealer_cards: session['dealer_cards'].first, wording: nil } end end @@ -35,8 +36,16 @@ # welcome -> form :player_name, creates a game instance, assigns the player name get '/blackjack/stay' do - #do stuff - erb :blackjack, locals: {player_cards: player_cards, dealer_cards: dealer_cards, message: message} + dealer_cards = session['dealer_cards'] + while calc_value(dealer_cards) < 17 + dealer_cards << deal[session['deck'], 1] + end + compare_cards(dealer_cards, session['player_cards']) + + #do stuff + wording = "You lose" + erb :blackjack, locals: {player_cards: session['player_cards'], + dealer_cards: session['dealer_cards'], wording: wording } end diff --git a/helpers/blackjack_helper.rb b/helpers/blackjack_helper.rb index 2dfb40b..58bdb2d 100644 --- a/helpers/blackjack_helper.rb +++ b/helpers/blackjack_helper.rb @@ -4,7 +4,7 @@ def deal(deck, num) end - def calc_value(cards) + def cards_total(cards) cards.map do |card| if card[0].is_a?(Integer) card[0] @@ -14,19 +14,27 @@ def calc_value(cards) 10 end end.reduce(:+) + + end + + def correct_for_aces(cards, total) + num_of_aces(cards).times do + total -=10 if total > 21 + end + total + end + + def calc_value(cards) + total = cards_total(cards) + correct_for_aces(cards, total) end def bust?(cards) total_value = calc_value(cards) - if total_value > 21 && no_aces?(cards) + if total_value > 21 true - elsif total_value < 21 + elsif total_value <= 21 false - else - num_of_aces.times do - total_value -= 10 - end - total_value > 21 end end @@ -35,7 +43,7 @@ def no_aces?(cards) end def num_of_aces(cards) - cards.select { |cards| card[0] == :ace }.length + cards.select { |card| card[0] == :ace }.length end def new_deck diff --git a/views/blackjack.erb b/views/blackjack.erb index 01eb3ac..11859cb 100644 --- a/views/blackjack.erb +++ b/views/blackjack.erb @@ -11,3 +11,8 @@ + + + +

<%= wording %>

+ From 06edb8320e0115c38b19a82cad244e979f0eda27 Mon Sep 17 00:00:00 2001 From: Morgan Martin Date: Fri, 22 Jul 2016 15:04:26 -0400 Subject: [PATCH 6/9] mostly --- app.rb | 9 +++------ helpers/blackjack_helper.rb | 28 ++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/app.rb b/app.rb index 80123e0..1728b8d 100644 --- a/app.rb +++ b/app.rb @@ -16,6 +16,7 @@ deck = session['deck'] = new_deck.shuffle player_cards = session['player_cards'] = deal(deck, 2) dealer_cards = session['dealer_cards'] = deal(deck, 2) + erb :blackjack, locals: { player_cards: player_cards, dealer_cards: dealer_cards.first, wording: nil } end @@ -36,15 +37,11 @@ # welcome -> form :player_name, creates a game instance, assigns the player name get '/blackjack/stay' do - dealer_cards = session['dealer_cards'] while calc_value(dealer_cards) < 17 - dealer_cards << deal[session['deck'], 1] + dealer_cards << deal( session['deck'], 1 ) end - compare_cards(dealer_cards, session['player_cards']) - - #do stuff - wording = "You lose" + wording = final_result(dealer_cards, session['player_cards']) erb :blackjack, locals: {player_cards: session['player_cards'], dealer_cards: session['dealer_cards'], wording: wording } diff --git a/helpers/blackjack_helper.rb b/helpers/blackjack_helper.rb index 58bdb2d..dec5b03 100644 --- a/helpers/blackjack_helper.rb +++ b/helpers/blackjack_helper.rb @@ -3,6 +3,34 @@ def deal(deck, num) deck.pop(num) end + def state(cards) + case calc_value(cards) + when calc_value(cards) > 21 + :busted + when calc_value(cards) == 21 && cards.length == 2 + :blackjack + else + calc_value(cards) + end + end + + def final_result(dealer_cards, player_cards) + dealer_state = state(dealer_cards) + player_state = state(player_cards) + if dealer_state == player_state + "It was a tie!!" + elsif player_state == :busted + "You lost!" + elsif dealer_state == :blackjack + "The dealer had blackjack! You lose..." + elsif player_state == :blackjack + "You had blackjack, you win!" + elsif player_state < dealer_state + "You lose..." + elsif dealer_state < player_state + "You win!" + end + end def cards_total(cards) cards.map do |card| From 2ce7bc6021ffccce1090293cc6dd353b1dc078d1 Mon Sep 17 00:00:00 2001 From: essian Date: Fri, 22 Jul 2016 22:42:06 +0100 Subject: [PATCH 7/9] bugfix --- app.rb | 7 ++++--- helpers/blackjack_helper.rb | 12 ++++++------ views/blackjack.erb | 2 +- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/app.rb b/app.rb index 1728b8d..060be21 100644 --- a/app.rb +++ b/app.rb @@ -12,17 +12,16 @@ end get '/blackjack' do - turn = session['turn'] = 'player' deck = session['deck'] = new_deck.shuffle player_cards = session['player_cards'] = deal(deck, 2) - dealer_cards = session['dealer_cards'] = deal(deck, 2) + dealer_cards = session['dealer_cards'] = deal(deck, 2) erb :blackjack, locals: { player_cards: player_cards, dealer_cards: dealer_cards.first, wording: nil } end post '/blackjack/hit' do - session['player_cards'] << deal(session['deck'], 1) + session['player_cards'] << deal(session['deck'], 1).flatten player_cards = session['player_cards'] # player_cards = [[:ace,:spade],[:ace, :club],[10, :spade]] if bust?(player_cards) @@ -46,3 +45,5 @@ dealer_cards: session['dealer_cards'], wording: wording } end + + diff --git a/helpers/blackjack_helper.rb b/helpers/blackjack_helper.rb index dec5b03..c643ce1 100644 --- a/helpers/blackjack_helper.rb +++ b/helpers/blackjack_helper.rb @@ -4,10 +4,9 @@ def deal(deck, num) end def state(cards) - case calc_value(cards) - when calc_value(cards) > 21 + if calc_value(cards) > 21 :busted - when calc_value(cards) == 21 && cards.length == 2 + elsif calc_value(cards) == 21 && cards.length == 2 :blackjack else calc_value(cards) @@ -17,6 +16,7 @@ def state(cards) def final_result(dealer_cards, player_cards) dealer_state = state(dealer_cards) player_state = state(player_cards) + binding.pry if dealer_state == player_state "It was a tie!!" elsif player_state == :busted @@ -66,9 +66,9 @@ def bust?(cards) end end - def no_aces?(cards) - !cards.map { |card| card[0] }.any? { |card| card == :ace } - end + # def no_aces?(cards) + # !cards.map { |card| card[0] }.any? { |card| card == :ace } + # end def num_of_aces(cards) cards.select { |card| card[0] == :ace }.length diff --git a/views/blackjack.erb b/views/blackjack.erb index 11859cb..d91c2ae 100644 --- a/views/blackjack.erb +++ b/views/blackjack.erb @@ -6,7 +6,7 @@
-
+ From 1ee59f5ac8013fbb838c8efaf4fe661413745ff7 Mon Sep 17 00:00:00 2001 From: essian Date: Fri, 22 Jul 2016 23:48:14 +0100 Subject: [PATCH 8/9] starts including bets --- app.rb | 7 ++++++- views/blackjack.erb | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/app.rb b/app.rb index 060be21..2d71fb2 100644 --- a/app.rb +++ b/app.rb @@ -12,6 +12,8 @@ end get '/blackjack' do + session['purse'] ||= 1000 + deck = session['deck'] = new_deck.shuffle player_cards = session['player_cards'] = deal(deck, 2) dealer_cards = session['dealer_cards'] = deal(deck, 2) @@ -23,7 +25,6 @@ post '/blackjack/hit' do session['player_cards'] << deal(session['deck'], 1).flatten player_cards = session['player_cards'] - # player_cards = [[:ace,:spade],[:ace, :club],[10, :spade]] if bust?(player_cards) redirect('/blackjack/stay') else @@ -46,4 +47,8 @@ end +get '/bet' do + + end + diff --git a/views/blackjack.erb b/views/blackjack.erb index d91c2ae..c553978 100644 --- a/views/blackjack.erb +++ b/views/blackjack.erb @@ -15,4 +15,6 @@

<%= wording %>

+ + Play Hand From 8224774b7b4980d790bc099a736517739343b2f4 Mon Sep 17 00:00:00 2001 From: Morgan Martin Date: Fri, 22 Jul 2016 19:25:12 -0400 Subject: [PATCH 9/9] add betting --- app.rb | 21 ++++++++++++--------- helpers/blackjack_helper.rb | 12 +++++++++++- views/.#welcome.erb | 1 + views/bet.erb | 4 ++++ views/blackjack.erb | 7 ++----- views/welcome.erb | 2 +- 6 files changed, 31 insertions(+), 16 deletions(-) create mode 120000 views/.#welcome.erb create mode 100644 views/bet.erb diff --git a/app.rb b/app.rb index 2d71fb2..1977d11 100644 --- a/app.rb +++ b/app.rb @@ -8,18 +8,19 @@ helpers BlackjackHelper get '/' do + session.clear + session['purse'] ||= 1000 erb :welcome end get '/blackjack' do - session['purse'] ||= 1000 - deck = session['deck'] = new_deck.shuffle player_cards = session['player_cards'] = deal(deck, 2) - dealer_cards = session['dealer_cards'] = deal(deck, 2) + dealer_cards = session['dealer_cards'] = deal(deck, 2) erb :blackjack, locals: { player_cards: player_cards, - dealer_cards: dealer_cards.first, wording: nil } + dealer_cards: dealer_cards.first, wording: nil, + bet: session['bet'], purse: session['purse']} end post '/blackjack/hit' do @@ -38,7 +39,7 @@ # welcome -> form :player_name, creates a game instance, assigns the player name get '/blackjack/stay' do dealer_cards = session['dealer_cards'] - while calc_value(dealer_cards) < 17 + while calc_value(dealer_cards) < 17 dealer_cards << deal( session['deck'], 1 ) end wording = final_result(dealer_cards, session['player_cards']) @@ -47,8 +48,10 @@ end -get '/bet' do - - end - +get '/bet' do + erb :bet +end +post '/bet' do + handle_bet(params[:bet], session['purse']) +end diff --git a/helpers/blackjack_helper.rb b/helpers/blackjack_helper.rb index c643ce1..5473460 100644 --- a/helpers/blackjack_helper.rb +++ b/helpers/blackjack_helper.rb @@ -3,6 +3,17 @@ def deal(deck, num) deck.pop(num) end + def handle_bet(bet, purse) + bet = bet.to_i + if bet < purse + session['bet'] = bet + session['purse'] -= bet + redirect('/blackjack') + else + get :bet, locals: { message: "Please enter valid bet" } + end + end + def state(cards) if calc_value(cards) > 21 :busted @@ -16,7 +27,6 @@ def state(cards) def final_result(dealer_cards, player_cards) dealer_state = state(dealer_cards) player_state = state(player_cards) - binding.pry if dealer_state == player_state "It was a tie!!" elsif player_state == :busted diff --git a/views/.#welcome.erb b/views/.#welcome.erb new file mode 120000 index 0000000..e849b28 --- /dev/null +++ b/views/.#welcome.erb @@ -0,0 +1 @@ +morgan@mbox.Home.4028:1469188764 \ No newline at end of file diff --git a/views/bet.erb b/views/bet.erb new file mode 100644 index 0000000..997ae44 --- /dev/null +++ b/views/bet.erb @@ -0,0 +1,4 @@ + + + + diff --git a/views/blackjack.erb b/views/blackjack.erb index c553978..1dd8e15 100644 --- a/views/blackjack.erb +++ b/views/blackjack.erb @@ -1,7 +1,7 @@

Player hand: <%= player_cards %>

Dealer hand: <%= dealer_cards %>

-

Player bankroll:

-

Bet amounts:

+

Player bankroll:<%= purse %>

+

Bet amounts: <%= bet %>

@@ -15,6 +15,3 @@

<%= wording %>

- - Play Hand - diff --git a/views/welcome.erb b/views/welcome.erb index 94a3f5a..b31400e 100644 --- a/views/welcome.erb +++ b/views/welcome.erb @@ -1,3 +1,3 @@

Welcome to Sinatra Blackjack!!

-Let's play! +Play Hand