Oshuma-gambler 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|