texas_holdem 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.autotest +5 -0
- data/.document +5 -0
- data/.gitignore +21 -0
- data/Gemfile +0 -0
- data/LICENSE +20 -0
- data/README +0 -0
- data/README.rdoc +17 -0
- data/Rakefile +62 -0
- data/VERSION +1 -0
- data/lib/betting_round.rb +83 -0
- data/lib/deck.rb +35 -0
- data/lib/game.rb +20 -0
- data/lib/hand.rb +78 -0
- data/lib/player.rb +42 -0
- data/lib/players_hand.rb +132 -0
- data/lib/texas_holdem.rb +8 -0
- data/test/helper.rb +57 -0
- data/test/test_betting_round.rb +140 -0
- data/test/test_deck.rb +37 -0
- data/test/test_game.rb +30 -0
- data/test/test_hand.rb +158 -0
- data/test/test_player.rb +32 -0
- data/test/test_players_hand.rb +117 -0
- data/test/test_texas_holdem.rb +9 -0
- metadata +99 -0
data/.autotest
ADDED
data/.document
ADDED
data/.gitignore
ADDED
data/Gemfile
ADDED
File without changes
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Keith McDonnell
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
File without changes
|
data/README.rdoc
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
= texas_holdem
|
2
|
+
|
3
|
+
Description goes here.
|
4
|
+
|
5
|
+
== Note on Patches/Pull Requests
|
6
|
+
|
7
|
+
* Fork the project.
|
8
|
+
* Make your feature addition or bug fix.
|
9
|
+
* Add tests for it. This is important so I don't break it in a
|
10
|
+
future version unintentionally.
|
11
|
+
* Commit, do not mess with rakefile, version, or history.
|
12
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
13
|
+
* Send me a pull request. Bonus points for topic branches.
|
14
|
+
|
15
|
+
== Copyright
|
16
|
+
|
17
|
+
Copyright (c) 2010 Keith McDonnell. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "texas_holdem"
|
8
|
+
gem.summary = %Q{Ruby classes modelling a game Texas Holdem poker}
|
9
|
+
gem.description = %Q{Ruby classes modelling a game Texas Holdem poker}
|
10
|
+
gem.email = "keith@dancingtext.com"
|
11
|
+
gem.homepage = "http://github.com/kmcd/texas_holdem"
|
12
|
+
gem.authors = ["Keith McDonnell"]
|
13
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
14
|
+
end
|
15
|
+
Jeweler::GemcutterTasks.new
|
16
|
+
rescue LoadError
|
17
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
18
|
+
end
|
19
|
+
|
20
|
+
require 'rake/testtask'
|
21
|
+
Rake::TestTask.new(:test) do |test|
|
22
|
+
test.libs << 'lib' << 'test'
|
23
|
+
test.pattern = 'test/**/test_*.rb'
|
24
|
+
test.verbose = true
|
25
|
+
end
|
26
|
+
|
27
|
+
task :test => :check_dependencies
|
28
|
+
|
29
|
+
task :default => :test
|
30
|
+
|
31
|
+
require 'rake/rdoctask'
|
32
|
+
Rake::RDocTask.new do |rdoc|
|
33
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
34
|
+
|
35
|
+
rdoc.rdoc_dir = 'rdoc'
|
36
|
+
rdoc.title = "texas_holdem #{version}"
|
37
|
+
rdoc.rdoc_files.include('README*')
|
38
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
39
|
+
end
|
40
|
+
|
41
|
+
desc 'Create class & unit test'
|
42
|
+
task :class, :name do |task,args|
|
43
|
+
class_name = args.name.capitalize
|
44
|
+
file_name = args.name.downcase
|
45
|
+
|
46
|
+
write_to "lib/#{file_name}.rb", %Q{class TexasHoldem::#{class_name}
|
47
|
+
end}
|
48
|
+
|
49
|
+
write_to "test/test_#{file_name}.rb", %Q{require 'helper'
|
50
|
+
class #{class_name}Test < Test::Unit::TestCase
|
51
|
+
def setup
|
52
|
+
end
|
53
|
+
|
54
|
+
test "should " do
|
55
|
+
flunk
|
56
|
+
end
|
57
|
+
end}
|
58
|
+
end
|
59
|
+
|
60
|
+
def write_to(local_filename,text)
|
61
|
+
File.open(local_filename, 'w') {|f| f.write(text) }
|
62
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'timeout'
|
2
|
+
|
3
|
+
class BettingRound
|
4
|
+
attr_accessor :max_wait_time_for_bet
|
5
|
+
|
6
|
+
def initialize(hand)
|
7
|
+
@hand = hand
|
8
|
+
@betting_circle = players.enum_for
|
9
|
+
players.each {|player| player.add_observer self }
|
10
|
+
end
|
11
|
+
|
12
|
+
def next_player
|
13
|
+
@current_player = @betting_circle.next
|
14
|
+
rescue StopIteration
|
15
|
+
@betting_circle.rewind and retry
|
16
|
+
end
|
17
|
+
|
18
|
+
def max_wait_time_for_bet(seconds)
|
19
|
+
Timeout::timeout(seconds) { yield }
|
20
|
+
rescue Timeout::Error
|
21
|
+
fold @current_player and next_player
|
22
|
+
end
|
23
|
+
|
24
|
+
def current_player
|
25
|
+
@current_player || next_player
|
26
|
+
end
|
27
|
+
|
28
|
+
def players
|
29
|
+
@players ||= @hand.players
|
30
|
+
end
|
31
|
+
|
32
|
+
def bets
|
33
|
+
@bets ||= Hash.new(0)
|
34
|
+
end
|
35
|
+
|
36
|
+
def minimum_bet
|
37
|
+
bets.values.empty? ? @hand.minimum_bet : amount_to_match_pot
|
38
|
+
end
|
39
|
+
|
40
|
+
def minimum_raise
|
41
|
+
minimum_bet + @hand.minimum_bet
|
42
|
+
end
|
43
|
+
|
44
|
+
def amount_bet
|
45
|
+
bets.values.compact.reduce(:+) || 0
|
46
|
+
end
|
47
|
+
|
48
|
+
def finished?
|
49
|
+
players.size == 1 || everyone_bet_equal_amount?
|
50
|
+
end
|
51
|
+
|
52
|
+
def update(args)
|
53
|
+
if args[:fold]
|
54
|
+
fold @current_player
|
55
|
+
else
|
56
|
+
bet, player = args[:bet][:amount], args[:bet][:player]
|
57
|
+
return unless valid? bet, player
|
58
|
+
bets[player] += bet
|
59
|
+
@hand.pot += bet
|
60
|
+
end
|
61
|
+
next_player
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def valid?(bet,player)
|
67
|
+
return unless player.eql? current_player
|
68
|
+
bet == minimum_bet || bet >= minimum_raise || bet == 0
|
69
|
+
end
|
70
|
+
|
71
|
+
def everyone_bet_equal_amount?
|
72
|
+
bets.values.uniq.size == 1
|
73
|
+
end
|
74
|
+
|
75
|
+
def amount_to_match_pot
|
76
|
+
bets.values.max - bets[current_player]
|
77
|
+
end
|
78
|
+
|
79
|
+
def fold(player)
|
80
|
+
players.delete player
|
81
|
+
@hand.fold player
|
82
|
+
end
|
83
|
+
end
|
data/lib/deck.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
class TexasHoldem::Deck
|
2
|
+
FACES, SUITS = "AKQJT98765432", "cdhs"
|
3
|
+
|
4
|
+
attr_reader :cards
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
build
|
8
|
+
shuffle
|
9
|
+
end
|
10
|
+
|
11
|
+
def next_card
|
12
|
+
@cards.pop
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def build
|
18
|
+
@cards = []
|
19
|
+
|
20
|
+
FACES.each_byte do |f|
|
21
|
+
SUITS.each_byte {|s| @cards.push(f.chr + s.chr) }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def shuffle
|
26
|
+
3.times do
|
27
|
+
shuf = []
|
28
|
+
@cards.each do |c|
|
29
|
+
loc = rand(shuf.size + 1)
|
30
|
+
shuf.insert(loc, c)
|
31
|
+
end
|
32
|
+
@cards = shuf.reverse
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/game.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
class TexasHoldem::Game
|
2
|
+
SMALL_BLIND_PERCENTAGE = 0.0125
|
3
|
+
attr_reader :players, :entrance_fee
|
4
|
+
|
5
|
+
def initialize(players,entrance_fee)
|
6
|
+
@players, @entrance_fee = players, entrance_fee
|
7
|
+
end
|
8
|
+
|
9
|
+
def finished?
|
10
|
+
players.size == 1
|
11
|
+
end
|
12
|
+
|
13
|
+
def winner
|
14
|
+
players.first if finished?
|
15
|
+
end
|
16
|
+
|
17
|
+
def small_blind
|
18
|
+
@entrance_fee * SMALL_BLIND_PERCENTAGE
|
19
|
+
end
|
20
|
+
end
|
data/lib/hand.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'enumerated_attribute'
|
2
|
+
|
3
|
+
class TexasHoldem::Hand
|
4
|
+
enum_attr :round, %w( ^pocket flop turn river showdown )
|
5
|
+
attr_reader :players, :community_cards
|
6
|
+
attr_accessor :pot
|
7
|
+
|
8
|
+
def initialize(players, small_blind_amount=1)
|
9
|
+
@players = players
|
10
|
+
@deck = TexasHoldem::Deck.new
|
11
|
+
@community_cards = []
|
12
|
+
@small_blind_amount = small_blind_amount
|
13
|
+
@pot = 0 # Should this be an Observer?
|
14
|
+
end
|
15
|
+
|
16
|
+
def dealer
|
17
|
+
@players.first
|
18
|
+
end
|
19
|
+
|
20
|
+
def minimum_bet
|
21
|
+
@small_blind_amount * 2
|
22
|
+
end
|
23
|
+
|
24
|
+
def small_blind
|
25
|
+
return dealer if players_remaining? 2
|
26
|
+
@players[2]
|
27
|
+
end
|
28
|
+
|
29
|
+
def big_blind
|
30
|
+
return @players.last if players_remaining? 2
|
31
|
+
@players[1]
|
32
|
+
end
|
33
|
+
|
34
|
+
def winner
|
35
|
+
if finished?
|
36
|
+
@players.first.take_winnings @pot
|
37
|
+
@players.first
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def finished?
|
42
|
+
players_remaining? 1
|
43
|
+
end
|
44
|
+
|
45
|
+
def fold(player)
|
46
|
+
@players.delete player
|
47
|
+
end
|
48
|
+
|
49
|
+
def deal
|
50
|
+
case round
|
51
|
+
when :pocket : deal_pocket_cards && deduct_blinds # Move to BettingRound?
|
52
|
+
when :flop : deal_community_cards 3
|
53
|
+
when :turn : deal_community_cards 1
|
54
|
+
when :river : deal_community_cards 1
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def players_remaining?(number)
|
61
|
+
@players.size == number
|
62
|
+
end
|
63
|
+
|
64
|
+
def deal_pocket_cards
|
65
|
+
@players.each do |player|
|
66
|
+
2.times { player.cards << @deck.next_card }
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def deal_community_cards(number)
|
71
|
+
number.times { @community_cards << @deck.next_card }
|
72
|
+
end
|
73
|
+
|
74
|
+
def deduct_blinds
|
75
|
+
@pot += small_blind.bet(@small_blind_amount)
|
76
|
+
@pot += big_blind.bet(@small_blind_amount * 2)
|
77
|
+
end
|
78
|
+
end
|
data/lib/player.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
class NotEnoughCashError < StandardError
|
2
|
+
end
|
3
|
+
|
4
|
+
require 'observer'
|
5
|
+
|
6
|
+
class TexasHoldem::Player
|
7
|
+
attr_reader :name, :cards, :cash
|
8
|
+
include Observable
|
9
|
+
|
10
|
+
def initialize(name,cash)
|
11
|
+
@name, @cash = name, cash
|
12
|
+
@cards = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def bet(amount)
|
16
|
+
# TODO: add remaining cash instead of raising an error
|
17
|
+
raise NotEnoughCashError unless enough_cash_for?(amount)
|
18
|
+
@cash -= amount
|
19
|
+
changed true
|
20
|
+
notify_observers :bet => { :player => self, :amount => amount }
|
21
|
+
amount
|
22
|
+
end
|
23
|
+
|
24
|
+
def check
|
25
|
+
bet 0
|
26
|
+
end
|
27
|
+
|
28
|
+
def fold
|
29
|
+
changed true
|
30
|
+
notify_observers :fold => true
|
31
|
+
end
|
32
|
+
|
33
|
+
def take_winnings(amount)
|
34
|
+
@cash += amount
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def enough_cash_for?(amount)
|
40
|
+
@cash > amount
|
41
|
+
end
|
42
|
+
end
|
data/lib/players_hand.rb
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
# TODO: rename to PlayerHand or Player::Hand
|
2
|
+
class TexasHoldem::PlayersHand
|
3
|
+
attr_reader :cards
|
4
|
+
|
5
|
+
include Comparable
|
6
|
+
|
7
|
+
# TODO: dry up [scdh] references
|
8
|
+
MATCHES = {
|
9
|
+
'one pair' => /(\d{1,2})[scdh] (?:\s\1[scdh]){1}/x,
|
10
|
+
'two pair' => /(\d{1,2})[scdh] \1[scdh].*(\d{1,2})[scdh] \2[scdh]/,
|
11
|
+
'three of a kind' => /(\d{1,2})[scdh] (?:\s\1[scdh]){2}/x,
|
12
|
+
'four of a kind' => /(\d{1,2})[scdh] (?:\s\1[scdh]){3}/x,
|
13
|
+
}
|
14
|
+
|
15
|
+
def initialize(cards)
|
16
|
+
@cards = cards
|
17
|
+
@cards.gsub!(/J/, '11')
|
18
|
+
@cards.gsub!(/Q/, '12')
|
19
|
+
@cards.gsub!(/K/, '13')
|
20
|
+
@cards.gsub!(/A/, '14')
|
21
|
+
@cards = @cards.split.sort_by {|c| c.gsub(/\D/,'').to_i }.join ' '
|
22
|
+
end
|
23
|
+
|
24
|
+
def <=>(players_hand)
|
25
|
+
if score == players_hand.score
|
26
|
+
remaining_cards <=> players_hand.remaining_cards
|
27
|
+
else
|
28
|
+
score <=> players_hand.score
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def name
|
33
|
+
# TODO: refactor to polymorphic type?
|
34
|
+
if four_of_a_kind?
|
35
|
+
'four of a kind'
|
36
|
+
elsif full_house?
|
37
|
+
'full house'
|
38
|
+
elsif flush?
|
39
|
+
'flush'
|
40
|
+
elsif straight?
|
41
|
+
'straight'
|
42
|
+
elsif three_of_a_kind?
|
43
|
+
'three of a kind'
|
44
|
+
elsif two_pair?
|
45
|
+
'two pair'
|
46
|
+
elsif one_pair?
|
47
|
+
'one pair'
|
48
|
+
else
|
49
|
+
'high card'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def one_pair?
|
54
|
+
@cards.match MATCHES['one pair']
|
55
|
+
end
|
56
|
+
|
57
|
+
def two_pair?
|
58
|
+
@cards.match MATCHES['two pair']
|
59
|
+
end
|
60
|
+
|
61
|
+
def straight?
|
62
|
+
card_sequence = face_values.split.map {|d| d.to_i }
|
63
|
+
(card_sequence.first..card_sequence.last).to_a == card_sequence
|
64
|
+
end
|
65
|
+
|
66
|
+
def flush?
|
67
|
+
@cards.match /\d{1,2}([csdh]) (?:\s\d{1,2}\1){4} /x
|
68
|
+
end
|
69
|
+
|
70
|
+
def three_of_a_kind?
|
71
|
+
@cards.match MATCHES['three of a kind']
|
72
|
+
end
|
73
|
+
|
74
|
+
def full_house?
|
75
|
+
# TODO: change this to [csdh]
|
76
|
+
@cards.gsub(/\D/,'').match /^(?:(\d) \1{2} (\d) \2|(\d) \3 (\d) \4{2})/x
|
77
|
+
end
|
78
|
+
|
79
|
+
def four_of_a_kind?
|
80
|
+
@cards.match MATCHES['four of a kind']
|
81
|
+
end
|
82
|
+
|
83
|
+
protected
|
84
|
+
|
85
|
+
def score
|
86
|
+
base_score + relative_score
|
87
|
+
end
|
88
|
+
|
89
|
+
def base_score
|
90
|
+
case name
|
91
|
+
when /one pair/ : 1
|
92
|
+
when /two pair/ : 2
|
93
|
+
when /three/ : 3
|
94
|
+
when /straight/ : 4
|
95
|
+
when /flush/ : 5
|
96
|
+
when /full house/ : 6
|
97
|
+
when /four/ : 7
|
98
|
+
else
|
99
|
+
0
|
100
|
+
end * 1000
|
101
|
+
end
|
102
|
+
|
103
|
+
def relative_score
|
104
|
+
case name
|
105
|
+
when /one pair/ : @cards[MATCHES['one pair'],1].to_i * 2
|
106
|
+
when /two pair/ : @cards[MATCHES['two pair'],2].to_i * 2
|
107
|
+
when /three/ : @cards[MATCHES['three of a kind'],1].to_i * 3
|
108
|
+
when /straight/ : face_values.split.last.to_i
|
109
|
+
when /flush/ : face_values.split.sort.last.to_i
|
110
|
+
when /full house/ : @cards[MATCHES['three of a kind'],1].to_i
|
111
|
+
when /four/ : @cards[MATCHES['four of a kind'],1].to_i
|
112
|
+
else
|
113
|
+
0
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def remaining_cards
|
118
|
+
case name
|
119
|
+
when /high card/ : @cards
|
120
|
+
when /one pair/ : @cards.gsub(MATCHES['one pair'], '')
|
121
|
+
when /two pair/ : @cards.gsub(MATCHES['two pair'], '')
|
122
|
+
else
|
123
|
+
''
|
124
|
+
end.gsub /[a-z]/, ''
|
125
|
+
end
|
126
|
+
|
127
|
+
private
|
128
|
+
|
129
|
+
def face_values
|
130
|
+
@cards.gsub(/[scdh]/,'')
|
131
|
+
end
|
132
|
+
end
|
data/lib/texas_holdem.rb
ADDED
data/test/helper.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'active_support/testing/declarative'
|
4
|
+
require 'mocha'
|
5
|
+
|
6
|
+
# TODO: create a rake task to load irb environment
|
7
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
8
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
9
|
+
require 'texas_holdem'
|
10
|
+
|
11
|
+
class Test::Unit::TestCase
|
12
|
+
extend ActiveSupport::Testing::Declarative
|
13
|
+
|
14
|
+
def assert_cards(number,players)
|
15
|
+
assert players.all? {|player| player.cards.size == number }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class String
|
20
|
+
include Test::Unit::Assertions
|
21
|
+
|
22
|
+
def hand_name(name)
|
23
|
+
assert_equal name, TexasHoldem::PlayersHand.new(self).name
|
24
|
+
end
|
25
|
+
|
26
|
+
def beats(loser)
|
27
|
+
winner, loser = TexasHoldem::PlayersHand.new(self), TexasHoldem::PlayersHand.new(loser)
|
28
|
+
assert( winner > loser )
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class TexasHoldem::Hand
|
33
|
+
def self.factory(small_blind=1.25)
|
34
|
+
players = %w( Amy Bill Carl ).map {|name| TexasHoldem::Player.factory name }
|
35
|
+
new players, small_blind
|
36
|
+
end
|
37
|
+
|
38
|
+
def advance_to_round(number)
|
39
|
+
(number - 1).times do
|
40
|
+
deal
|
41
|
+
round_next
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class TexasHoldem::Player
|
47
|
+
def self.factory(name, cash=100)
|
48
|
+
new name, cash
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
module HandTestHelper
|
53
|
+
def setup
|
54
|
+
@hand = TexasHoldem::Hand.factory
|
55
|
+
@amy, @bill, @carl = *@hand.players
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class BettingRoundTest < Test::Unit::TestCase
|
4
|
+
include HandTestHelper
|
5
|
+
|
6
|
+
def setup
|
7
|
+
super
|
8
|
+
@betting_round = BettingRound.new @hand
|
9
|
+
@hand.deal
|
10
|
+
end
|
11
|
+
|
12
|
+
def assert_current_player(player)
|
13
|
+
assert_equal player, @betting_round.current_player
|
14
|
+
end
|
15
|
+
|
16
|
+
test "player to the left of big blind is first to bet" do
|
17
|
+
assert_current_player @amy
|
18
|
+
end
|
19
|
+
|
20
|
+
test "play continues clockwise around the table" do
|
21
|
+
assert_current_player @amy
|
22
|
+
@betting_round.next_player
|
23
|
+
assert_current_player @bill
|
24
|
+
@betting_round.next_player
|
25
|
+
assert_current_player @carl
|
26
|
+
@betting_round.next_player
|
27
|
+
assert_current_player @amy
|
28
|
+
end
|
29
|
+
|
30
|
+
test "should track amount bet" do
|
31
|
+
@amy.bet 20
|
32
|
+
assert_equal 20, @betting_round.amount_bet
|
33
|
+
@bill.bet 20
|
34
|
+
assert_equal 40, @betting_round.amount_bet
|
35
|
+
@carl.bet 20
|
36
|
+
assert_equal 60, @betting_round.amount_bet
|
37
|
+
end
|
38
|
+
|
39
|
+
test "should only accept bet from current player" do
|
40
|
+
assert_current_player @amy
|
41
|
+
@carl.bet 20
|
42
|
+
assert_equal 0, @betting_round.amount_bet
|
43
|
+
assert_current_player @amy
|
44
|
+
end
|
45
|
+
|
46
|
+
test "should finish if all players check" do
|
47
|
+
@betting_round.players.each {|player| player.check }
|
48
|
+
assert @betting_round.finished?
|
49
|
+
end
|
50
|
+
|
51
|
+
test "should finish if all players check or fold" do
|
52
|
+
@amy.check
|
53
|
+
@bill.check
|
54
|
+
@carl.fold
|
55
|
+
assert @betting_round.finished?
|
56
|
+
end
|
57
|
+
|
58
|
+
test "should remove player from hand if they fold" do
|
59
|
+
player = @betting_round.current_player
|
60
|
+
player.fold
|
61
|
+
assert_nil @hand.players.find {|p| p == player }
|
62
|
+
end
|
63
|
+
|
64
|
+
test "should finish when all but one fold" do
|
65
|
+
@amy.fold
|
66
|
+
@carl.fold
|
67
|
+
assert @betting_round.finished?
|
68
|
+
end
|
69
|
+
|
70
|
+
test "should have minimum raises equal to big blind" do
|
71
|
+
@amy.bet @hand.minimum_bet - 1
|
72
|
+
assert_equal 0, @betting_round.amount_bet
|
73
|
+
assert_current_player @amy
|
74
|
+
end
|
75
|
+
|
76
|
+
test "betting finishes when everyone puts in same amount" do
|
77
|
+
@betting_round.players.each {|player| player.bet 10 }
|
78
|
+
assert @betting_round.finished?
|
79
|
+
end
|
80
|
+
|
81
|
+
test "should calculate minimum bet for current player" do
|
82
|
+
@amy.bet 20
|
83
|
+
|
84
|
+
assert_current_player @bill
|
85
|
+
assert_equal @betting_round.minimum_bet, 20
|
86
|
+
@bill.bet 30
|
87
|
+
|
88
|
+
assert_current_player @carl
|
89
|
+
assert_equal @betting_round.minimum_bet, 30
|
90
|
+
@carl.bet 40
|
91
|
+
|
92
|
+
assert_current_player @amy
|
93
|
+
assert_equal @betting_round.minimum_bet, 20
|
94
|
+
@amy.bet 20
|
95
|
+
|
96
|
+
assert_current_player @bill
|
97
|
+
assert_equal @betting_round.minimum_bet, 10
|
98
|
+
@bill.bet 10
|
99
|
+
end
|
100
|
+
|
101
|
+
test "betting finishes when everyone matches amount previously put in" do
|
102
|
+
@amy.bet 20
|
103
|
+
@bill.bet 30
|
104
|
+
@carl.bet 40
|
105
|
+
assert !@betting_round.finished?
|
106
|
+
@amy.bet 20
|
107
|
+
assert !@betting_round.finished?
|
108
|
+
@bill.bet 10
|
109
|
+
assert @betting_round.finished?
|
110
|
+
end
|
111
|
+
|
112
|
+
test "should enforce (big blind) minumim bet raise" do
|
113
|
+
@amy.bet 10
|
114
|
+
assert_equal 10, @betting_round.minimum_bet
|
115
|
+
assert_equal 12.5, @betting_round.minimum_raise
|
116
|
+
|
117
|
+
@bill.bet 12
|
118
|
+
assert_current_player @bill
|
119
|
+
|
120
|
+
@bill.bet 12.5
|
121
|
+
assert_current_player @carl
|
122
|
+
end
|
123
|
+
|
124
|
+
test "should add bets to the pot" do
|
125
|
+
@amy.bet 20
|
126
|
+
@bill.bet 20
|
127
|
+
@carl.bet 20
|
128
|
+
blinds = 3.75
|
129
|
+
assert_equal 60 + blinds, @hand.pot
|
130
|
+
end
|
131
|
+
|
132
|
+
test "should kick player out of the hand if they take too long to bet" do
|
133
|
+
@betting_round.max_wait_time_for_bet(0.09) do
|
134
|
+
assert_current_player @amy
|
135
|
+
sleep 0.1
|
136
|
+
assert !@betting_round.players.include?(@amy)
|
137
|
+
assert_current_player @bill
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
data/test/test_deck.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
SORTED_FULL_DECK = %w[ 2c 2d 2h 2s 3c 3d 3h 3s 4c 4d 4h 4s 5c 5d 5h 5s 6c 6d 6h 6s
|
4
|
+
7c 7d 7h 7s 8c 8d 8h 8s 9c 9d 9h 9s Ac Ad Ah As Jc Jd Jh Js Kc Kd Kh Ks Qc
|
5
|
+
Qd Qh Qs Tc Td Th Ts]
|
6
|
+
|
7
|
+
class NewDeckTest < Test::Unit::TestCase
|
8
|
+
def setup
|
9
|
+
@deck = TexasHoldem::Deck.new
|
10
|
+
end
|
11
|
+
|
12
|
+
test "should have 52 cards initially" do
|
13
|
+
assert_equal 52, @deck.cards.size
|
14
|
+
end
|
15
|
+
|
16
|
+
test "should have 52 unique cards" do
|
17
|
+
assert_equal 52, @deck.cards.uniq.size
|
18
|
+
end
|
19
|
+
|
20
|
+
test "should have 2 - Ace of Clubs, Spades, Diamonds & Hearts" do
|
21
|
+
assert_equal SORTED_FULL_DECK, @deck.cards.sort
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class DeckDealTest < Test::Unit::TestCase
|
26
|
+
def setup
|
27
|
+
@deck = TexasHoldem::Deck.new
|
28
|
+
end
|
29
|
+
|
30
|
+
test "should deal the next card" do
|
31
|
+
delt_card = @deck.next_card
|
32
|
+
|
33
|
+
assert_equal 51, @deck.cards.size
|
34
|
+
assert SORTED_FULL_DECK.include?(delt_card)
|
35
|
+
assert_equal SORTED_FULL_DECK - [delt_card], @deck.cards.sort
|
36
|
+
end
|
37
|
+
end
|
data/test/test_game.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class GameTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@game = TexasHoldem::Game.new [], 100
|
6
|
+
end
|
7
|
+
|
8
|
+
test "should not have a winner at game start" do
|
9
|
+
assert_nil @game.winner
|
10
|
+
end
|
11
|
+
|
12
|
+
test "should have players" do
|
13
|
+
assert_equal [], @game.players
|
14
|
+
end
|
15
|
+
|
16
|
+
test "should have small blind as 1.25% of entrance fee" do
|
17
|
+
assert_equal 1.25, @game.small_blind
|
18
|
+
end
|
19
|
+
|
20
|
+
test "should know when finshed" do
|
21
|
+
@game.stubs(:players).returns [TexasHoldem::Player.new('Foo', 100)]
|
22
|
+
assert_equal true, @game.finished?
|
23
|
+
end
|
24
|
+
|
25
|
+
test "should have a winner when finished" do
|
26
|
+
winner = TexasHoldem::Player.new 'Foo', 100
|
27
|
+
@game.stubs(:players).returns [winner]
|
28
|
+
assert_equal winner, @game.winner
|
29
|
+
end
|
30
|
+
end
|
data/test/test_hand.rb
ADDED
@@ -0,0 +1,158 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class HandTest < Test::Unit::TestCase
|
4
|
+
include HandTestHelper
|
5
|
+
|
6
|
+
test "should not have a winner initially" do
|
7
|
+
assert_nil @hand.winner
|
8
|
+
end
|
9
|
+
|
10
|
+
test "should have a winner if everyone else folds" do
|
11
|
+
@hand.deal
|
12
|
+
@hand.fold @bill
|
13
|
+
@hand.fold @carl
|
14
|
+
|
15
|
+
assert_equal @hand.winner, @amy
|
16
|
+
end
|
17
|
+
|
18
|
+
test "automatically deduct blinds after dealing pocket cards" do
|
19
|
+
assert_equal 100, @hand.small_blind.cash
|
20
|
+
assert_equal 100, @hand.big_blind.cash
|
21
|
+
|
22
|
+
@hand.deal
|
23
|
+
|
24
|
+
assert @hand.pocket?
|
25
|
+
assert_equal 98.75, @hand.small_blind.cash
|
26
|
+
assert_equal 97.5, @hand.big_blind.cash
|
27
|
+
assert_equal 2.5 + 1.25, @hand.pot
|
28
|
+
end
|
29
|
+
|
30
|
+
test "should know when finished" do
|
31
|
+
@hand.deal
|
32
|
+
@hand.fold @bill
|
33
|
+
@hand.fold @carl
|
34
|
+
|
35
|
+
assert_equal true, @hand.finished?
|
36
|
+
end
|
37
|
+
|
38
|
+
test "pay out winnings when only one player remains" do
|
39
|
+
@hand.deal
|
40
|
+
@hand.fold @hand.small_blind
|
41
|
+
@hand.fold @hand.big_blind
|
42
|
+
|
43
|
+
assert_equal 103.75, @hand.winner.cash
|
44
|
+
end
|
45
|
+
|
46
|
+
test "minimum bet is double the small blind" do
|
47
|
+
assert_equal 2.5, @hand.minimum_bet
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class PocketHandTest < Test::Unit::TestCase
|
52
|
+
include HandTestHelper
|
53
|
+
|
54
|
+
test "first round should be pocket/hole cards" do
|
55
|
+
assert @hand.pocket?
|
56
|
+
end
|
57
|
+
|
58
|
+
test "first round should deal two cards to all players" do
|
59
|
+
@hand.deal
|
60
|
+
assert_cards 2, @hand.players
|
61
|
+
end
|
62
|
+
|
63
|
+
test "should have a dealer" do
|
64
|
+
assert_equal @amy, @hand.dealer
|
65
|
+
end
|
66
|
+
|
67
|
+
test "should have a big blind player" do
|
68
|
+
assert_equal @bill, @hand.big_blind
|
69
|
+
end
|
70
|
+
|
71
|
+
test "should have a small blind player" do
|
72
|
+
assert_equal @carl, @hand.small_blind
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
class FlopTest < Test::Unit::TestCase
|
77
|
+
include HandTestHelper
|
78
|
+
|
79
|
+
def setup
|
80
|
+
super
|
81
|
+
@hand.advance_to_round 2
|
82
|
+
@hand.deal
|
83
|
+
end
|
84
|
+
|
85
|
+
test "second round should be the flop" do
|
86
|
+
assert @hand.flop?
|
87
|
+
end
|
88
|
+
|
89
|
+
test "second round should deal no new cards to any players" do
|
90
|
+
assert_cards 2, @hand.players
|
91
|
+
end
|
92
|
+
|
93
|
+
test "second round should deal three community cards" do
|
94
|
+
assert_equal 3, @hand.community_cards.size
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
class TurnTest < Test::Unit::TestCase
|
99
|
+
include HandTestHelper
|
100
|
+
|
101
|
+
def setup
|
102
|
+
super
|
103
|
+
@hand.advance_to_round 3
|
104
|
+
@hand.deal
|
105
|
+
end
|
106
|
+
|
107
|
+
test "third round should be the turn" do
|
108
|
+
assert @hand.turn?
|
109
|
+
end
|
110
|
+
|
111
|
+
test "third round should deal no new cards to any players" do
|
112
|
+
assert_cards 2, @hand.players
|
113
|
+
end
|
114
|
+
|
115
|
+
test "second round should deal one extra community card" do
|
116
|
+
assert_equal 4, @hand.community_cards.size
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
class RiverTest < Test::Unit::TestCase
|
121
|
+
include HandTestHelper
|
122
|
+
|
123
|
+
def setup
|
124
|
+
super
|
125
|
+
@hand.advance_to_round 4
|
126
|
+
@hand.deal
|
127
|
+
end
|
128
|
+
|
129
|
+
test "third round should be the river" do
|
130
|
+
assert @hand.river?
|
131
|
+
end
|
132
|
+
|
133
|
+
test "third round should deal no new cards to any players" do
|
134
|
+
assert_cards 2, @hand.players
|
135
|
+
end
|
136
|
+
|
137
|
+
test "second round should deal one extra community card" do
|
138
|
+
assert_equal 5, @hand.community_cards.size
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
class TwoPlayerHandTest < Test::Unit::TestCase
|
143
|
+
include HandTestHelper
|
144
|
+
|
145
|
+
def setup
|
146
|
+
super
|
147
|
+
@hand = TexasHoldem::Hand.new [@bill, @carl]
|
148
|
+
end
|
149
|
+
|
150
|
+
test "should have the dealer as the small blind" do
|
151
|
+
assert_equal @hand.dealer, @bill
|
152
|
+
assert_equal @hand.small_blind, @bill
|
153
|
+
end
|
154
|
+
|
155
|
+
test "should have second player as big blind" do
|
156
|
+
assert_equal @hand.big_blind, @carl
|
157
|
+
end
|
158
|
+
end
|
data/test/test_player.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class PlayerTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@entrance_fee = 100
|
6
|
+
@player = TexasHoldem::Player.new 'Carl', @entrance_fee
|
7
|
+
end
|
8
|
+
|
9
|
+
test "should have a name" do
|
10
|
+
assert_equal 'Carl', @player.name
|
11
|
+
end
|
12
|
+
|
13
|
+
test "should have no cards initially" do
|
14
|
+
assert @player.cards.empty?
|
15
|
+
end
|
16
|
+
|
17
|
+
test "should have cash" do
|
18
|
+
assert_equal @entrance_fee, @player.cash
|
19
|
+
end
|
20
|
+
|
21
|
+
test "should place a bet" do
|
22
|
+
@player.bet 99
|
23
|
+
assert_equal 1, @player.cash
|
24
|
+
end
|
25
|
+
|
26
|
+
test "should NOT bet more than available cash" do
|
27
|
+
# FIXME: treat as all in insead of raising an error
|
28
|
+
assert_raises(NotEnoughCashError) do
|
29
|
+
@player.bet(101)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class HandTest < Test::Unit::TestCase
|
4
|
+
test "should always have cards sorted in ascending order by face value" do
|
5
|
+
hand = TexasHoldem::PlayersHand.new('Ad As 5c 6c Jd')
|
6
|
+
assert_equal "5c 6c 11d 14s 14d", hand.cards
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class HandIdentificationTest < Test::Unit::TestCase
|
11
|
+
# TODO: add more non-sequential matches
|
12
|
+
|
13
|
+
test "should recognise a high card" do
|
14
|
+
'2d 3s 5c 6c Ad'.hand_name 'high card'
|
15
|
+
end
|
16
|
+
|
17
|
+
test "should recognise a pair" do
|
18
|
+
'2d 2s 5c 6c Ad'.hand_name 'one pair'
|
19
|
+
end
|
20
|
+
|
21
|
+
test "should recognise two pair" do
|
22
|
+
'2d 2s 5c 5d Ad'.hand_name 'two pair'
|
23
|
+
end
|
24
|
+
|
25
|
+
test "should recognise three of a kind" do
|
26
|
+
'2d 2s 2h 5d Ad'.hand_name 'three of a kind'
|
27
|
+
end
|
28
|
+
|
29
|
+
test "should recognise a straight" do
|
30
|
+
'2d 3s 4h 5d 6d'.hand_name 'straight'
|
31
|
+
'10c Jd Qs Kd As'.hand_name 'straight'
|
32
|
+
end
|
33
|
+
|
34
|
+
test "should recognise a flush" do
|
35
|
+
'2h 3h 4h 5h 7h'.hand_name 'flush'
|
36
|
+
end
|
37
|
+
|
38
|
+
test "should recognise a full house" do
|
39
|
+
'2d 2s 2h 4d 4c'.hand_name 'full house'
|
40
|
+
'2d 2s 4h 4d 4c'.hand_name 'full house'
|
41
|
+
'2d 4s 2h 4d 4c'.hand_name 'full house'
|
42
|
+
end
|
43
|
+
|
44
|
+
test "should recognise four of a kind" do
|
45
|
+
'2d 2c 2s 2h 3c'.hand_name 'four of a kind'
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class WinningHandsTest < Test::Unit::TestCase
|
50
|
+
test "highest card should win if no scoring poker hands" do
|
51
|
+
'2d 3s 5c 6c Ad'.beats '2c 3d 5s 6h Kd'
|
52
|
+
end
|
53
|
+
|
54
|
+
test "one pair beats no matches" do
|
55
|
+
'2d 2s 5c 6c Ad'.beats '2c 3d 5s 6h Kd'
|
56
|
+
end
|
57
|
+
|
58
|
+
test "high pair beats low pair" do
|
59
|
+
'Ad As 5c 6c Jd'.beats 'Kc Kd 5s 6h Qd'
|
60
|
+
end
|
61
|
+
|
62
|
+
test "highest card wins when pairs are equal" do
|
63
|
+
'Ad As 5c 6c Kd'.beats 'Ac Ad 5s 6h Qd'
|
64
|
+
end
|
65
|
+
|
66
|
+
test "two pair beats a pair" do
|
67
|
+
'Ad As 5c 5d Kd'.beats 'Ac Ad 5s 6h Qd'
|
68
|
+
end
|
69
|
+
|
70
|
+
test "highest pair wins if both two pairs" do
|
71
|
+
'2d 2s 4c 4d Kd'.beats '2c 2d 3s 3h Qd'
|
72
|
+
'Ad As 4c 4d Kd'.beats 'Kc Kd Qs Qh Jd'
|
73
|
+
end
|
74
|
+
|
75
|
+
test "highest card wins if both hands have identincal two pairs" do
|
76
|
+
'2d 2s 4c 4d 6d'.beats '2d 2s 4c 4d 5d'
|
77
|
+
end
|
78
|
+
|
79
|
+
test "three of a kind beats two pair" do
|
80
|
+
'Ad As Ac 5d Kd'.beats 'Kc Kd 5s 5h Qd'
|
81
|
+
end
|
82
|
+
|
83
|
+
test "stright beats three of a kind" do
|
84
|
+
'2d 3c 4h 5s 6d'.beats 'Ad As Ac 5d Kd'
|
85
|
+
end
|
86
|
+
|
87
|
+
test "higher stright beats lower straight" do
|
88
|
+
'3c 4h 5s 6d 7d'.beats '2d 3c 4h 5s 6d'
|
89
|
+
'10c Jd Qs Kd As'.beats '9h 10c Jd Qs Kd'
|
90
|
+
end
|
91
|
+
|
92
|
+
test "flush beats a straight" do
|
93
|
+
'2h 3h 4h 5h 7h'.beats '9h 10c Jd Qs Kd'
|
94
|
+
end
|
95
|
+
|
96
|
+
test "high card determines winner of flushes" do
|
97
|
+
'2h 3h 4h 5h 8h'.beats '2d 3d 4d 5d 7d'
|
98
|
+
end
|
99
|
+
|
100
|
+
test "full house beats a flush" do
|
101
|
+
'2d 2s 2h 4d 4c'.beats '2d 3d 4d 5d 7d'
|
102
|
+
end
|
103
|
+
|
104
|
+
test "higher three of a kind determines full house winner" do
|
105
|
+
'3d 3s 3h 4d 4c'.beats '2s 2h 2c Ad Ac'
|
106
|
+
'Ad As Ah 4d 4c'.beats 'Ks Kh Kc Ad Ac'
|
107
|
+
end
|
108
|
+
|
109
|
+
test "four of a kind beats a full house" do
|
110
|
+
'2d 2c 2s 2h 3c'.beats '3d 3s 3h 4d 4c'
|
111
|
+
end
|
112
|
+
|
113
|
+
test "higher card determines four of a kind winner" do
|
114
|
+
'3d 3c 3s 3h 4c'.beats '2d 2c 2s 2h 5c'
|
115
|
+
'Ad Ac As Ah 4c'.beats 'Kd Kc Ks Kh 5c'
|
116
|
+
end
|
117
|
+
end
|
metadata
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: texas_holdem
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Keith McDonnell
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-10-29 00:00:00 +01:00
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description: Ruby classes modelling a game Texas Holdem poker
|
23
|
+
email: keith@dancingtext.com
|
24
|
+
executables: []
|
25
|
+
|
26
|
+
extensions: []
|
27
|
+
|
28
|
+
extra_rdoc_files:
|
29
|
+
- LICENSE
|
30
|
+
- README
|
31
|
+
- README.rdoc
|
32
|
+
files:
|
33
|
+
- .autotest
|
34
|
+
- .document
|
35
|
+
- .gitignore
|
36
|
+
- Gemfile
|
37
|
+
- LICENSE
|
38
|
+
- README
|
39
|
+
- README.rdoc
|
40
|
+
- Rakefile
|
41
|
+
- VERSION
|
42
|
+
- lib/betting_round.rb
|
43
|
+
- lib/deck.rb
|
44
|
+
- lib/game.rb
|
45
|
+
- lib/hand.rb
|
46
|
+
- lib/player.rb
|
47
|
+
- lib/players_hand.rb
|
48
|
+
- lib/texas_holdem.rb
|
49
|
+
- test/helper.rb
|
50
|
+
- test/test_betting_round.rb
|
51
|
+
- test/test_deck.rb
|
52
|
+
- test/test_game.rb
|
53
|
+
- test/test_hand.rb
|
54
|
+
- test/test_player.rb
|
55
|
+
- test/test_players_hand.rb
|
56
|
+
- test/test_texas_holdem.rb
|
57
|
+
has_rdoc: true
|
58
|
+
homepage: http://github.com/kmcd/texas_holdem
|
59
|
+
licenses: []
|
60
|
+
|
61
|
+
post_install_message:
|
62
|
+
rdoc_options:
|
63
|
+
- --charset=UTF-8
|
64
|
+
require_paths:
|
65
|
+
- lib
|
66
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
67
|
+
none: false
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
hash: 3
|
72
|
+
segments:
|
73
|
+
- 0
|
74
|
+
version: "0"
|
75
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
76
|
+
none: false
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
hash: 3
|
81
|
+
segments:
|
82
|
+
- 0
|
83
|
+
version: "0"
|
84
|
+
requirements: []
|
85
|
+
|
86
|
+
rubyforge_project:
|
87
|
+
rubygems_version: 1.3.7
|
88
|
+
signing_key:
|
89
|
+
specification_version: 3
|
90
|
+
summary: Ruby classes modelling a game Texas Holdem poker
|
91
|
+
test_files:
|
92
|
+
- test/test_game.rb
|
93
|
+
- test/test_player.rb
|
94
|
+
- test/test_betting_round.rb
|
95
|
+
- test/test_hand.rb
|
96
|
+
- test/test_deck.rb
|
97
|
+
- test/test_players_hand.rb
|
98
|
+
- test/helper.rb
|
99
|
+
- test/test_texas_holdem.rb
|