Oshuma-gambler 0.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.
- data/History.txt +10 -0
- data/Manifest.txt +31 -0
- data/README +1 -0
- data/README.rdoc +1 -0
- data/README.txt +46 -0
- data/Rakefile +47 -0
- data/bin/gambler_client +214 -0
- data/lib/gambler/card.rb +163 -0
- data/lib/gambler/deck.rb +46 -0
- data/lib/gambler/exceptions.rb +26 -0
- data/lib/gambler/game/blackjack.rb +31 -0
- data/lib/gambler/game.rb +9 -0
- data/lib/gambler/player.rb +64 -0
- data/lib/gambler.rb +24 -0
- data/tasks/ditz.rake +43 -0
- data/tasks/docs.rake +70 -0
- data/tasks/git.rake +27 -0
- data/tasks/override_rake_task.rb +16 -0
- data/tasks/rcov.rake +48 -0
- data/tasks/site.rake +51 -0
- data/tasks/util.rb +32 -0
- data/test/game/test_basic_game.rb +32 -0
- data/test/game/test_blackjack.rb +26 -0
- data/test/helper.rb +6 -0
- data/test/suite.rb +5 -0
- data/test/test_card.rb +113 -0
- data/test/test_deck.rb +67 -0
- data/test/test_gambler.rb +14 -0
- data/test/test_player.rb +96 -0
- metadata +91 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
History.txt
|
|
2
|
+
Manifest.txt
|
|
3
|
+
README
|
|
4
|
+
README.rdoc
|
|
5
|
+
README.txt
|
|
6
|
+
Rakefile
|
|
7
|
+
bin/gambler_client
|
|
8
|
+
gambler.gemspec
|
|
9
|
+
lib/gambler.rb
|
|
10
|
+
lib/gambler/card.rb
|
|
11
|
+
lib/gambler/deck.rb
|
|
12
|
+
lib/gambler/exceptions.rb
|
|
13
|
+
lib/gambler/game.rb
|
|
14
|
+
lib/gambler/game/basic_game.rb
|
|
15
|
+
lib/gambler/game/blackjack.rb
|
|
16
|
+
lib/gambler/player.rb
|
|
17
|
+
tasks/ditz.rake
|
|
18
|
+
tasks/docs.rake
|
|
19
|
+
tasks/git.rake
|
|
20
|
+
tasks/override_rake_task.rb
|
|
21
|
+
tasks/rcov.rake
|
|
22
|
+
tasks/site.rake
|
|
23
|
+
tasks/util.rb
|
|
24
|
+
test/game/test_basic_game.rb
|
|
25
|
+
test/game/test_blackjack.rb
|
|
26
|
+
test/helper.rb
|
|
27
|
+
test/suite.rb
|
|
28
|
+
test/test_card.rb
|
|
29
|
+
test/test_deck.rb
|
|
30
|
+
test/test_gambler.rb
|
|
31
|
+
test/test_player.rb
|
data/README
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
README.txt
|
data/README.rdoc
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
README.txt
|
data/README.txt
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
= Gambler
|
|
2
|
+
|
|
3
|
+
Github:: http://github.com/Oshuma/gambler/
|
|
4
|
+
RubyForge:: http://gambler.rubyforge.org/
|
|
5
|
+
|
|
6
|
+
== DESCRIPTION:
|
|
7
|
+
|
|
8
|
+
Gambler is a Ruby library which can be included into other classes/modules.
|
|
9
|
+
It provides an object oriented interface for common gambling games such as
|
|
10
|
+
Blackjack, Poker, etc.
|
|
11
|
+
|
|
12
|
+
== SYNOPSIS:
|
|
13
|
+
|
|
14
|
+
Ruby library to satisfy yet another human addiction.
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
== REQUIREMENTS:
|
|
18
|
+
|
|
19
|
+
Pure Ruby, so far.
|
|
20
|
+
|
|
21
|
+
== INSTALL:
|
|
22
|
+
|
|
23
|
+
# From RubyForge:
|
|
24
|
+
$ gem install gambler
|
|
25
|
+
|
|
26
|
+
# From Github:
|
|
27
|
+
$ gem sources -a http://gems.github.com/ (You only need to do this once.)
|
|
28
|
+
$ gem install Oshuma-gambler
|
|
29
|
+
|
|
30
|
+
== LICENSE:
|
|
31
|
+
|
|
32
|
+
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
|
33
|
+
Version 2, December 2004
|
|
34
|
+
http://sam.zoy.org/wtfpl/
|
|
35
|
+
|
|
36
|
+
Copyright (C) 2008 Dale Campbell <dale@save-state.net>
|
|
37
|
+
|
|
38
|
+
Everyone is permitted to copy and distribute verbatim or modified
|
|
39
|
+
copies of this license document, and changing it is allowed as long
|
|
40
|
+
as the name is changed.
|
|
41
|
+
|
|
42
|
+
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
|
43
|
+
|
|
44
|
+
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
|
45
|
+
|
|
46
|
+
0. You just DO WHAT THE FUCK YOU WANT TO.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'hoe'
|
|
3
|
+
require './lib/gambler'
|
|
4
|
+
require './tasks/override_rake_task'
|
|
5
|
+
require './tasks/util'
|
|
6
|
+
|
|
7
|
+
GAMBLER_ROOT = File.dirname(__FILE__) unless defined? GAMBLER_ROOT
|
|
8
|
+
|
|
9
|
+
Hoe.new('Gambler', Gambler::VERSION) do |g|
|
|
10
|
+
g.developer('Dale Campbell', 'dale@save-state.net')
|
|
11
|
+
g.name = 'gambler'
|
|
12
|
+
g.version = Gambler::VERSION
|
|
13
|
+
g.changes = g.paragraphs_of('History.txt', 0..1).join("\n\n")
|
|
14
|
+
|
|
15
|
+
url = g.paragraphs_of('README.txt', 1).first.split(/\n/)[1].split[1].strip
|
|
16
|
+
g.url = url
|
|
17
|
+
|
|
18
|
+
g.summary = 'Ruby library to satisfy yet another human addiction.'
|
|
19
|
+
g.description = g.paragraphs_of('README.txt', 3..3).join("\n\n")
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Remove un-needed tasks.
|
|
23
|
+
remove_task 'audit'
|
|
24
|
+
remove_task 'generate_key'
|
|
25
|
+
remove_task 'multi'
|
|
26
|
+
remove_task 'post_blog'
|
|
27
|
+
|
|
28
|
+
Dir["#{GAMBLER_ROOT}/tasks/**/*.rake"].sort.each { |task| load task }
|
|
29
|
+
|
|
30
|
+
task :default => [ :test, :rcov ]
|
|
31
|
+
|
|
32
|
+
desc 'Clean up dynamically generated files'
|
|
33
|
+
task :cleanup do
|
|
34
|
+
%w{
|
|
35
|
+
docs:clear
|
|
36
|
+
issues:report:clear
|
|
37
|
+
rcov:clear
|
|
38
|
+
site:clear_local
|
|
39
|
+
}.each do |clean|
|
|
40
|
+
Rake::Task[clean].invoke
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
desc 'Open a console with Gambler loaded'
|
|
45
|
+
task :console do
|
|
46
|
+
sh "irb -rubygems -r ./lib/gambler.rb"
|
|
47
|
+
end
|
data/bin/gambler_client
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
#!/usr/bin/env ruby -w
|
|
2
|
+
|
|
3
|
+
GAMBLER_ROOT = File.join(File.dirname(__FILE__), '..')
|
|
4
|
+
$LOAD_PATH.unshift File.join(GAMBLER_ROOT, 'lib')
|
|
5
|
+
require 'gambler'
|
|
6
|
+
|
|
7
|
+
module Gambler
|
|
8
|
+
# A simple Client which allows you to play around with Gambler.
|
|
9
|
+
# Most of this class can be ignored, as it just sets up the gaming
|
|
10
|
+
# environment. The method to pay attention to is +play_blackjack+.
|
|
11
|
+
# This is the method that actually creates and deals a Blackjack game.
|
|
12
|
+
class Client
|
|
13
|
+
WIDTH = 50
|
|
14
|
+
|
|
15
|
+
$player_quits = false
|
|
16
|
+
|
|
17
|
+
attr_accessor :bots
|
|
18
|
+
attr_accessor :player
|
|
19
|
+
|
|
20
|
+
def initialize
|
|
21
|
+
@player = setup_player
|
|
22
|
+
@bots = Array.new
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# This is the main client menu.
|
|
26
|
+
def menu
|
|
27
|
+
display_header
|
|
28
|
+
until $player_quits do
|
|
29
|
+
display_player_stats
|
|
30
|
+
display_game_menu
|
|
31
|
+
choice = STDIN.gets.chomp
|
|
32
|
+
|
|
33
|
+
case choice
|
|
34
|
+
when '1':
|
|
35
|
+
play_blackjack
|
|
36
|
+
when '2':
|
|
37
|
+
puts 'This game is not implemented yet.'
|
|
38
|
+
when '3':
|
|
39
|
+
puts 'This game is not implemented yet.'
|
|
40
|
+
when /a/i:
|
|
41
|
+
add_ai_player
|
|
42
|
+
when /p/i:
|
|
43
|
+
setup_player
|
|
44
|
+
when /d/i:
|
|
45
|
+
debug_console
|
|
46
|
+
when /q/i:
|
|
47
|
+
$player_quits = true
|
|
48
|
+
exit
|
|
49
|
+
else
|
|
50
|
+
puts 'Invalid choice, dumbass.'
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end # of menu
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
# Add an AI Player as an opponent.
|
|
58
|
+
def add_ai_player
|
|
59
|
+
@bots << setup_player(:bot => true)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Simple debugging console.
|
|
63
|
+
def debug_console
|
|
64
|
+
stop_debug = false
|
|
65
|
+
code = Array.new
|
|
66
|
+
|
|
67
|
+
puts # spacer
|
|
68
|
+
puts '== DEBUG CONSOLE =='
|
|
69
|
+
puts 'Commands:'
|
|
70
|
+
puts ' /run - Quit debugger and run the code.'
|
|
71
|
+
puts ' /show - Show the code currently in the buffer.'
|
|
72
|
+
puts ' /quit - Quit debugger without running the code.'
|
|
73
|
+
|
|
74
|
+
until stop_debug do
|
|
75
|
+
print "eval:#{code.size + 1}> "
|
|
76
|
+
line = STDIN.gets.chomp
|
|
77
|
+
|
|
78
|
+
case line
|
|
79
|
+
when '/run':
|
|
80
|
+
run_code(code)
|
|
81
|
+
stop_debug = true
|
|
82
|
+
when '/show':
|
|
83
|
+
show_code_buffer(code)
|
|
84
|
+
when '/quit':
|
|
85
|
+
stop_debug = true
|
|
86
|
+
else # not a command, must be some Ruby code.
|
|
87
|
+
code << line
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end # of debug_console
|
|
91
|
+
|
|
92
|
+
# Client header.
|
|
93
|
+
def display_header
|
|
94
|
+
puts # spacer
|
|
95
|
+
puts ''.center(WIDTH, '=')
|
|
96
|
+
puts " Gambler v#{Gambler::VERSION} ".center(WIDTH, '=')
|
|
97
|
+
puts ''.center(WIDTH, '=')
|
|
98
|
+
puts '----------------------------------------'.center(WIDTH)
|
|
99
|
+
puts '| Feeding yet another human addiction. |'.center(WIDTH)
|
|
100
|
+
puts '----------------------------------------'.center(WIDTH)
|
|
101
|
+
end # of display_header
|
|
102
|
+
|
|
103
|
+
# Pretty print the player's stats.
|
|
104
|
+
def display_player_stats
|
|
105
|
+
puts '- Players -'.center(WIDTH)
|
|
106
|
+
seperator = "\t"
|
|
107
|
+
stat_width = WIDTH - 5
|
|
108
|
+
stats = String.new
|
|
109
|
+
bot_stats = String.new
|
|
110
|
+
|
|
111
|
+
stats << "Player: #{@player.name}".ljust(WIDTH/2)
|
|
112
|
+
stats << seperator
|
|
113
|
+
stats << "Chips: #{@player.chips}"
|
|
114
|
+
puts stats.center(stat_width)
|
|
115
|
+
|
|
116
|
+
if @bots.empty?
|
|
117
|
+
puts 'No AI opponents.'.center(WIDTH)
|
|
118
|
+
else
|
|
119
|
+
@bots.each do |bot|
|
|
120
|
+
bot_stats = "AI: #{bot.name}".ljust(WIDTH/2)
|
|
121
|
+
bot_stats << seperator
|
|
122
|
+
bot_stats << "Chips: #{bot.chips}"
|
|
123
|
+
puts bot_stats.center(stat_width)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end # of display_player_stats
|
|
127
|
+
|
|
128
|
+
# Client game menu.
|
|
129
|
+
def display_game_menu
|
|
130
|
+
puts '-----------------------'.center(WIDTH)
|
|
131
|
+
puts '| 1) Blackjack |'.center(WIDTH)
|
|
132
|
+
puts '| 2) Stud Poker |'.center(WIDTH)
|
|
133
|
+
puts "| 3) Texas Hold 'em |".center(WIDTH)
|
|
134
|
+
puts '| A) Add AI Player |'.center(WIDTH)
|
|
135
|
+
puts '| D) Debug Console |'.center(WIDTH)
|
|
136
|
+
puts '| P) Setup Player |'.center(WIDTH)
|
|
137
|
+
puts '| Q) Quit |'.center(WIDTH)
|
|
138
|
+
puts '-----------------------'.center(WIDTH)
|
|
139
|
+
puts
|
|
140
|
+
print 'Game: '
|
|
141
|
+
end # of display_menu
|
|
142
|
+
|
|
143
|
+
# Play a quick 1vs1 game of Blackjack.
|
|
144
|
+
def play_blackjack
|
|
145
|
+
begin
|
|
146
|
+
# Create an array and add the player and bots.
|
|
147
|
+
players = Array.new
|
|
148
|
+
players << @player
|
|
149
|
+
players << @bots
|
|
150
|
+
players.flatten!
|
|
151
|
+
|
|
152
|
+
@game = Gambler::Game::Blackjack.new(:players => players)
|
|
153
|
+
rescue Gambler::Exceptions::InvalidPlayerSize
|
|
154
|
+
puts 'Need at least 2 players for blackjack.'
|
|
155
|
+
until @bots.size >= 1
|
|
156
|
+
@bots << setup_player(:bot => true)
|
|
157
|
+
end
|
|
158
|
+
retry
|
|
159
|
+
end # of begin ZOMG!!1
|
|
160
|
+
end # of play_blackjack
|
|
161
|
+
|
|
162
|
+
# Takes an array of +code+ lines and <tt>eval</tt>'s them.
|
|
163
|
+
def run_code(code)
|
|
164
|
+
puts # spacer
|
|
165
|
+
begin
|
|
166
|
+
puts " BEGIN DEBUG ".center(WIDTH, '=')
|
|
167
|
+
eval(code.join("\n")) # Need to join, since +code+ is an Array.
|
|
168
|
+
puts " END DEBUG ".center(WIDTH, '=')
|
|
169
|
+
rescue Exception => error
|
|
170
|
+
puts " DEBUG FAILED ".center(WIDTH, '=')
|
|
171
|
+
puts error
|
|
172
|
+
end
|
|
173
|
+
puts # spacer
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# Setup a new Player instance.
|
|
177
|
+
def setup_player(options = {})
|
|
178
|
+
default_chips = 100
|
|
179
|
+
if options[:bot]
|
|
180
|
+
who = 'AI player'
|
|
181
|
+
default_name = 'Kenny'
|
|
182
|
+
else
|
|
183
|
+
who = 'your player'
|
|
184
|
+
default_name = 'Human'
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
puts "Setting up #{who}."
|
|
188
|
+
print "Name [#{default_name}]: "
|
|
189
|
+
name = STDIN.gets.chomp
|
|
190
|
+
name = default_name if name.empty?
|
|
191
|
+
|
|
192
|
+
print "Chips [#{default_chips}]: "
|
|
193
|
+
chips = STDIN.gets.chomp.to_i
|
|
194
|
+
chips = default_chips if chips.zero?
|
|
195
|
+
|
|
196
|
+
return Gambler::Player.new(name, :chips => chips)
|
|
197
|
+
end # of setup_player
|
|
198
|
+
|
|
199
|
+
# Takes an array of +code+ lines and prints them.
|
|
200
|
+
def show_code_buffer(code)
|
|
201
|
+
return (puts "Buffer empty.") if code.size.zero?
|
|
202
|
+
puts "== BUFFER ==\n"
|
|
203
|
+
code.each_with_index do |buf, line_num|
|
|
204
|
+
print "#{line_num + 1}: ".rjust(5)
|
|
205
|
+
puts buf
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
end # of Client
|
|
210
|
+
|
|
211
|
+
end # of Gambler
|
|
212
|
+
|
|
213
|
+
# Let's do this!
|
|
214
|
+
Gambler::Client.new.menu
|
data/lib/gambler/card.rb
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
module Gambler
|
|
2
|
+
|
|
3
|
+
# Object representing an individual Card.
|
|
4
|
+
#
|
|
5
|
+
# All of the following lines create a king of diamonds:
|
|
6
|
+
# # Array
|
|
7
|
+
# Card.new ['K', 'd']
|
|
8
|
+
#
|
|
9
|
+
# # Hash
|
|
10
|
+
# Card.new :face => 'K', :suit => 'd'
|
|
11
|
+
#
|
|
12
|
+
# # String
|
|
13
|
+
# Card.new 'Kd'
|
|
14
|
+
class Card
|
|
15
|
+
SUITS = %w(c d h s)
|
|
16
|
+
SUIT_NAMES = {
|
|
17
|
+
'c' => 'Clubs',
|
|
18
|
+
'd' => 'Diamonds',
|
|
19
|
+
'h' => 'Hearts',
|
|
20
|
+
's' => 'Spades'
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
FACES = %w(A K Q J T 9 8 7 6 5 4 3 2)
|
|
24
|
+
FACE_NAMES = {
|
|
25
|
+
'A' => 'Ace',
|
|
26
|
+
'K' => 'King',
|
|
27
|
+
'Q' => 'Queen',
|
|
28
|
+
'J' => 'Jack',
|
|
29
|
+
'T' => 'Ten',
|
|
30
|
+
'9' => 'Nine',
|
|
31
|
+
'8' => 'Eight',
|
|
32
|
+
'7' => 'Seven',
|
|
33
|
+
'6' => 'Six',
|
|
34
|
+
'5' => 'Five',
|
|
35
|
+
'4' => 'Four',
|
|
36
|
+
'3' => 'Three',
|
|
37
|
+
'2' => 'Two'
|
|
38
|
+
}
|
|
39
|
+
FACE_VALUES = {
|
|
40
|
+
'A' => 14,
|
|
41
|
+
'K' => 13,
|
|
42
|
+
'Q' => 12,
|
|
43
|
+
'J' => 11,
|
|
44
|
+
'T' => 10,
|
|
45
|
+
'9' => 9,
|
|
46
|
+
'8' => 8,
|
|
47
|
+
'7' => 7,
|
|
48
|
+
'6' => 6,
|
|
49
|
+
'5' => 5,
|
|
50
|
+
'4' => 4,
|
|
51
|
+
'3' => 3,
|
|
52
|
+
'2' => 2,
|
|
53
|
+
'L' => 1 # Magic low Ace.
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
attr_reader :face, :suit
|
|
57
|
+
|
|
58
|
+
# Creates a new Card object, based on the class of +args+.
|
|
59
|
+
def initialize(args)
|
|
60
|
+
face, suit = case args
|
|
61
|
+
when Array:
|
|
62
|
+
build_from_array(args)
|
|
63
|
+
when Hash:
|
|
64
|
+
build_from_hash(args)
|
|
65
|
+
when String:
|
|
66
|
+
build_from_string(args)
|
|
67
|
+
end
|
|
68
|
+
raise Exceptions::InvalidCardType unless SUITS.include?(suit) && FACES.include?(face)
|
|
69
|
+
@face, @suit = face, suit
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Class methods.
|
|
73
|
+
class << self
|
|
74
|
+
# Iterator for all Cards; yields one Card in +block+ or returns an Array of all Cards.
|
|
75
|
+
def all(&block)
|
|
76
|
+
cards = Array.new
|
|
77
|
+
each_suit do |suit|
|
|
78
|
+
each_face do |face|
|
|
79
|
+
card = self.new(:face => face, :suit => suit)
|
|
80
|
+
block_given? ? (yield card) : cards << card
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
return cards unless block_given?
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Iterator for the FACES.
|
|
87
|
+
def each_face(&block)
|
|
88
|
+
FACES.each { |face| yield face }
|
|
89
|
+
end # of each_face
|
|
90
|
+
|
|
91
|
+
# Iterator for the SUITS.
|
|
92
|
+
def each_suit(&block)
|
|
93
|
+
SUITS.each { |suit| yield suit }
|
|
94
|
+
end # of each_suit
|
|
95
|
+
|
|
96
|
+
# Build methods for each SUIT which will return an array of all Cards in that SUIT.
|
|
97
|
+
# This will allow for things like:
|
|
98
|
+
# Card.diamonds.sort_by { |card| card.face_value }.each {|card| puts card}
|
|
99
|
+
class_eval do
|
|
100
|
+
Card.each_suit do |index|
|
|
101
|
+
suit_name = SUIT_NAMES[index].downcase
|
|
102
|
+
define_method(suit_name) do
|
|
103
|
+
cards = Array.new
|
|
104
|
+
all do |card|
|
|
105
|
+
cards << card if card.suit == index
|
|
106
|
+
end
|
|
107
|
+
return cards
|
|
108
|
+
end
|
|
109
|
+
end # of Card.each_suit
|
|
110
|
+
end # of class_eval
|
|
111
|
+
end # of class methods
|
|
112
|
+
|
|
113
|
+
# Return the numerical face value of a Card.
|
|
114
|
+
def face_value
|
|
115
|
+
FACE_VALUES[@face]
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Print a human readable description of a Card instance.
|
|
119
|
+
# Card.new('Kd').to_s # => 'Kd'
|
|
120
|
+
def to_s
|
|
121
|
+
@face + @suit
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Print a (pretty) human readable description of a Card instance.
|
|
125
|
+
# Card.new('Kd').to_pretty_s # => 'King of Diamonds'
|
|
126
|
+
def to_pretty_s
|
|
127
|
+
face = FACE_NAMES[@face]
|
|
128
|
+
suit = SUIT_NAMES[@suit]
|
|
129
|
+
return "#{face} of #{suit}"
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
private
|
|
133
|
+
|
|
134
|
+
# Build a Card object with the given +array+.
|
|
135
|
+
# Example:
|
|
136
|
+
# build_from_array ['K', 'd']
|
|
137
|
+
def build_from_array(array)
|
|
138
|
+
raise Exceptions::InvalidCardType unless array.size == 2
|
|
139
|
+
face = array.shift
|
|
140
|
+
suit = array.shift
|
|
141
|
+
return face, suit
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# Build a Card object with the given +hash+.
|
|
145
|
+
# Example:
|
|
146
|
+
# build_from_hash(:face => 'K', :suit => 'd')
|
|
147
|
+
def build_from_hash(hash)
|
|
148
|
+
raise Exceptions::InvalidCardType unless hash.include?(:face) && hash.include?(:suit)
|
|
149
|
+
return hash[:face], hash[:suit]
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# Build a Card object with the given +string+.
|
|
153
|
+
# Example:
|
|
154
|
+
# build_from_string('Kd')
|
|
155
|
+
def build_from_string(string)
|
|
156
|
+
card = string.split('')
|
|
157
|
+
raise Exceptions::InvalidCardType unless card.size == 2
|
|
158
|
+
face = card.shift # First letter.
|
|
159
|
+
suit = card.shift # Second letter.
|
|
160
|
+
return face, suit
|
|
161
|
+
end
|
|
162
|
+
end # of Card
|
|
163
|
+
end # of Gambler
|
data/lib/gambler/deck.rb
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
module Gambler
|
|
2
|
+
|
|
3
|
+
# Handles a collection of Gambler::Card objects as a single Deck.
|
|
4
|
+
# +options+ can be:
|
|
5
|
+
# * <tt>cards</tt>: An array of Cards this Deck will contain.
|
|
6
|
+
#
|
|
7
|
+
# Examples:
|
|
8
|
+
#
|
|
9
|
+
# @deck = Deck.new
|
|
10
|
+
class Deck
|
|
11
|
+
attr_reader :cards, :shuffled
|
|
12
|
+
|
|
13
|
+
def initialize(options = {})
|
|
14
|
+
options[:cards] ||= Card.all
|
|
15
|
+
options[:cards].each do |card|
|
|
16
|
+
raise Exceptions::InvalidDeck unless card.is_a? Card
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
@cards = options[:cards]
|
|
20
|
+
@shuffled = false
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Deals one Card to the given +player+.
|
|
24
|
+
# Example:
|
|
25
|
+
# @deck.deal_to(@player)
|
|
26
|
+
def deal_to(player)
|
|
27
|
+
card = @cards.first
|
|
28
|
+
raise Exceptions::DeckEmpty if card.nil?
|
|
29
|
+
player.hand << card
|
|
30
|
+
@cards.delete(card)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Shuffles the Deck; changes <tt>@cards</tt> to reflect the shuffle.
|
|
34
|
+
# Example:
|
|
35
|
+
# @deck.shuffle!
|
|
36
|
+
def shuffle!
|
|
37
|
+
@cards.sort! {rand}
|
|
38
|
+
@shuffled = true
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Size of the current Deck (number of Cards remaining).
|
|
42
|
+
def size
|
|
43
|
+
@cards.size
|
|
44
|
+
end
|
|
45
|
+
end # of Deck
|
|
46
|
+
end # of Gambler
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module Gambler
|
|
2
|
+
|
|
3
|
+
module Exceptions
|
|
4
|
+
|
|
5
|
+
# Gambler
|
|
6
|
+
class MustOverrideMethod < Exception; end
|
|
7
|
+
|
|
8
|
+
# Card
|
|
9
|
+
class InvalidCardType < Exception; end
|
|
10
|
+
|
|
11
|
+
# Deck
|
|
12
|
+
class DeckEmpty < Exception; end
|
|
13
|
+
class InvalidDeck < Exception; end
|
|
14
|
+
|
|
15
|
+
# Game
|
|
16
|
+
class InvalidPlayers < Exception; end
|
|
17
|
+
class InvalidPlayerSize < Exception; end
|
|
18
|
+
class NoPlayers < Exception; end
|
|
19
|
+
|
|
20
|
+
# Player
|
|
21
|
+
class NoPlayerName < Exception; end
|
|
22
|
+
class InvalidChipCount < Exception; end
|
|
23
|
+
|
|
24
|
+
end # of Exceptions
|
|
25
|
+
|
|
26
|
+
end # of Gambler
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module Gambler
|
|
2
|
+
|
|
3
|
+
module Game
|
|
4
|
+
|
|
5
|
+
# The Game of Blackjack.
|
|
6
|
+
class Blackjack < Gambler::Game::BasicGame
|
|
7
|
+
INITIAL_CARDS = 2
|
|
8
|
+
|
|
9
|
+
def initialize(options = {})
|
|
10
|
+
raise Exceptions::InvalidPlayerSize unless options[:players].size >= 2
|
|
11
|
+
super(options)
|
|
12
|
+
@players.each { |player| player.empty_hand! }
|
|
13
|
+
deal_initial_hands
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
# Deal out the initial cards to each Player.
|
|
19
|
+
def deal_initial_hands
|
|
20
|
+
INITIAL_CARDS.times do
|
|
21
|
+
@players.each do |player|
|
|
22
|
+
@deck.deal_to player
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end # of Blackjack
|
|
28
|
+
|
|
29
|
+
end # of Game
|
|
30
|
+
|
|
31
|
+
end # of Gambler
|
data/lib/gambler/game.rb
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
module Gambler
|
|
2
|
+
|
|
3
|
+
# Main Player class in which all others should inherit (if neccessary).
|
|
4
|
+
# The Player's +name+ is required.
|
|
5
|
+
#
|
|
6
|
+
# +options+ can contain:
|
|
7
|
+
# * <tt>chips</tt>: Amount of chips the new Player will have. Defaults to 100.
|
|
8
|
+
# * <tt>hand</tt>: An array of Cards the new Player will be holding. Defaults to +nil+.
|
|
9
|
+
#
|
|
10
|
+
# Example:
|
|
11
|
+
# Player.new('Dale')
|
|
12
|
+
# Player.new('Kenny', :chips => 1_000_000)
|
|
13
|
+
# Player.new( 'Cheaty McGee', # has blackjack from the start!
|
|
14
|
+
# :hand => [Card.new('Ad'), Card.new('Kd')] )
|
|
15
|
+
class Player
|
|
16
|
+
# Initial chip count if none is specified.
|
|
17
|
+
CHIP_STACK = 100
|
|
18
|
+
|
|
19
|
+
attr_accessor :name, :chips, :hand
|
|
20
|
+
|
|
21
|
+
def initialize(name, options = {})
|
|
22
|
+
raise Exceptions::NoPlayerName unless name
|
|
23
|
+
@name = name
|
|
24
|
+
@hand = options[:hand] || Array.new
|
|
25
|
+
|
|
26
|
+
@chips = options[:chips] || CHIP_STACK
|
|
27
|
+
raise Exceptions::InvalidChipCount unless @chips.is_a? Fixnum
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Removes all the Cards from the Player's hand.
|
|
31
|
+
def empty_hand!
|
|
32
|
+
@hand = Array.new
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Pretty object inspection.
|
|
36
|
+
def inspect
|
|
37
|
+
%Q{#<Gambler::Player '#{@name}'>}
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Pretty printing of a Player.
|
|
41
|
+
def to_s
|
|
42
|
+
"#{@name} ($#{@chips})"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Allows a Player to view their +hand+ in various formats.
|
|
46
|
+
def view_hand(options = {})
|
|
47
|
+
format = options[:format] || :array
|
|
48
|
+
pretty = options[:pretty] || false
|
|
49
|
+
seperator = options[:seperator] || (pretty ? ', ' : ' ')
|
|
50
|
+
|
|
51
|
+
method = (pretty ? :to_pretty_s : :to_s)
|
|
52
|
+
|
|
53
|
+
case format
|
|
54
|
+
when :array
|
|
55
|
+
cards = Array.new
|
|
56
|
+
@hand.each { |card| cards << card.send(method) }
|
|
57
|
+
when :string
|
|
58
|
+
cards = @hand.collect { |card| card.send(method) }.join(seperator)
|
|
59
|
+
end
|
|
60
|
+
return cards
|
|
61
|
+
end # of view_hand
|
|
62
|
+
|
|
63
|
+
end # of Player
|
|
64
|
+
end # of Gambler
|