ruby-blackjack 1.0.1 → 1.0.2
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 +4 -4
- data/README.md +7 -8
- data/bin/blackjack +6 -6
- data/src/blackjack_cli.rb +99 -97
- data/src/game.rb +161 -161
- data/src/objects/card.rb +96 -96
- data/src/strings/string.rb +17 -17
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9279031775dc13d7be33caeeb7a70f33160fb8f7
|
4
|
+
data.tar.gz: 9685e0dd224ef292144310559abd7b424e67cb19
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 80712c4b61ab0c7bed72c36bfe6ff3b37f49489b9c40e772e7d405c99eea80899d5fdc27c89a988e6a0a5ac695ce1c93c6f02dfc9d112f25ce302790d7627d06
|
7
|
+
data.tar.gz: a3013fdf6da05ba6394d76d708bfce721d790aebfbea70959ba5e84cf841190c6d2dfe2d46589a9f20e694b915002a4b82847d15215ff1a92ed2267cb506b929
|
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
|master|develop|
|
4
4
|
|:----:|:-----:|
|
5
|
-
|[](https://gitlab.namibsun.net/namibsun/ruby/blackjack/commits/master)|[](https://gitlab.namibsun.net/namibsun/ruby/blackjack/commits/develop)|
|
6
6
|
|
7
7
|

|
8
8
|
|
@@ -16,10 +16,9 @@ Then start the program using the command `blackjack`
|
|
16
16
|
|
17
17
|
## Further Information
|
18
18
|
|
19
|
-
* [Changelog](
|
20
|
-
* [License (GPLv3)](
|
21
|
-
* [Gitlab](https://gitlab.namibsun.net/
|
22
|
-
* [Github](https://github.com/namboy94/
|
23
|
-
* [
|
24
|
-
* [
|
25
|
-
* [Rubygems site](https://rubygems.org/gems/ruby-blackjack)
|
19
|
+
* [Changelog](CHANGELOG)
|
20
|
+
* [License (GPLv3)](LICENSE)
|
21
|
+
* [Gitlab](https://gitlab.namibsun.net/namibsun/ruby/blackjack)
|
22
|
+
* [Github](https://github.com/namboy94/blackjack)
|
23
|
+
* [Progstats](https://progstats.namibsun.net/projects/blackjack)
|
24
|
+
* [Rubygems](https://rubygems.org/gems/ruby-blackjack)
|
data/bin/blackjack
CHANGED
@@ -1,22 +1,22 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
# Copyright 2016
|
2
|
+
# Copyright 2016 Hermann Krumrey <hermann@krumreyh.com>
|
3
3
|
#
|
4
|
-
# This file is part of blackjack.
|
4
|
+
# This file is part of ruby-blackjack.
|
5
5
|
#
|
6
|
-
# blackjack is free software: you can redistribute it and/or modify
|
6
|
+
# ruby-blackjack is free software: you can redistribute it and/or modify
|
7
7
|
# it under the terms of the GNU General Public License as published by
|
8
8
|
# the Free Software Foundation, either version 3 of the License, or
|
9
9
|
# (at your option) any later version.
|
10
10
|
#
|
11
|
-
# blackjack is distributed in the hope that it will be useful,
|
11
|
+
# ruby-blackjack is distributed in the hope that it will be useful,
|
12
12
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
13
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
14
|
# GNU General Public License for more details.
|
15
15
|
#
|
16
16
|
# You should have received a copy of the GNU General Public License
|
17
|
-
# along with blackjack.
|
17
|
+
# along with ruby-blackjack. If not, see <http://www.gnu.org/licenses/>.
|
18
18
|
|
19
19
|
require_relative('../src/blackjack_cli')
|
20
20
|
|
21
21
|
cli = BlackjackCli.new
|
22
|
-
cli.game_loop
|
22
|
+
cli.game_loop
|
data/src/blackjack_cli.rb
CHANGED
@@ -1,128 +1,130 @@
|
|
1
|
-
# Copyright 2016
|
1
|
+
# Copyright 2016 Hermann Krumrey <hermann@krumreyh.com>
|
2
2
|
#
|
3
|
-
# This file is part of blackjack.
|
3
|
+
# This file is part of ruby-blackjack.
|
4
4
|
#
|
5
|
-
# blackjack is free software: you can redistribute it and/or modify
|
5
|
+
# ruby-blackjack is free software: you can redistribute it and/or modify
|
6
6
|
# it under the terms of the GNU General Public License as published by
|
7
7
|
# the Free Software Foundation, either version 3 of the License, or
|
8
8
|
# (at your option) any later version.
|
9
9
|
#
|
10
|
-
# blackjack is distributed in the hope that it will be useful,
|
10
|
+
# ruby-blackjack is distributed in the hope that it will be useful,
|
11
11
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
12
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
13
|
# GNU General Public License for more details.
|
14
14
|
#
|
15
15
|
# You should have received a copy of the GNU General Public License
|
16
|
-
# along with blackjack.
|
16
|
+
# along with ruby-blackjack. If not, see <http://www.gnu.org/licenses/>.
|
17
17
|
|
18
18
|
require_relative('game.rb')
|
19
19
|
require_relative('strings/string.rb')
|
20
20
|
|
21
21
|
# Class that offers an interactive interface for the user to play blackjack
|
22
22
|
class BlackjackCli
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
23
|
+
# Constructor for the BlackJackCli class
|
24
|
+
# @return [nil]
|
25
|
+
def initialize
|
26
|
+
@default_text_color = [LIGHT_GRAY_BG, BLACK_FG]
|
27
|
+
puts " Blackjack CLI started \n\n".set_attributes(@default_text_color)
|
28
|
+
@blackjack = Game.new
|
29
|
+
end
|
30
|
+
|
31
|
+
# the main game loop.
|
32
|
+
# It continually asks the user for a new choice of either hit or stand
|
33
|
+
# @return [nil]
|
34
|
+
def game_loop
|
35
|
+
new_game = true
|
36
|
+
|
37
|
+
while true
|
38
|
+
if new_game
|
39
|
+
print_result(@blackjack.start)
|
40
|
+
new_game = false
|
30
41
|
end
|
31
42
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
new_game = false
|
41
|
-
end
|
42
|
-
|
43
|
-
result = nil
|
44
|
-
case get_play_command
|
45
|
-
when "stand\n"
|
46
|
-
result = @blackjack.stand
|
47
|
-
when "hit\n"
|
48
|
-
result = @blackjack.hit
|
49
|
-
else
|
50
|
-
puts 'Something went wrong'
|
51
|
-
end
|
52
|
-
|
53
|
-
print_result(result)
|
54
|
-
|
55
|
-
if result[2] == 'win'
|
56
|
-
puts ' You won :D '.set_attributes([GREEN_BG, BLACK_FG])
|
57
|
-
elsif result[2] == 'loss'
|
58
|
-
puts ' You lost :( '.set_attributes([RED_BG, BLACK_FG])
|
59
|
-
elsif result[2] == 'draw'
|
60
|
-
puts " It's a draw ".set_attributes([YELLOW_BG, BLACK_FG])
|
61
|
-
end
|
62
|
-
|
63
|
-
if result[2] != 'undecided'
|
64
|
-
new_game = true
|
65
|
-
pause_when_game_ends
|
66
|
-
end
|
67
|
-
|
68
|
-
end
|
43
|
+
result = nil
|
44
|
+
case get_play_command
|
45
|
+
when "stand\n"
|
46
|
+
result = @blackjack.stand
|
47
|
+
when "hit\n"
|
48
|
+
result = @blackjack.hit
|
49
|
+
else
|
50
|
+
puts 'Something went wrong'
|
69
51
|
end
|
70
52
|
|
71
|
-
|
72
|
-
# @return [nil]
|
73
|
-
def pause_when_game_ends
|
74
|
-
puts ' Press enter to start a new game '.set_attributes(@default_text_color)
|
75
|
-
gets
|
76
|
-
end
|
53
|
+
print_result(result)
|
77
54
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
puts format_cards(result[0])
|
85
|
-
puts "\n Dealer Cards: (#{Game.calculate_optimal_card_score(result[1])}) \n"
|
86
|
-
.set_attributes(@default_text_color)
|
87
|
-
puts format_cards(result[1])
|
88
|
-
puts "\n"
|
55
|
+
if result[2] == 'win'
|
56
|
+
puts ' You won :D '.set_attributes([GREEN_BG, BLACK_FG])
|
57
|
+
elsif result[2] == 'loss'
|
58
|
+
puts ' You lost :( '.set_attributes([RED_BG, BLACK_FG])
|
59
|
+
elsif result[2] == 'draw'
|
60
|
+
puts " It's a draw ".set_attributes([YELLOW_BG, BLACK_FG])
|
89
61
|
end
|
90
62
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
def format_cards(cards)
|
95
|
-
cards_string = ''
|
96
|
-
|
97
|
-
card_parts = []
|
98
|
-
cards.each { |card|
|
99
|
-
card_parts.push(card.get_ascii_card.split("\n"))
|
100
|
-
}
|
101
|
-
|
102
|
-
if card_parts.length == 0
|
103
|
-
return ''
|
104
|
-
end
|
105
|
-
|
106
|
-
(0...card_parts[0].length).each { |i|
|
107
|
-
card_parts.each { |card_part|
|
108
|
-
cards_string += card_part[i] + ' '
|
109
|
-
}
|
110
|
-
cards_string += "\n"
|
111
|
-
}
|
112
|
-
cards_string
|
63
|
+
if result[2] != 'undecided'
|
64
|
+
new_game = true
|
65
|
+
pause_when_game_ends
|
113
66
|
end
|
114
67
|
|
115
|
-
# Gets the user's input on what to do next
|
116
|
-
# @return [string] the (validated) user input
|
117
|
-
def get_play_command
|
118
|
-
puts ' What would you like to do? (hit|stand) '.set_attributes(@default_text_color)
|
119
|
-
input = gets
|
120
|
-
while not input == "hit\n" and not input == "stand\n"
|
121
|
-
puts " Please enter 'hit' or 'stand' ".set_attributes(@default_text_color)
|
122
|
-
input = gets
|
123
68
|
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# This pauses the game until the user presses enter/return
|
72
|
+
# before starting a new game
|
73
|
+
# @return [nil]
|
74
|
+
def pause_when_game_ends
|
75
|
+
puts ' Press enter to start a new game '
|
76
|
+
.set_attributes(@default_text_color)
|
77
|
+
gets
|
78
|
+
end
|
79
|
+
|
80
|
+
# Prints the current game state based on the results of a hit or stand action
|
81
|
+
# @param [Card Array, Card Array] result the result to be displayed
|
82
|
+
# @return [nil]
|
83
|
+
def print_result(result)
|
84
|
+
puts " Player Cards: (#{Game.calculate_optimal_card_score(result[0])}) \n"
|
85
|
+
.set_attributes(@default_text_color)
|
86
|
+
puts format_cards(result[0])
|
87
|
+
puts "\n Dealer Cards: (#{Game.calculate_optimal_card_score(result[1])}) \n"
|
88
|
+
.set_attributes(@default_text_color)
|
89
|
+
puts format_cards(result[1])
|
124
90
|
puts "\n"
|
125
|
-
|
91
|
+
end
|
92
|
+
|
93
|
+
# Formats cards to be displayed side-by-side
|
94
|
+
# @param [Card Array] cards the cards to be displayed
|
95
|
+
# @return [string] a formatted string of all cards side by side
|
96
|
+
def format_cards(cards)
|
97
|
+
cards_string = ''
|
98
|
+
|
99
|
+
card_parts = []
|
100
|
+
cards.each { |card|
|
101
|
+
card_parts.push(card.get_ascii_card.split("\n"))
|
102
|
+
}
|
103
|
+
|
104
|
+
if card_parts.length == 0
|
105
|
+
return ''
|
126
106
|
end
|
127
107
|
|
108
|
+
(0...card_parts[0].length).each { |i|
|
109
|
+
card_parts.each { |card_part|
|
110
|
+
cards_string += card_part[i] + ' '
|
111
|
+
}
|
112
|
+
cards_string += "\n"
|
113
|
+
}
|
114
|
+
cards_string
|
115
|
+
end
|
116
|
+
|
117
|
+
# Gets the user's input on what to do next
|
118
|
+
# @return [string] the (validated) user input
|
119
|
+
def get_play_command
|
120
|
+
puts ' What would you like to do? (hit|stand) '.set_attributes(@default_text_color)
|
121
|
+
input = gets
|
122
|
+
while not input == "hit\n" and not input == "stand\n"
|
123
|
+
puts " Please enter 'hit' or 'stand' ".set_attributes(@default_text_color)
|
124
|
+
input = gets
|
125
|
+
end
|
126
|
+
puts "\n"
|
127
|
+
input
|
128
|
+
end
|
129
|
+
|
128
130
|
end
|
data/src/game.rb
CHANGED
@@ -1,194 +1,194 @@
|
|
1
|
-
# Copyright 2016
|
1
|
+
# Copyright 2016 Hermann Krumrey <hermann@krumreyh.com>
|
2
2
|
#
|
3
|
-
# This file is part of blackjack.
|
4
|
-
#
|
5
|
-
# blackjack is free software: you can redistribute it and/or modify
|
3
|
+
# This file is part of ruby-blackjack.
|
4
|
+
#
|
5
|
+
# ruby-blackjack is free software: you can redistribute it and/or modify
|
6
6
|
# it under the terms of the GNU General Public License as published by
|
7
7
|
# the Free Software Foundation, either version 3 of the License, or
|
8
8
|
# (at your option) any later version.
|
9
|
-
#
|
10
|
-
# blackjack is distributed in the hope that it will be useful,
|
9
|
+
#
|
10
|
+
# ruby-blackjack is distributed in the hope that it will be useful,
|
11
11
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
12
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
13
|
# GNU General Public License for more details.
|
14
|
-
#
|
14
|
+
#
|
15
15
|
# You should have received a copy of the GNU General Public License
|
16
|
-
# along with blackjack.
|
16
|
+
# along with ruby-blackjack. If not, see <http://www.gnu.org/licenses/>.
|
17
17
|
|
18
18
|
require_relative('objects/card.rb')
|
19
19
|
|
20
20
|
# Class that simulates a Blackjack game
|
21
21
|
class Game
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
23
|
+
# Initializes the instance variables used to keep track of the game state
|
24
|
+
# @return [nil]
|
25
|
+
def initialize
|
26
|
+
@deck = generate_deck
|
27
|
+
@used_cards = []
|
28
|
+
@player_cards = []
|
29
|
+
@dealer_cards = []
|
30
|
+
@player_score = 0
|
31
|
+
@dealer_score = 0
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
# Generates a new deck of cards
|
36
|
+
# The deck is shuffled directly after creation
|
37
|
+
# @return [Card Array] the generated deck
|
38
|
+
def generate_deck
|
39
|
+
deck = []
|
40
|
+
suits = %w(spades hearts diamonds clubs)
|
41
|
+
(2...15).each { |i|
|
42
|
+
suits.each { |suit|
|
43
|
+
deck.push(Card.new(suit, i))
|
44
|
+
}
|
45
|
+
}
|
46
|
+
deck.shuffle
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
# Draws a new card
|
51
|
+
# It automatically stocks up the deck with previously used cards if the deck runs out of cards
|
52
|
+
# @return [Card] the newly drawn card
|
53
|
+
def draw_card
|
54
|
+
if @deck.length == 0
|
55
|
+
@deck = @used_cards.shuffle
|
56
|
+
@used_cards = []
|
32
57
|
end
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
58
|
+
@deck.pop
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
# Starts a game of roulette. Each player will draw two cards, the dealer's second card will stay
|
63
|
+
# top down until the player stands
|
64
|
+
# @return [Card Array, Card Array, string] the result of the first few drawings. Refer to evaluate() for details
|
65
|
+
def start
|
66
|
+
# Let the player draw his cards
|
67
|
+
hit
|
68
|
+
hit
|
69
|
+
|
70
|
+
# Let the dealer draw his cards
|
71
|
+
hit(true)
|
72
|
+
result = hit(true)
|
73
|
+
@dealer_cards[1].flip_over # Flip over the card
|
74
|
+
|
75
|
+
result
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
# Draws a new card for a player and immediately evaluates the current state of the game
|
80
|
+
# @param [Object] dealer flag can be set to make the dealer instead of the player draw a card
|
81
|
+
# @return [Card Array, Card Array, string] the result of the drawing. Refer to evaluate() for details
|
82
|
+
def hit(dealer = false)
|
83
|
+
if dealer
|
84
|
+
@dealer_cards.push(draw_card)
|
85
|
+
@dealer_score = self.class.calculate_optimal_card_score(@dealer_cards)
|
86
|
+
else
|
87
|
+
@player_cards.push(draw_card)
|
88
|
+
@player_score = self.class.calculate_optimal_card_score(@player_cards)
|
47
89
|
end
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
90
|
+
evaluate
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
# Stops the user interaction. The cards of the user will no longer change, and now the dealer
|
95
|
+
# draws cards until he is above 16 points. Afterwards, the game state is evaluated
|
96
|
+
# @return [Card Array, Card Array, string] the result of the drawing. Refer to evaluate() for details
|
97
|
+
def stand
|
98
|
+
@dealer_cards[1].flip_over
|
99
|
+
result = [@player_cards.clone, @dealer_cards.clone, 'undecided']
|
100
|
+
while @dealer_score < 17 and result[2] == 'undecided'
|
101
|
+
result = hit(true)
|
59
102
|
end
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
# @return [Card Array, Card Array, string] the result of the first few drawings. Refer to evaluate() for details
|
65
|
-
def start
|
66
|
-
# Let the player draw his cards
|
67
|
-
hit
|
68
|
-
hit
|
69
|
-
|
70
|
-
# Let the dealer draw his cards
|
71
|
-
hit(true)
|
72
|
-
result = hit(true)
|
73
|
-
@dealer_cards[1].flip_over # Flip over the card
|
74
|
-
|
75
|
-
result
|
103
|
+
if result[2] == 'undecided'
|
104
|
+
evaluate(true)
|
105
|
+
else
|
106
|
+
result
|
76
107
|
end
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
108
|
+
end
|
109
|
+
|
110
|
+
|
111
|
+
# Evaluates the current state of the game according to the standard blackjack rules
|
112
|
+
# @param [boolean] player_standing flag that is set to evaluate a game once the player has decided to stand
|
113
|
+
# @return [Card Array, Card Array, string] the player's cards,
|
114
|
+
# the dealer's cards,
|
115
|
+
# a string stating the current status of the match.
|
116
|
+
# Possible Options: 'loss', if the user lost
|
117
|
+
# 'win', if the user won
|
118
|
+
# 'draw', if the game ended in a draw
|
119
|
+
# 'undecided', if the game is not finished
|
120
|
+
def evaluate(player_standing = false)
|
121
|
+
player_cards = @player_cards
|
122
|
+
dealer_cards = @dealer_cards
|
123
|
+
state = 'undecided'
|
124
|
+
if @player_score > 21
|
125
|
+
state = 'loss'
|
126
|
+
elsif @dealer_score > 21
|
127
|
+
state = 'win'
|
128
|
+
elsif player_standing and @player_score > @dealer_score
|
129
|
+
state = 'win'
|
130
|
+
elsif player_standing and @player_score < @dealer_score
|
131
|
+
state = 'loss'
|
132
|
+
elsif player_standing and @player_score == @dealer_score
|
133
|
+
state = 'draw'
|
91
134
|
end
|
92
135
|
|
93
|
-
|
94
|
-
|
95
|
-
# draws cards until he is above 16 points. Afterwards, the game state is evaluated
|
96
|
-
# @return [Card Array, Card Array, string] the result of the drawing. Refer to evaluate() for details
|
97
|
-
def stand
|
98
|
-
@dealer_cards[1].flip_over
|
99
|
-
result = [@player_cards.clone, @dealer_cards.clone, 'undecided']
|
100
|
-
while @dealer_score < 17 and result[2] == 'undecided'
|
101
|
-
result = hit(true)
|
102
|
-
end
|
103
|
-
if result[2] == 'undecided'
|
104
|
-
evaluate(true)
|
105
|
-
else
|
106
|
-
result
|
107
|
-
end
|
136
|
+
if state != 'undecided'
|
137
|
+
player_cards, dealer_cards = cleanup
|
108
138
|
end
|
109
139
|
|
110
|
-
|
111
|
-
|
112
|
-
# @param [boolean] player_standing flag that is set to evaluate a game once the player has decided to stand
|
113
|
-
# @return [Card Array, Card Array, string] the player's cards,
|
114
|
-
# the dealer's cards,
|
115
|
-
# a string stating the current status of the match.
|
116
|
-
# Possible Options: 'loss', if the user lost
|
117
|
-
# 'win', if the user won
|
118
|
-
# 'draw', if the game ended in a draw
|
119
|
-
# 'undecided', if the game is not finished
|
120
|
-
def evaluate(player_standing = false)
|
121
|
-
player_cards = @player_cards
|
122
|
-
dealer_cards = @dealer_cards
|
123
|
-
state = 'undecided'
|
124
|
-
if @player_score > 21
|
125
|
-
state = 'loss'
|
126
|
-
elsif @dealer_score > 21
|
127
|
-
state = 'win'
|
128
|
-
elsif player_standing and @player_score > @dealer_score
|
129
|
-
state = 'win'
|
130
|
-
elsif player_standing and @player_score < @dealer_score
|
131
|
-
state = 'loss'
|
132
|
-
elsif player_standing and @player_score == @dealer_score
|
133
|
-
state = 'draw'
|
134
|
-
end
|
135
|
-
|
136
|
-
if state != 'undecided'
|
137
|
-
player_cards, dealer_cards = cleanup
|
138
|
-
end
|
139
|
-
|
140
|
-
return player_cards, dealer_cards, state
|
141
|
-
end
|
140
|
+
return player_cards, dealer_cards, state
|
141
|
+
end
|
142
142
|
|
143
143
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
end
|
150
|
-
@used_cards += @player_cards + @dealer_cards
|
151
|
-
@player_score = 0
|
152
|
-
@dealer_score = 0
|
153
|
-
old_player_cards = @player_cards.clone
|
154
|
-
old_dealer_cards = @dealer_cards.clone
|
155
|
-
@player_cards = []
|
156
|
-
@dealer_cards = []
|
157
|
-
return old_player_cards, old_dealer_cards
|
144
|
+
# Resets the game to enable starting a new game.
|
145
|
+
# @return [Card Array, Card Array] the user's cards and the dealer's cards
|
146
|
+
def cleanup
|
147
|
+
if @dealer_cards[1].is_flipped
|
148
|
+
@dealer_cards[1].flip_over
|
158
149
|
end
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
150
|
+
@used_cards += @player_cards + @dealer_cards
|
151
|
+
@player_score = 0
|
152
|
+
@dealer_score = 0
|
153
|
+
old_player_cards = @player_cards.clone
|
154
|
+
old_dealer_cards = @dealer_cards.clone
|
155
|
+
@player_cards = []
|
156
|
+
@dealer_cards = []
|
157
|
+
return old_player_cards, old_dealer_cards
|
158
|
+
end
|
159
|
+
|
160
|
+
|
161
|
+
# Calculates the optimal amount of points for blackjack for an array of cards
|
162
|
+
# @param [Card Array] cards the cards to be checked
|
163
|
+
# @return [int] the optimal blackjack value of the cards
|
164
|
+
def self.calculate_optimal_card_score(cards)
|
165
|
+
score = 0
|
166
|
+
aces = 0
|
167
|
+
cards.each { |card|
|
168
|
+
unless card.is_flipped # == if card is not flipped
|
169
|
+
score += card.get_value
|
170
|
+
if card.is_ace
|
171
|
+
aces += 1
|
178
172
|
end
|
179
|
-
|
173
|
+
end
|
174
|
+
}
|
175
|
+
while score > 21 and aces > 0
|
176
|
+
aces -= 1
|
177
|
+
score -= 10
|
180
178
|
end
|
179
|
+
score
|
180
|
+
end
|
181
181
|
|
182
182
|
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
183
|
+
# @return [int] the player's current score
|
184
|
+
def get_player_score
|
185
|
+
@player_score
|
186
|
+
end
|
187
187
|
|
188
188
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
189
|
+
# @return [int] the dealer's current score
|
190
|
+
def get_dealer_score
|
191
|
+
@dealer_score
|
192
|
+
end
|
193
193
|
|
194
194
|
end
|
data/src/objects/card.rb
CHANGED
@@ -1,19 +1,19 @@
|
|
1
|
-
# Copyright 2016
|
1
|
+
# Copyright 2016 Hermann Krumrey <hermann@krumreyh.com>
|
2
2
|
#
|
3
|
-
# This file is part of blackjack.
|
3
|
+
# This file is part of ruby-blackjack.
|
4
4
|
#
|
5
|
-
# blackjack is free software: you can redistribute it and/or modify
|
5
|
+
# ruby-blackjack is free software: you can redistribute it and/or modify
|
6
6
|
# it under the terms of the GNU General Public License as published by
|
7
7
|
# the Free Software Foundation, either version 3 of the License, or
|
8
8
|
# (at your option) any later version.
|
9
9
|
#
|
10
|
-
# blackjack is distributed in the hope that it will be useful,
|
10
|
+
# ruby-blackjack is distributed in the hope that it will be useful,
|
11
11
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
12
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
13
|
# GNU General Public License for more details.
|
14
14
|
#
|
15
15
|
# You should have received a copy of the GNU General Public License
|
16
|
-
# along with blackjack.
|
16
|
+
# along with ruby-blackjack. If not, see <http://www.gnu.org/licenses/>.
|
17
17
|
|
18
18
|
require_relative('../strings/string.rb')
|
19
19
|
|
@@ -22,111 +22,111 @@ require_relative('../strings/string.rb')
|
|
22
22
|
class Card
|
23
23
|
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
suit, @value, display_number, @ace = determine_card_data(type, number)
|
35
|
-
@backside = generate_cardback
|
36
|
-
@flipped = false
|
37
|
-
@ascii_card = format_card(suit, display_number)
|
38
|
-
end
|
25
|
+
# Creates a new card
|
26
|
+
# The constructor generates ASCII art of the card and calculates its blackjack value
|
27
|
+
# The card is also assigned a cardback.
|
28
|
+
# @param [string] type the type of the suit the card belongs to, i.e 'spades', 'hearts' etc.
|
29
|
+
# @param [int] number the number of the card. Numbers 2 through 10 are simply the normal numbers,
|
30
|
+
# 11 is the ace, 12 jack, 13 queen, 14 king
|
31
|
+
# @return [nil]
|
32
|
+
def initialize(type, number)
|
39
33
|
|
34
|
+
suit, @value, display_number, @ace = determine_card_data(type, number)
|
35
|
+
@backside = generate_cardback
|
36
|
+
@flipped = false
|
37
|
+
@ascii_card = format_card(suit, display_number)
|
38
|
+
end
|
40
39
|
|
41
|
-
# Generates an ASCII playing card from the provided information
|
42
|
-
# @param [string] suit the suit of the card
|
43
|
-
# @param [string] number the number of the card (like 'A' for ace or '10' for 10)
|
44
|
-
# @return [string] the ASCII card
|
45
|
-
def format_card(suit, number)
|
46
40
|
|
47
|
-
|
48
|
-
|
49
|
-
|
41
|
+
# Generates an ASCII playing card from the provided information
|
42
|
+
# @param [string] suit the suit of the card
|
43
|
+
# @param [string] number the number of the card (like 'A' for ace or '10' for 10)
|
44
|
+
# @return [string] the ASCII card
|
45
|
+
def format_card(suit, number)
|
50
46
|
|
51
|
-
|
47
|
+
top = '┌───────────┐'
|
48
|
+
empty_row = "| |\n"
|
49
|
+
bottom = '└───────────┘'
|
52
50
|
|
53
|
-
|
54
|
-
ascii_card += empty_row * 2 + "| #{suit} |\n" + empty_row * 2
|
55
|
-
ascii_card += '|' + ' ' * offset + "#{number} |\n#{bottom}"
|
56
|
-
ascii_card.set_attributes([WHITE_BG, BLACK_FG])
|
57
|
-
end
|
51
|
+
offset = 10 - number.length
|
58
52
|
|
53
|
+
ascii_card = "#{top}\n| #{number}" + ' ' * offset + "|\n"
|
54
|
+
ascii_card += empty_row * 2 + "| #{suit} |\n" + empty_row * 2
|
55
|
+
ascii_card += '|' + ' ' * offset + "#{number} |\n#{bottom}"
|
56
|
+
ascii_card.set_attributes([WHITE_BG, BLACK_FG])
|
57
|
+
end
|
59
58
|
|
60
|
-
# Determines the suit of the card, its blackjack value, its number to be shown visually as well as
|
61
|
-
# if the card is an ace.
|
62
|
-
# @param [string] type the suit identifier string ('spades', 'hearts', 'clubs' or 'diamonds')
|
63
|
-
# @param [int] number the number of the card. Should be a number from 1 to 14
|
64
|
-
# @return [string, int, string, boolean] the suit of the card, the blackjack value of the card,
|
65
|
-
# the string representation of the card number and if the card is an ace
|
66
|
-
def determine_card_data(type, number)
|
67
|
-
|
68
|
-
suits = {'spades' => '♠', 'diamonds' => '♦', 'hearts' => '♥', 'clubs' => '♣'}
|
69
|
-
special_cards = {10 => '10', 12 => 'B', 13 => 'Q', 14 => 'K'}
|
70
|
-
|
71
|
-
ace = false
|
72
|
-
|
73
|
-
suit = suits[type]
|
74
|
-
if type == 'spades' or type == 'clubs'
|
75
|
-
suit = suit.set_attributes([BLACK_FG], [WHITE_BG, BLACK_FG])
|
76
|
-
else
|
77
|
-
suit = suit.set_attributes([RED_FG], [WHITE_BG, BLACK_FG])
|
78
|
-
end
|
79
|
-
|
80
|
-
if number < 10 and number != 1
|
81
|
-
value = number
|
82
|
-
display_number = number.to_s
|
83
|
-
elsif number >= 10 and number != 11
|
84
|
-
value = 10
|
85
|
-
display_number = special_cards[number]
|
86
|
-
else
|
87
|
-
ace = true
|
88
|
-
value = 11 # Set value of ace to 11, since we can then just downgrade the value to 1 if the need arises
|
89
|
-
display_number = 'A'
|
90
|
-
end
|
91
|
-
|
92
|
-
return suit, value, display_number, ace
|
93
|
-
end
|
94
59
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
60
|
+
# Determines the suit of the card, its blackjack value, its number to be shown visually as well as
|
61
|
+
# if the card is an ace.
|
62
|
+
# @param [string] type the suit identifier string ('spades', 'hearts', 'clubs' or 'diamonds')
|
63
|
+
# @param [int] number the number of the card. Should be a number from 1 to 14
|
64
|
+
# @return [string, int, string, boolean] the suit of the card, the blackjack value of the card,
|
65
|
+
# the string representation of the card number and if the card is an ace
|
66
|
+
def determine_card_data(type, number)
|
102
67
|
|
103
|
-
|
104
|
-
|
105
|
-
def flip_over
|
106
|
-
cached = @ascii_card
|
107
|
-
@ascii_card = @backside
|
108
|
-
@backside = cached
|
109
|
-
@flipped = !@flipped
|
110
|
-
end
|
68
|
+
suits = {'spades' => '♠', 'diamonds' => '♦', 'hearts' => '♥', 'clubs' => '♣'}
|
69
|
+
special_cards = {10 => '10', 12 => 'B', 13 => 'Q', 14 => 'K'}
|
111
70
|
|
112
|
-
|
113
|
-
def get_ascii_card
|
114
|
-
@ascii_card
|
115
|
-
end
|
71
|
+
ace = false
|
116
72
|
|
117
|
-
|
118
|
-
|
119
|
-
|
73
|
+
suit = suits[type]
|
74
|
+
if type == 'spades' or type == 'clubs'
|
75
|
+
suit = suit.set_attributes([BLACK_FG], [WHITE_BG, BLACK_FG])
|
76
|
+
else
|
77
|
+
suit = suit.set_attributes([RED_FG], [WHITE_BG, BLACK_FG])
|
120
78
|
end
|
121
79
|
|
122
|
-
|
123
|
-
|
124
|
-
|
80
|
+
if number < 10 and number != 1
|
81
|
+
value = number
|
82
|
+
display_number = number.to_s
|
83
|
+
elsif number >= 10 and number != 11
|
84
|
+
value = 10
|
85
|
+
display_number = special_cards[number]
|
86
|
+
else
|
87
|
+
ace = true
|
88
|
+
value = 11 # Set value of ace to 11, since we can then just downgrade the value to 1 if the need arises
|
89
|
+
display_number = 'A'
|
125
90
|
end
|
126
91
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
92
|
+
return suit, value, display_number, ace
|
93
|
+
end
|
94
|
+
|
95
|
+
# Generates a cardback ASCII art
|
96
|
+
# @return [string] the cardback ASCII art
|
97
|
+
def generate_cardback
|
98
|
+
("┌───────────┐\n" +
|
99
|
+
("│░░░░░░░░░░░│\n" * 7) +
|
100
|
+
'└───────────┘').set_attributes([WHITE_BG, BLACK_FG])
|
101
|
+
end
|
102
|
+
|
103
|
+
# Flips over the card so that the cardback is shown instead of the generated ASCII card
|
104
|
+
# @return [nil]
|
105
|
+
def flip_over
|
106
|
+
cached = @ascii_card
|
107
|
+
@ascii_card = @backside
|
108
|
+
@backside = cached
|
109
|
+
@flipped = !@flipped
|
110
|
+
end
|
111
|
+
|
112
|
+
# @return [string] the generated ASCII card, or the cardback if the card is currently flipped
|
113
|
+
def get_ascii_card
|
114
|
+
@ascii_card
|
115
|
+
end
|
116
|
+
|
117
|
+
# @return [int] the blackjack value of the card
|
118
|
+
def get_value
|
119
|
+
@value
|
120
|
+
end
|
121
|
+
|
122
|
+
# @return [boolean] if the card is an ace or not
|
123
|
+
def is_ace
|
124
|
+
@ace
|
125
|
+
end
|
126
|
+
|
127
|
+
# @return [boolean] if the card is flipped or not
|
128
|
+
def is_flipped
|
129
|
+
@flipped
|
130
|
+
end
|
131
131
|
|
132
132
|
end
|
data/src/strings/string.rb
CHANGED
@@ -1,19 +1,19 @@
|
|
1
|
-
# Copyright 2016
|
1
|
+
# Copyright 2016 Hermann Krumrey <hermann@krumreyh.com>
|
2
2
|
#
|
3
|
-
# This file is part of blackjack.
|
3
|
+
# This file is part of ruby-blackjack.
|
4
4
|
#
|
5
|
-
# blackjack is free software: you can redistribute it and/or modify
|
5
|
+
# ruby-blackjack is free software: you can redistribute it and/or modify
|
6
6
|
# it under the terms of the GNU General Public License as published by
|
7
7
|
# the Free Software Foundation, either version 3 of the License, or
|
8
8
|
# (at your option) any later version.
|
9
9
|
#
|
10
|
-
# blackjack is distributed in the hope that it will be useful,
|
10
|
+
# ruby-blackjack is distributed in the hope that it will be useful,
|
11
11
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
12
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
13
|
# GNU General Public License for more details.
|
14
14
|
#
|
15
15
|
# You should have received a copy of the GNU General Public License
|
16
|
-
# along with blackjack.
|
16
|
+
# along with ruby-blackjack. If not, see <http://www.gnu.org/licenses/>.
|
17
17
|
|
18
18
|
# Class that modifies the String class and equips it with a method to set terminal properties of a string
|
19
19
|
class String
|
@@ -25,19 +25,19 @@ class String
|
|
25
25
|
# @return [string] the string with the attributes set
|
26
26
|
def set_attributes(attributes, previous_attributes = [])
|
27
27
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
28
|
+
mode_start_string = ''
|
29
|
+
modes_end_string = "\e[0m"
|
30
|
+
attributes.each { |attribute|
|
31
|
+
mode_start_string += "\e[#{attribute}m"
|
32
|
+
}
|
33
|
+
attributed_string = mode_start_string
|
34
|
+
attributed_string += self.gsub("\n", "#{modes_end_string}\n#{mode_start_string}")
|
35
|
+
attributed_string += modes_end_string
|
36
36
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
37
|
+
previous_attributes.each { |attribute|
|
38
|
+
attributed_string += "\e[#{attribute}m"
|
39
|
+
}
|
40
|
+
attributed_string
|
41
41
|
end
|
42
42
|
|
43
43
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-blackjack
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Hermann Krumrey
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-06-07 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: A Blackjack CLI game
|
14
14
|
email: hermann@krumreyh.com
|
@@ -44,7 +44,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
44
44
|
version: '0'
|
45
45
|
requirements: []
|
46
46
|
rubyforge_project:
|
47
|
-
rubygems_version: 2.
|
47
|
+
rubygems_version: 2.5.2.1
|
48
48
|
signing_key:
|
49
49
|
specification_version: 4
|
50
50
|
summary: Blackjack
|