twenty_one 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 097ec3f9595fb36938715267bb2fdb70cf8027c8
4
+ data.tar.gz: 73f084d40fbe6660fe8bbf4922fbe93706f8c3f8
5
+ SHA512:
6
+ metadata.gz: 1993da48eb109d1b4c398836ae1c327f915f1cf8cac619d90b90c417e205b8f0c59f9ef5bb49727ab55ccc45f7e91ce7837893d64f372fd5b8facf421628602a
7
+ data.tar.gz: 5ef4b0b47e205911b1dc0cea8e6e4fb4cac033a700767c660385395e419da2a69ffb8d17ec266717c6c1c72add04eaf29d355867f52ad6604f4e54aaf766959f
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in twenty_one.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 pori
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,111 @@
1
+ # TwentyOne
2
+
3
+ A simple command-line implementation of _21_, better known as _blackjack_.
4
+
5
+ ## Installation
6
+
7
+ Just install the gem:
8
+
9
+ $ gem install twenty_one
10
+
11
+ ## Usage
12
+
13
+ To start a new game. Simply execute:
14
+
15
+ $ 21
16
+
17
+ ### Tests
18
+
19
+ Testing was done with rspec. If the you cloned the project run tests with:
20
+
21
+ $ rspec
22
+
23
+ ### Game Rules
24
+
25
+ #### Terms
26
+
27
+ * "blackjack" is a hand worth 21
28
+ * "bust" is a loss
29
+ * "push" is a tie between the player's hand and the dealer's hand
30
+ * "shoe" is a stack of decks mixed together
31
+ * "hit" drawing a single card from the shoe
32
+ * "stand" ending a turn
33
+ * "hole" the card that the dealer keeps hidden
34
+ * "hand" the cards a player poses
35
+ * "showdown" when the player's hand is pitted against the player's hand
36
+
37
+ #### Goal
38
+
39
+ The goal of the game is to draw a hand with a value greater than the dealer's as long as it is not greater than 21.
40
+
41
+ #### Phases
42
+
43
+ 1. Bet
44
+ * The player will state the amount (in dollars) they want to bet
45
+ 2. Deal cards
46
+ * The player and the dealer are each hit with two cards
47
+ * The dealer's second card will be the hole
48
+ 3. Player turn
49
+ * Player can choose to hit
50
+ * Player ends with a stand
51
+ * A hand exceeding 21 is an automatic bust
52
+ 4. Dealer turn
53
+ * The dealer reveals the hole card
54
+ * The dealer will hit if their hand is worth less than 21
55
+ * If the dealer busts and the player did not bust, the player wins
56
+ * Otherwise, it is a push
57
+ 5. Showdown
58
+ * If the player has a hand worth more than the dealer, the player wins.
59
+ * Otherwise, the dealer wins
60
+
61
+ ### Cards
62
+
63
+ * 52 cards are represented
64
+ * Regular cards are valued at whatever number they hold
65
+ * Face cards are worth 10
66
+ * Ace cards are worth 1 or 11
67
+ * Players can choose whichever they like
68
+ * Dealers must choose whichever is appropriate to surpass 17
69
+ * A player can choose to hit when it is their turn
70
+ * If a hit causes a hand higher than 21, the player automatically busts
71
+ * A player can choose to stand when it is their turn
72
+
73
+ #### Chips
74
+
75
+ * White chips are worth $1
76
+ * Red chips are worth $5
77
+ * Green chips are worth $25
78
+ * Black chips are worth $100
79
+
80
+ #### Player
81
+
82
+ * A player will start with 100 total chips
83
+ * 50 white chips
84
+ * 25 red chips
85
+ * 15 green chips
86
+ * 10 black chips
87
+ * Bets will be filled sequentially from highest value chips to lowest
88
+ * A regular win will give the player double what theu bet in chips
89
+ * A blackjack will win the player 2.5 times what they bet in chips
90
+ * A bust means the player will not get back their chips
91
+
92
+ #### Dealer
93
+
94
+ * A dealer's hand must be no less than 17
95
+ * If the hand is worth less than 17, the dealer must hit until it is 17 or greater
96
+ * If a dealer busts and the player has not, then player wins the round
97
+
98
+ ## Planned Features
99
+
100
+ * Multiple players
101
+ * An option to play as the dealer
102
+ * Saving player stats to a local SQLite database
103
+ * Socket-based multiplayer
104
+
105
+ ## Contributing
106
+
107
+ 1. Fork it ( https://github.com/pori/twenty_one/fork )
108
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
109
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
110
+ 4. Push to the branch (`git push origin my-new-feature`)
111
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
data/bin/21 ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "pathname"
4
+
5
+ bin_file = Pathname.new(__FILE__).realpath
6
+
7
+ $:.unshift File.expand_path("../../lib/", bin_file)
8
+
9
+ require "twenty_one/game"
10
+
11
+ TwentyOne::Game.play
@@ -0,0 +1,21 @@
1
+ require "twenty_one/face_card"
2
+
3
+ module TwentyOne
4
+ class AceCard < FaceCard
5
+ @@LOWER_VALUE = 1
6
+ @@UPPER_VALUE = 11
7
+
8
+ def initialize(suit)
9
+ super suit, :ace
10
+ @value = @@LOWER_VALUE
11
+ end
12
+
13
+ def use_upper
14
+ @value = @@UPPER_VALUE
15
+ end
16
+
17
+ def use_lower
18
+ @value = @@LOWER_VALUE
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,44 @@
1
+ require "twenty_one/chip"
2
+ require "twenty_one/player"
3
+
4
+ module TwentyOne
5
+ class Bet
6
+ attr_reader :chips
7
+
8
+ def initialize()
9
+ @chips = []
10
+ end
11
+
12
+ def present(chips)
13
+ @chips = chips
14
+ end
15
+
16
+ def value
17
+ Chip.get_amount(@chips)
18
+ end
19
+
20
+ def payout(type)
21
+ res = []
22
+
23
+ if type == :twenty_one
24
+ payout_generator = Player.new "Temporary player"
25
+
26
+ payout_generator.make_bet value * 2.5
27
+
28
+ res.concat payout_generator.bet.chips
29
+ payout_generator = nil
30
+ elsif type == :push
31
+ res.concat @chips
32
+ else
33
+ 2.times do res.concat @chips end
34
+ end
35
+
36
+ @chips = []
37
+ res
38
+ end
39
+
40
+ def clear
41
+ @chips = []
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,14 @@
1
+ module TwentyOne
2
+ class Card
3
+ attr_reader :suit, :value
4
+
5
+ def initialize(suit, value = nil)
6
+ @suit = suit
7
+ @value = value
8
+ end
9
+
10
+ def to_s
11
+ "#{@value} of #{@suit}"
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,40 @@
1
+ module TwentyOne
2
+ class Chip
3
+ attr_reader :color, :value
4
+
5
+ def initialize(color)
6
+ @color = color
7
+
8
+ case color
9
+ when :white
10
+ @value = 1
11
+ when :red
12
+ @value = 5
13
+ when :green
14
+ @value = 25
15
+ when :black
16
+ @value = 100
17
+ end
18
+ end
19
+
20
+ def self.generate_chips(color, total)
21
+ set = []
22
+
23
+ total.times do
24
+ set.push Chip.new(color)
25
+ end
26
+
27
+ set
28
+ end
29
+
30
+ def self.get_amount(chips)
31
+ amount = 0
32
+
33
+ chips.each do |chip|
34
+ amount += chip.value
35
+ end
36
+
37
+ amount
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,48 @@
1
+ require "twenty_one/player"
2
+
3
+ module TwentyOne
4
+ class Dealer < Player
5
+ attr_reader :shoe
6
+
7
+ def initialize(name, shoe)
8
+ super name
9
+
10
+ @shoe = shoe
11
+ end
12
+
13
+ def showdown(player)
14
+ if player.hand.value == @hand.value && player.hand.value <= 21
15
+ player.deal_bet :push
16
+
17
+ @pushes += 1
18
+
19
+ return :push
20
+ elsif @hand.value <= 21 && player.hand.value < @hand.value || player.hand.value > 21
21
+ @chips.push player.bet.chips
22
+
23
+ player.deal_bet :bust
24
+
25
+ @wins += 1
26
+
27
+ return :bust
28
+ else
29
+ win_type = :win
30
+
31
+ if player.hand.value == 21
32
+ player.deal_bet :twenty_one
33
+ win_type = :twenty_one
34
+ else
35
+ player.deal_bet :win
36
+ end
37
+
38
+ @busts += 1
39
+
40
+ return win_type
41
+ end
42
+ end
43
+
44
+ def hit(player)
45
+ player.hand.cards.push shoe.pop
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,45 @@
1
+ require 'twenty_one/card'
2
+ require 'twenty_one/face_card'
3
+ require 'twenty_one/ace_card'
4
+
5
+ module TwentyOne
6
+ class Deck
7
+ @@DECK_LENGTH = 52
8
+ attr_reader :cards
9
+
10
+ def initialize
11
+ @cards = []
12
+
13
+ @cards.concat generate_suit(:clubs)
14
+ @cards.concat generate_suit(:diamonds)
15
+ @cards.concat generate_suit(:hearts)
16
+ @cards.concat generate_suit(:spades)
17
+ end
18
+
19
+ def shuffle
20
+ @cards.shuffle!
21
+ end
22
+
23
+ def draw
24
+ @cards.shift
25
+ end
26
+
27
+ private
28
+
29
+ def generate_suit(suit)
30
+ set = []
31
+
32
+ set.push AceCard.new(suit)
33
+
34
+ for i in 2..@@DECK_LENGTH / 4 - 3
35
+ set.push Card.new suit, i
36
+ end
37
+
38
+ set.push FaceCard.new suit, :jack
39
+ set.push FaceCard.new suit, :queen
40
+ set.push FaceCard.new suit, :king
41
+
42
+ set
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,16 @@
1
+ require 'twenty_one/card'
2
+
3
+ module TwentyOne
4
+ class FaceCard < Card
5
+ attr_reader :name
6
+
7
+ def initialize(suit, name)
8
+ super suit, 10
9
+ @name = name
10
+ end
11
+
12
+ def to_s
13
+ "#{@name} of #{@suit}"
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,143 @@
1
+ require "twenty_one/player"
2
+ require "twenty_one/dealer"
3
+ require "twenty_one/deck"
4
+ require "twenty_one/ace_card"
5
+
6
+ module TwentyOne
7
+ class Game
8
+ @@BLACKJACK = 21
9
+ @@DEALER_MIN = 17
10
+ @@MAX_BET = 20
11
+ @@MIN_BET = 1
12
+ @@SHOE_DECKS_COUNT = 4
13
+
14
+ def self.play
15
+ @playing = true
16
+ @phase = :bet
17
+ @player = Player.new "Alex"
18
+
19
+ shoe = []
20
+
21
+ @@SHOE_DECKS_COUNT.times do
22
+ shoe.concat Deck.new.shuffle
23
+ end
24
+
25
+ @dealer = Dealer.new "Harold", shoe
26
+
27
+ puts "Welcome to the twenty_one table! Today's dealer is #{@dealer.name}"
28
+ puts "Press any key to begin the game..."
29
+ gets
30
+
31
+ while @playing
32
+ case @phase
33
+ when :bet
34
+ puts "How much would you like to bet? (minimum of $1)"
35
+ amount = gets.chomp.to_i
36
+
37
+ if Chip.get_amount(@player.chips) == 0
38
+ puts "Oh man! You're completely out of money! It's time you see a specialist..."
39
+ @pahse = :gameover
40
+ elsif Chip.get_amount(@player.chips) <= amount
41
+ puts "Woah! You don't have enough money to bet that amount."
42
+ elsif amount > 0
43
+ @phase = :deal
44
+ end
45
+ when :deal
46
+ @player.make_bet amount
47
+
48
+ puts "Deal!"
49
+
50
+ # Deal cards
51
+ 2.times do @dealer.hit(@player) end
52
+ 2.times do @dealer.hit(@dealer) end
53
+
54
+ puts "You have:"
55
+
56
+ @player.hand.cards.each { |card| puts card }
57
+
58
+ puts "The dealer has a #{@dealer.hand.cards.first.to_s} and one card face-down"
59
+
60
+ @phase = :player_turn
61
+ when :side_rules
62
+ #TODO: Side Rules
63
+ when :player_turn
64
+ puts "What would you like to do? hit, stand"
65
+ choice = gets.chomp
66
+
67
+ case choice
68
+ when "hit"
69
+ @dealer.hit @player
70
+
71
+ puts "You got a #{@player.hand.cards.last.to_s}"
72
+
73
+ if @player.hand.cards.last.is_a?(AceCard) && @player.hand.cards.last.name == :ace
74
+ puts "You got an #{@player.hand.cards.last.to_s}!"
75
+ puts "Would you like it to value 1 or 11?"
76
+ new_ace_value = gets
77
+
78
+ case new_ace_value
79
+ when "1"
80
+ @player.hand.cards.last.use_lower
81
+ when "11"
82
+ @player.hand.cards.last.use_upper
83
+ end
84
+
85
+ puts "Your ace's new value is #{@player.hand.cards.last.value}"
86
+ end
87
+
88
+ if @player.hand.value > @@BLACKJACK
89
+ puts "Aaaaah shucks! You have more than 21 which means you lose."
90
+ @phase = :results
91
+ end
92
+ when "stand"
93
+ puts "Alright! It's the dealer's turn."
94
+ @phase = :showdown
95
+ end
96
+ when :dealer_turn
97
+ when :showdown
98
+ puts "The dealer reveals his card!"
99
+ puts "It's a #{@dealer.hand.cards.last.to_s}"
100
+
101
+ while @dealer.hand.value < @@DEALER_MIN && @dealer.hand.value != @@BLACKJACK
102
+ @dealer.hit(@dealer)
103
+
104
+ puts "The dealer drew a #{@dealer.hand.cards.last.to_s}"
105
+ end
106
+
107
+ result = @dealer.showdown(@player)
108
+
109
+ case result
110
+ when :twenty_one
111
+ puts "TwentyOne!"
112
+ when :win
113
+ puts "You won!"
114
+ when :bust
115
+ puts "You lost!"
116
+ when :push
117
+ puts "Tie!"
118
+ end
119
+
120
+ @phase = :results
121
+ when :results
122
+ puts "Here are your game stats:"
123
+ puts "Chips: #{@player.chips.size}"
124
+ puts "Total value: $#{Chip.get_amount(@player.chips)}"
125
+ puts "TwentyOnes: #{@player.twenty_ones}"
126
+ puts "Wins: #{@player.wins}"
127
+ puts "Busts: #{@player.busts}"
128
+ puts "Pushes: #{@player.pushes}"
129
+
130
+ puts "Play again?"
131
+ answer = gets.chomp
132
+
133
+ case answer
134
+ when "no"
135
+ @playing = false
136
+ when "yes"
137
+ @phase = :bet
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,25 @@
1
+ require "twenty_one/card"
2
+
3
+ module TwentyOne
4
+ class Hand
5
+ attr_reader :cards
6
+
7
+ def initialize(cards = [])
8
+ @cards = cards
9
+ end
10
+
11
+ def clear
12
+ @cards = []
13
+ end
14
+
15
+ def value
16
+ count = 0
17
+
18
+ @cards.each do |card|
19
+ count += card.value
20
+ end
21
+
22
+ count
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,84 @@
1
+ require "twenty_one/chip"
2
+ require "twenty_one/hand"
3
+ require "twenty_one/bet"
4
+
5
+ module TwentyOne
6
+ class Player
7
+ @@STARTING_CHIPS = 100
8
+ attr_reader :name, :chips, :twenty_ones, :wins, :busts, :pushes, :bet, :hand
9
+ attr_accessor :choice
10
+
11
+ def initialize(name)
12
+ @name = name
13
+ @twenty_ones = 0
14
+ @wins = 0
15
+ @busts = 0
16
+ @pushes = 0
17
+ @bet = Bet.new
18
+ @hand = Hand.new
19
+ @chips = Chip.generate_chips(:white, 50)
20
+ .concat Chip.generate_chips(:red, 25)
21
+ .concat Chip.generate_chips(:green, 15)
22
+ .concat Chip.generate_chips(:black, 10)
23
+ end
24
+
25
+ def make_bet(amount)
26
+ while @bet.value < amount
27
+ distance_to_total = amount - @bet.value
28
+
29
+ if distance_to_total >= 100
30
+ chip = take_chip :black
31
+ elsif distance_to_total >= 25
32
+ chip = take_chip :green
33
+ elsif distance_to_total >= 5
34
+ chip = take_chip :red
35
+ else
36
+ chip = take_chip :white
37
+ end
38
+
39
+ if chip.nil?
40
+ return false
41
+ end
42
+
43
+ @bet.chips.push chip
44
+ end
45
+
46
+ true
47
+ end
48
+
49
+ def deal_bet(result)
50
+ case result
51
+ when :twenty_one
52
+ @wins += 1
53
+ @twenty_ones += 1
54
+ @chips.concat @bet.payout(:twenty_one)
55
+ when :win
56
+ @wins += 1
57
+ @chips.concat @bet.payout(:win)
58
+ when :bust
59
+ @busts += 1
60
+ when :push
61
+ @pushes += 1
62
+ @chips.concat @bet.payout(:push)
63
+ end
64
+
65
+ @hand.clear
66
+ @bet.clear
67
+ end
68
+
69
+ private
70
+
71
+ def take_chip(color)
72
+ idx = @chips.index { |chip| chip.color == color }
73
+
74
+ if not idx.nil? then
75
+ temp = @chips[idx].clone
76
+ @chips.delete_at idx
77
+
78
+ return temp
79
+ end
80
+
81
+ nil
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,3 @@
1
+ module TwentyOne
2
+ VERSION = "0.1.0"
3
+ end
data/lib/twenty_one.rb ADDED
@@ -0,0 +1,5 @@
1
+ require "twenty_one/version"
2
+
3
+ module TwentyOne
4
+ # Your code goes here...
5
+ end
Binary file
Binary file
Binary file
@@ -0,0 +1,29 @@
1
+ require "twenty_one/ace_card"
2
+
3
+ include TwentyOne
4
+
5
+ describe AceCard do
6
+ before(:each) do
7
+ @ace = AceCard.new :club
8
+ end
9
+
10
+ it "should have a value of 1 or 11" do
11
+ expect(@ace.value).to eq(1 || 11)
12
+ end
13
+
14
+ describe "#use_upper" do
15
+ it "should use the higher Ace value" do
16
+ @ace.use_upper
17
+
18
+ expect(@ace.value).to eq(11)
19
+ end
20
+ end
21
+
22
+ describe "#use_lower" do
23
+ it "should use the lower Ace value" do
24
+ @ace.use_lower
25
+
26
+ expect(@ace.value).to eq(1)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,65 @@
1
+ require "twenty_one/bet"
2
+ require "twenty_one/chip"
3
+ require "twenty_one/player"
4
+
5
+ include TwentyOne
6
+
7
+ describe Bet do
8
+ before(:each) do
9
+ @bet = Bet.new
10
+ end
11
+
12
+ it "should start with an empty chip set" do
13
+ expect(@bet.chips).to eq([])
14
+ end
15
+
16
+ describe "#present(chips)" do
17
+ it "should take in some chips" do
18
+ @bet.present [Chip.new(:white), Chip.new(:red)]
19
+
20
+ expect(@bet.chips).to_not eq([])
21
+ end
22
+ end
23
+
24
+ describe "#value()" do
25
+ it "should get the value of bet's chips" do
26
+ temp_bet = Bet.new
27
+
28
+ temp_bet.present [Chip.new(:white), Chip.new(:red)]
29
+
30
+ expect(temp_bet.value).to_not eq(0)
31
+ end
32
+ end
33
+
34
+ describe "#payout(player)" do
35
+ it "should give back double the originally bet chips for a regular win" do
36
+ chips = @bet.chips
37
+
38
+ chips.concat @bet.chips
39
+
40
+ expect(@bet.payout(:win)).to eq(chips)
41
+ end
42
+
43
+ it "should give back two and a half times the originally bet chips for a twenty_one" do
44
+
45
+ end
46
+
47
+ it "should increase a player's chip count" do
48
+ temp_player = Player.new "Alex"
49
+ bet = Bet.new
50
+ bet.present [Chip.new(:white), Chip.new(:red)]
51
+
52
+ temp_player.chips.concat bet.payout(:win)
53
+
54
+ expect(temp_player.chips.size).to be > 100
55
+ end
56
+ end
57
+
58
+ describe "#clear()" do
59
+ it "should clear out the bet's chips" do
60
+ @bet.clear
61
+
62
+ expect(@bet.value).to eq(0)
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,15 @@
1
+ require "twenty_one/card"
2
+
3
+ include TwentyOne
4
+
5
+ describe Card do
6
+
7
+ before(:each) do
8
+ @card = Card.new :spades, 2
9
+ end
10
+
11
+ it "should have a type corresponding to a playing card" do
12
+ expect(@card.suit).to eq(:spades)
13
+ end
14
+
15
+ end
@@ -0,0 +1,47 @@
1
+ require 'twenty_one/chip'
2
+
3
+ include TwentyOne
4
+
5
+ describe Chip do
6
+
7
+ it 'should value $1 if it is white' do
8
+ white = Chip.new :white
9
+
10
+ expect(white.value).to eq(1)
11
+ end
12
+
13
+ it 'should value $5 if it is red' do
14
+ red = Chip.new :red
15
+
16
+ expect(red.value).to eq(5)
17
+ end
18
+
19
+ it 'should value $25 if it is green' do
20
+ green = Chip.new :green
21
+
22
+ expect(green.value).to eq(25)
23
+ end
24
+
25
+ it 'should value $100 if it is black' do
26
+ black = Chip.new :black
27
+
28
+ expect(black.value).to eq(100)
29
+ end
30
+
31
+ describe '#generate_chips(color, amount)' do
32
+ it 'should generate a set of chips of a specific color' do
33
+ chips = Chip.generate_chips :white, 50
34
+
35
+ expect(chips.size).to eq(50)
36
+ end
37
+ end
38
+
39
+ describe '#get_amount(chips)' do
40
+ it 'should get the total amount of money a set of chips is worth' do
41
+ chips = [Chip.new(:white), Chip.new(:red), Chip.new(:green), Chip.new(:black)]
42
+
43
+ expect(Chip.get_amount(chips)).to eq(131)
44
+ end
45
+ end
46
+
47
+ end
@@ -0,0 +1,75 @@
1
+ require "twenty_one/dealer"
2
+ require "twenty_one/player"
3
+ require "twenty_one/deck"
4
+ require "twenty_one/card"
5
+ require "twenty_one/ace_card"
6
+ require "twenty_one/face_card"
7
+
8
+ include TwentyOne
9
+
10
+ describe Dealer do
11
+ before(:each) do
12
+ shoe = []
13
+ 4.times do
14
+ shoe.concat Deck.new.cards
15
+ end
16
+
17
+ @dealer = Dealer.new "Ken Thompson", shoe
18
+ @player = Player.new "Dennis Ritchie"
19
+ end
20
+
21
+ it "should start with a pretty big selection of cards" do
22
+ expect(@dealer.shoe.size).to be >= 52
23
+ end
24
+
25
+ describe "#showdown(player)" do
26
+ it "should push if there is a tie" do
27
+ @player.make_bet 100
28
+
29
+ @player.hand.cards.concat [Card.new(:diamonds, 2), Card.new(:spades, 3)]
30
+ @dealer.hand.cards.concat [Card.new(:hearts, 2), Card.new(:clubs, 3)]
31
+
32
+ result = @dealer.showdown @player
33
+
34
+ expect(result).to eq(:push)
35
+ end
36
+
37
+ it "should report a bust if the player loses" do
38
+ @player.make_bet 100
39
+
40
+ ace_card = AceCard.new :clubs
41
+
42
+ ace_card.use_upper
43
+
44
+ @dealer.hit @player
45
+ @dealer.hand.cards.concat [ace_card, Card.new(:clubs, 6)]
46
+
47
+ result = @dealer.showdown @player
48
+
49
+ expect(result).to eq(:bust)
50
+ end
51
+
52
+ it "should report a win if the player wins" do
53
+ @player.make_bet 100
54
+
55
+ ace_card = AceCard.new :clubs
56
+
57
+ ace_card.use_upper
58
+
59
+ @player.hand.cards.concat [ace_card, Card.new(:spade, 5)]
60
+ @dealer.hit(@dealer)
61
+
62
+ result = @dealer.showdown @player
63
+
64
+ expect(result).to eq(:win)
65
+ end
66
+ end
67
+
68
+ describe "#hit(player)" do
69
+ it "should add a card to the player's hand" do
70
+ @dealer.hit @player
71
+
72
+ expect(@player.hand.cards.size).to be > 0
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,33 @@
1
+ require 'twenty_one/deck'
2
+
3
+ include TwentyOne
4
+
5
+ describe Deck do
6
+
7
+ before(:each) do
8
+ @deck = Deck.new
9
+ end
10
+
11
+ it 'should have a set of 52 cards' do
12
+ expect(@deck.cards.size).to eq(52)
13
+ end
14
+
15
+ describe '#shuffle' do
16
+ it 'should be able to shuffle the deck' do
17
+ original_card_order = @deck.cards.clone
18
+
19
+ @deck.shuffle
20
+
21
+ expect(@deck.cards).to_not eq(original_card_order)
22
+ end
23
+ end
24
+
25
+ describe '#draw' do
26
+ it 'should be able to draw a random card and discard it' do
27
+ random_card = @deck.draw
28
+
29
+ expect(@deck.cards.first).to_not eq(random_card)
30
+ end
31
+ end
32
+
33
+ end
@@ -0,0 +1,13 @@
1
+ require 'twenty_one/face_card'
2
+
3
+ include TwentyOne
4
+
5
+ describe FaceCard do
6
+
7
+ it 'should create a playing card value at 10' do
8
+ face_card = FaceCard.new :club, :king
9
+
10
+ expect(face_card.value).to eq(10)
11
+ end
12
+
13
+ end
@@ -0,0 +1,135 @@
1
+ require "twenty_one/player"
2
+ #require "twenty_one/bet"
3
+ require "twenty_one/hand"
4
+
5
+ include TwentyOne
6
+
7
+ describe Player do
8
+ before(:each) do
9
+ @player = Player.new "Pori"
10
+ end
11
+
12
+ it "should have a name" do
13
+ expect(@player.name).to eq("Pori")
14
+ end
15
+
16
+ it "should start with 100 chips" do
17
+ expect(@player.chips.size).to eq(100)
18
+ end
19
+
20
+ it "should start with no wins" do
21
+ expect(@player.wins).to eq(0)
22
+ end
23
+
24
+ it "should start with no losses" do
25
+ expect(@player.busts).to eq(0)
26
+ end
27
+
28
+ it "should start with no ties" do
29
+ expect(@player.busts).to eq(0)
30
+ end
31
+
32
+ it "should start with an empty bet" do
33
+ expect(@player.bet.value).to eq(0)
34
+ end
35
+
36
+ it "should start with no cards in hand" do
37
+ expect(@player.hand.value).to eq(Hand.new.value)
38
+ end
39
+
40
+ it "should start with no choices made" do
41
+ expect(@player.choice).to eq(nil)
42
+ end
43
+
44
+ describe "#make_bet(amount)" do
45
+ it "should remove some chips from the player for the bet" do
46
+ chips_count = @player.chips.size
47
+ @player.make_bet 100
48
+
49
+ expect(chips_count).to_not eq(@player.chips.size)
50
+ end
51
+
52
+ it "should have added chips to the bet" do
53
+ @player.make_bet 100
54
+
55
+ expect(@player.bet.value).to_not eq(0)
56
+ end
57
+
58
+ it "should successfully make a bet" do
59
+ temp_player = Player.new "Sergey Brin"
60
+ bet = temp_player.make_bet 100
61
+
62
+ expect(bet).to eq(true)
63
+ end
64
+
65
+ it "should fail if too high of a bet is made" do
66
+ temp_player = Player.new "Yukihiro"
67
+ bet = temp_player.make_bet 10000
68
+
69
+ expect(bet).to eq(false)
70
+ end
71
+ end
72
+
73
+ describe "#deal_bet(result)" do
74
+ it "should add to the player's win column" do
75
+ @player.deal_bet :win
76
+
77
+ expect(@player.wins).to eq(1)
78
+ end
79
+
80
+ it "should empty the player's bet" do
81
+ @player.deal_bet :win
82
+
83
+ expect(@player.bet.value).to eq(0)
84
+ end
85
+
86
+ it "should empty the player's hand" do
87
+ @player.deal_bet :win
88
+
89
+ expect(@player.hand.value).to eq(0)
90
+ end
91
+
92
+ it "should add the player's winnings to the chips set" do
93
+ @player.make_bet 100
94
+ @player.deal_bet :win
95
+
96
+ expect(@player.chips.size).to be > 100
97
+ end
98
+
99
+ it "should add to the player's loss column" do
100
+ temp_player = Player.new "Ken Thompson"
101
+
102
+ temp_player.make_bet 100
103
+ temp_player.deal_bet :bust
104
+
105
+ expect(temp_player.busts).to eq(1)
106
+ end
107
+
108
+ it "should lose chips when a player busts" do
109
+ temp_player = Player.new "Dennis Ritchie"
110
+
111
+ temp_player.make_bet 100
112
+ temp_player.deal_bet :bust
113
+
114
+ expect(temp_player.chips.size).to be < 100
115
+ end
116
+
117
+ it "should increase the tie column where there is a push" do
118
+ temp_player = Player.new "Linus Torvalds"
119
+
120
+ temp_player.make_bet 100
121
+ temp_player.deal_bet :push
122
+
123
+ expect(temp_player.pushes).to eq(1)
124
+ end
125
+
126
+ it "should restore the original amount of chips where there is a push" do
127
+ temp_player = Player.new "Richard Stallman"
128
+
129
+ temp_player.make_bet 100
130
+ temp_player.deal_bet :push
131
+
132
+ expect(temp_player.chips.size).to be(100)
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,78 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # The generated `.rspec` file contains `--require spec_helper` which will cause this
4
+ # file to always be loaded, without a need to explicitly require it in any files.
5
+ #
6
+ # Given that it is always loaded, you are encouraged to keep this file as
7
+ # light-weight as possible. Requiring heavyweight dependencies from this file
8
+ # will add to the boot time of your test suite on EVERY test run, even for an
9
+ # individual file that may not need all of that loaded. Instead, make a
10
+ # separate helper file that requires this one and then use it only in the specs
11
+ # that actually need it.
12
+ #
13
+ # The `.rspec` file also contains a few flags that are not defaults but that
14
+ # users commonly want.
15
+ #
16
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
17
+ RSpec.configure do |config|
18
+ # The settings below are suggested to provide a good initial experience
19
+ # with RSpec, but feel free to customize to your heart's content.
20
+ =begin
21
+ # These two settings work together to allow you to limit a spec run
22
+ # to individual examples or groups you care about by tagging them with
23
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
24
+ # get run.
25
+ config.filter_run :focus
26
+ config.run_all_when_everything_filtered = true
27
+
28
+ # Many RSpec users commonly either run the entire suite or an individual
29
+ # file, and it's useful to allow more verbose output when running an
30
+ # individual spec file.
31
+ if config.files_to_run.one?
32
+ # Use the documentation formatter for detailed output,
33
+ # unless a formatter has already been configured
34
+ # (e.g. via a command-line flag).
35
+ config.default_formatter = 'doc'
36
+ end
37
+
38
+ # Print the 10 slowest examples and example groups at the
39
+ # end of the spec run, to help surface which specs are running
40
+ # particularly slow.
41
+ config.profile_examples = 10
42
+
43
+ # Run specs in random order to surface order dependencies. If you find an
44
+ # order dependency and want to debug it, you can fix the order by providing
45
+ # the seed, which is printed after each run.
46
+ # --seed 1234
47
+ config.order = :random
48
+
49
+ # Seed global randomization in this process using the `--seed` CLI option.
50
+ # Setting this allows you to use `--seed` to deterministically reproduce
51
+ # test failures related to randomization by passing the same `--seed` value
52
+ # as the one that triggered the failure.
53
+ Kernel.srand config.seed
54
+
55
+ # rspec-expectations config goes here. You can use an alternate
56
+ # assertion/expectation library such as wrong or the stdlib/minitest
57
+ # assertions if you prefer.
58
+ config.expect_with :rspec do |expectations|
59
+ # Enable only the newer, non-monkey-patching expect syntax.
60
+ # For more details, see:
61
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
62
+ expectations.syntax = :expect
63
+ end
64
+
65
+ # rspec-mocks config goes here. You can use an alternate test double
66
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
67
+ config.mock_with :rspec do |mocks|
68
+ # Enable only the newer, non-monkey-patching expect syntax.
69
+ # For more details, see:
70
+ # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
71
+ mocks.syntax = :expect
72
+
73
+ # Prevents you from mocking or stubbing a method that does not exist on
74
+ # a real object. This is generally recommended.
75
+ mocks.verify_partial_doubles = true
76
+ end
77
+ =end
78
+ end
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'twenty_one/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "twenty_one"
8
+ spec.version = TwentyOne::VERSION
9
+ spec.authors = ["pori"]
10
+ spec.email = ["porialex@gmail.com"]
11
+ spec.summary = %q{A simple command-line implementation of 21, better known as blackjack.}
12
+ spec.description = %q{}
13
+ spec.homepage = "https://github.com/pori/twenty_one"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.6"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec"
24
+ end
metadata ADDED
@@ -0,0 +1,130 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: twenty_one
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - pori
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-07-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: ''
56
+ email:
57
+ - porialex@gmail.com
58
+ executables:
59
+ - '21'
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - ".gitignore"
64
+ - Gemfile
65
+ - LICENSE.txt
66
+ - README.md
67
+ - Rakefile
68
+ - bin/21
69
+ - lib/twenty_one.rb
70
+ - lib/twenty_one/ace_card.rb
71
+ - lib/twenty_one/bet.rb
72
+ - lib/twenty_one/card.rb
73
+ - lib/twenty_one/chip.rb
74
+ - lib/twenty_one/dealer.rb
75
+ - lib/twenty_one/deck.rb
76
+ - lib/twenty_one/face_card.rb
77
+ - lib/twenty_one/game.rb
78
+ - lib/twenty_one/hand.rb
79
+ - lib/twenty_one/player.rb
80
+ - lib/twenty_one/version.rb
81
+ - spec/lib/.ace_card_spec.rb.swp
82
+ - spec/lib/.card_spec.rb.swp
83
+ - spec/lib/.dealer_spec.rb.swp
84
+ - spec/lib/ace_card_spec.rb
85
+ - spec/lib/bet_spec.rb
86
+ - spec/lib/card_spec.rb
87
+ - spec/lib/chip_spec.rb
88
+ - spec/lib/dealer_spec.rb
89
+ - spec/lib/deck_spec.rb
90
+ - spec/lib/face_card_spec.rb
91
+ - spec/lib/player_spec.rb
92
+ - spec/spec_helper.rb
93
+ - twenty_one.gemspec
94
+ homepage: https://github.com/pori/twenty_one
95
+ licenses:
96
+ - MIT
97
+ metadata: {}
98
+ post_install_message:
99
+ rdoc_options: []
100
+ require_paths:
101
+ - lib
102
+ required_ruby_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ required_rubygems_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ requirements: []
113
+ rubyforge_project:
114
+ rubygems_version: 2.2.2
115
+ signing_key:
116
+ specification_version: 4
117
+ summary: A simple command-line implementation of 21, better known as blackjack.
118
+ test_files:
119
+ - spec/lib/.ace_card_spec.rb.swp
120
+ - spec/lib/.card_spec.rb.swp
121
+ - spec/lib/.dealer_spec.rb.swp
122
+ - spec/lib/ace_card_spec.rb
123
+ - spec/lib/bet_spec.rb
124
+ - spec/lib/card_spec.rb
125
+ - spec/lib/chip_spec.rb
126
+ - spec/lib/dealer_spec.rb
127
+ - spec/lib/deck_spec.rb
128
+ - spec/lib/face_card_spec.rb
129
+ - spec/lib/player_spec.rb
130
+ - spec/spec_helper.rb