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 ADDED
@@ -0,0 +1,10 @@
1
+ === 0.0.2 / 2008-06-09
2
+
3
+ * Basic gambling framework!
4
+
5
+ === 0.0.1 / 2008-06-05
6
+
7
+ * 1 major enhancement
8
+
9
+ * Birthday!
10
+
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
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,9 @@
1
+ require 'gambler/game/basic_game'
2
+ require 'gambler/game/blackjack'
3
+
4
+ module Gambler
5
+
6
+ module Game
7
+ end # of Game
8
+
9
+ end # of Gambler
@@ -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