acpc_poker_types 2.0.0 → 3.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/acpc_poker_types.gemspec +2 -2
- data/lib/acpc_poker_types/acpc_dealer_data/action_messages.rb +1 -3
- data/lib/acpc_poker_types/acpc_dealer_data/poker_match_data.rb +1 -1
- data/lib/acpc_poker_types/board_cards.rb +38 -37
- data/lib/acpc_poker_types/card.rb +40 -54
- data/lib/acpc_poker_types/chip_stack.rb +25 -25
- data/lib/acpc_poker_types/game_definition.rb +286 -284
- data/lib/acpc_poker_types/hand.rb +19 -17
- data/lib/acpc_poker_types/match_state.rb +208 -235
- data/lib/acpc_poker_types/pile_of_cards.rb +6 -4
- data/lib/acpc_poker_types/player.rb +138 -133
- data/lib/acpc_poker_types/poker_action.rb +80 -90
- data/lib/acpc_poker_types/rank.rb +51 -49
- data/lib/acpc_poker_types/suit.rb +45 -43
- data/lib/acpc_poker_types/version.rb +1 -1
- data/spec/card_spec.rb +0 -5
- data/spec/coverage/index.html +1 -1
- data/spec/match_state_spec.rb +8 -10
- data/spec/player_spec.rb +12 -19
- data/spec/poker_action_spec.rb +105 -171
- data/spec/support/spec_helper.rb +0 -1
- metadata +121 -219
- data/spec/coverage/assets/0.5.3/app.js +0 -88
- data/spec/coverage/assets/0.5.3/fancybox/blank.gif +0 -0
- data/spec/coverage/assets/0.5.3/fancybox/fancy_close.png +0 -0
- data/spec/coverage/assets/0.5.3/fancybox/fancy_loading.png +0 -0
- data/spec/coverage/assets/0.5.3/fancybox/fancy_nav_left.png +0 -0
- data/spec/coverage/assets/0.5.3/fancybox/fancy_nav_right.png +0 -0
- data/spec/coverage/assets/0.5.3/fancybox/fancy_shadow_e.png +0 -0
- data/spec/coverage/assets/0.5.3/fancybox/fancy_shadow_n.png +0 -0
- data/spec/coverage/assets/0.5.3/fancybox/fancy_shadow_ne.png +0 -0
- data/spec/coverage/assets/0.5.3/fancybox/fancy_shadow_nw.png +0 -0
- data/spec/coverage/assets/0.5.3/fancybox/fancy_shadow_s.png +0 -0
- data/spec/coverage/assets/0.5.3/fancybox/fancy_shadow_se.png +0 -0
- data/spec/coverage/assets/0.5.3/fancybox/fancy_shadow_sw.png +0 -0
- data/spec/coverage/assets/0.5.3/fancybox/fancy_shadow_w.png +0 -0
- data/spec/coverage/assets/0.5.3/fancybox/fancy_title_left.png +0 -0
- data/spec/coverage/assets/0.5.3/fancybox/fancy_title_main.png +0 -0
- data/spec/coverage/assets/0.5.3/fancybox/fancy_title_over.png +0 -0
- data/spec/coverage/assets/0.5.3/fancybox/fancy_title_right.png +0 -0
- data/spec/coverage/assets/0.5.3/fancybox/fancybox-x.png +0 -0
- data/spec/coverage/assets/0.5.3/fancybox/fancybox-y.png +0 -0
- data/spec/coverage/assets/0.5.3/fancybox/fancybox.png +0 -0
- data/spec/coverage/assets/0.5.3/fancybox/jquery.fancybox-1.3.1.css +0 -363
- data/spec/coverage/assets/0.5.3/fancybox/jquery.fancybox-1.3.1.pack.js +0 -44
- data/spec/coverage/assets/0.5.3/favicon_green.png +0 -0
- data/spec/coverage/assets/0.5.3/favicon_red.png +0 -0
- data/spec/coverage/assets/0.5.3/favicon_yellow.png +0 -0
- data/spec/coverage/assets/0.5.3/highlight.css +0 -129
- data/spec/coverage/assets/0.5.3/highlight.pack.js +0 -1
- data/spec/coverage/assets/0.5.3/jquery-1.6.2.min.js +0 -18
- data/spec/coverage/assets/0.5.3/jquery.dataTables.min.js +0 -152
- data/spec/coverage/assets/0.5.3/jquery.timeago.js +0 -141
- data/spec/coverage/assets/0.5.3/jquery.url.js +0 -174
- data/spec/coverage/assets/0.5.3/loading.gif +0 -0
- data/spec/coverage/assets/0.5.3/magnify.png +0 -0
- data/spec/coverage/assets/0.5.3/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/spec/coverage/assets/0.5.3/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/spec/coverage/assets/0.5.3/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/spec/coverage/assets/0.5.3/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/spec/coverage/assets/0.5.3/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/spec/coverage/assets/0.5.3/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/spec/coverage/assets/0.5.3/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/spec/coverage/assets/0.5.3/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/spec/coverage/assets/0.5.3/smoothness/images/ui-icons_222222_256x240.png +0 -0
- data/spec/coverage/assets/0.5.3/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
- data/spec/coverage/assets/0.5.3/smoothness/images/ui-icons_454545_256x240.png +0 -0
- data/spec/coverage/assets/0.5.3/smoothness/images/ui-icons_888888_256x240.png +0 -0
- data/spec/coverage/assets/0.5.3/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/spec/coverage/assets/0.5.3/smoothness/jquery-ui-1.8.4.custom.css +0 -295
- data/spec/coverage/assets/0.5.3/stylesheet.css +0 -383
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4486cbb027fcef016f2c31f6cb33360b618a17e0
|
|
4
|
+
data.tar.gz: c06bc66f83a1609b25e7a8f30b577cb99c121454
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7f10ec42bac803bd7a134d1fa3686ce45462fab47f56672050704c249fb48c3b4c0aa942ed911e8083805143992b0a39f41d3041e718aef984bcb8ca379794ce
|
|
7
|
+
data.tar.gz: fd175bdd332b8cdad9ad26baff8663364cfdadc8db1f65bc320864d5b409193c833c4045f21d21632e8f9b217423751ceaa86e92ffcbfd7a97cb67ab8c886c16
|
data/acpc_poker_types.gemspec
CHANGED
|
@@ -10,10 +10,10 @@ Gem::Specification.new do |s|
|
|
|
10
10
|
s.summary = %q{ACPC Poker Types}
|
|
11
11
|
s.description = %q{Poker classes and constants that conform to the standards of the Annual Computer Poker Competition.}
|
|
12
12
|
|
|
13
|
-
s.add_dependency 'dmorrill10-utils'
|
|
13
|
+
s.add_dependency 'dmorrill10-utils', '~> 1.0'
|
|
14
14
|
s.add_dependency 'acpc_dealer', '~> 0.0'
|
|
15
|
+
s.add_dependency 'celluloid', '~> 0.13'
|
|
15
16
|
|
|
16
|
-
s.add_development_dependency 'celluloid', '~> 0.13'
|
|
17
17
|
s.add_development_dependency 'awesome_print'
|
|
18
18
|
s.add_development_dependency 'minitest'
|
|
19
19
|
s.add_development_dependency 'turn'
|
|
@@ -41,12 +41,10 @@ module AcpcPokerTypes::AcpcDealerData
|
|
|
41
41
|
end
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
-
CONCATONATED_ACTIONS = AcpcPokerTypes::PokerAction::LEGAL_ACPC_CHARACTERS.to_a.join('')
|
|
45
|
-
|
|
46
44
|
# @param [String] from_message FROM message (message from player)
|
|
47
45
|
def self.parse_from_message(from_message)
|
|
48
46
|
if from_message.strip.match(
|
|
49
|
-
/^FROM\s*(\d+)\s*at\s*[\d\.]+\s*(#{AcpcPokerTypes::MatchState::LABEL}\S+):([#{CONCATONATED_ACTIONS}]\s*\d*)$/
|
|
47
|
+
/^FROM\s*(\d+)\s*at\s*[\d\.]+\s*(#{AcpcPokerTypes::MatchState::LABEL}\S+):([#{AcpcPokerTypes::PokerAction::CONCATONATED_ACTIONS}]\s*\d*)$/
|
|
50
48
|
)
|
|
51
49
|
FromMessage.new(
|
|
52
50
|
$1.to_i - 1,
|
|
@@ -330,7 +330,7 @@ module AcpcPokerTypes::AcpcDealerData
|
|
|
330
330
|
# return nil unless current_hand
|
|
331
331
|
|
|
332
332
|
# @match_def.game_def.min_wagers[current_hand.next_state.round]
|
|
333
|
-
# ChipStack.new [@min_wager.to_i, action_with_context.
|
|
333
|
+
# ChipStack.new [@min_wager.to_i, action_with_context.cost.to_i].max
|
|
334
334
|
# end
|
|
335
335
|
|
|
336
336
|
protected
|
|
@@ -1,50 +1,51 @@
|
|
|
1
|
-
|
|
2
|
-
require 'dmorrill10-utils/class'
|
|
3
|
-
|
|
4
1
|
require 'acpc_poker_types/pile_of_cards'
|
|
5
2
|
|
|
6
3
|
# List of community board cards.
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
module AcpcPokerTypes
|
|
5
|
+
class BoardCards < Array
|
|
6
|
+
def initialize(board_cards=[[]])
|
|
7
|
+
super(board_cards.map { |elem| AcpcPokerTypes::PileOfCards.new elem })
|
|
8
|
+
end
|
|
10
9
|
|
|
11
|
-
|
|
10
|
+
def round
|
|
11
|
+
self.length - 1
|
|
12
|
+
end
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
alias_method :array_push, :push
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
end
|
|
16
|
+
def next_round!
|
|
17
|
+
self.array_push AcpcPokerTypes::PileOfCards.new
|
|
18
|
+
self
|
|
19
|
+
end
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
def push(new_element)
|
|
22
|
+
self.last.push new_element
|
|
23
|
+
self
|
|
24
|
+
end
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
alias_method :<<, :push
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
28
|
+
# @return [String] The string representation of these board cards.
|
|
29
|
+
def to_s
|
|
30
|
+
if all? { |pile_for_round| pile_for_round.empty? }
|
|
31
|
+
''
|
|
32
|
+
else
|
|
33
|
+
'/' + (map { |pile_for_round| pile_for_round.join }).join('/')
|
|
34
|
+
end
|
|
34
35
|
end
|
|
35
|
-
end
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
37
|
+
# @see #to_s
|
|
38
|
+
alias_method :to_str, :to_s
|
|
39
|
+
|
|
40
|
+
# @return [String] The string representation of these board cards.
|
|
41
|
+
def to_acpc
|
|
42
|
+
if all? { |pile_for_round| pile_for_round.empty? }
|
|
43
|
+
''
|
|
44
|
+
else
|
|
45
|
+
'/' + (map do |pile_for_round|
|
|
46
|
+
(pile_for_round.map { |card| card.to_acpc }).join
|
|
47
|
+
end).join('/')
|
|
48
|
+
end
|
|
48
49
|
end
|
|
49
50
|
end
|
|
50
|
-
end
|
|
51
|
+
end
|
|
@@ -1,71 +1,57 @@
|
|
|
1
1
|
|
|
2
2
|
require 'dmorrill10-utils'
|
|
3
3
|
|
|
4
|
-
require
|
|
5
|
-
require
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
acpc_string_of_cards.scan(/[#{all_ranks}][#{all_suits}]/).inject([]) do |pile, acpc_card|
|
|
21
|
-
pile.push << AcpcPokerTypes::Card.from_acpc(acpc_card)
|
|
4
|
+
require 'acpc_poker_types/rank'
|
|
5
|
+
require 'acpc_poker_types/suit'
|
|
6
|
+
|
|
7
|
+
module AcpcPokerTypes
|
|
8
|
+
class Card
|
|
9
|
+
CONCATONATED_RANKS = (AcpcPokerTypes::Rank::DOMAIN.map { |rank, properties| properties[:acpc_character] }).join
|
|
10
|
+
CONCATONATED_SUITS = (AcpcPokerTypes::Suit::DOMAIN.map { |suit, properties| properties[:acpc_character] }).join
|
|
11
|
+
CONCATONATED_CARDS = CONCATONATED_RANKS + CONCATONATED_SUITS
|
|
12
|
+
|
|
13
|
+
# @param [String] acpc_string_of_cards A string of cards in ACPC format
|
|
14
|
+
# @return [Array<AcpcPokerTypes::Card>]
|
|
15
|
+
def self.cards(acpc_string_of_cards)
|
|
16
|
+
acpc_string_of_cards.scan(/[#{CONCATONATED_RANKS}][#{CONCATONATED_SUITS}]/).map do |acpc_card|
|
|
17
|
+
AcpcPokerTypes::Card.from_acpc(acpc_card)
|
|
18
|
+
end
|
|
22
19
|
end
|
|
23
|
-
end
|
|
24
20
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
attr_reader :rank, :suit
|
|
21
|
+
# @return [Integer] The numeric ACPC representation of the card.
|
|
22
|
+
def self.acpc_card_number(rank, suit)
|
|
23
|
+
rank.to_i * AcpcPokerTypes::Suit::DOMAIN.length + suit.to_i
|
|
24
|
+
end
|
|
31
25
|
|
|
32
|
-
|
|
33
|
-
def self.from_acpc(acpc_card)
|
|
34
|
-
all_ranks = AcpcPokerTypes::Rank::DOMAIN.values.map do |card_rank|
|
|
35
|
-
card_rank[:acpc_character]
|
|
36
|
-
end.join
|
|
37
|
-
all_suits = AcpcPokerTypes::Suit::DOMAIN.values.map do |card_suit|
|
|
38
|
-
card_suit[:acpc_character]
|
|
39
|
-
end.join
|
|
26
|
+
attr_reader :rank, :suit
|
|
40
27
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
28
|
+
# @return AcpcPokerTypes::Card
|
|
29
|
+
def self.from_acpc(acpc_card)
|
|
30
|
+
rank = acpc_card[0]
|
|
31
|
+
suit = acpc_card[1]
|
|
44
32
|
|
|
45
33
|
AcpcPokerTypes::Card.from_components rank, suit
|
|
46
|
-
else
|
|
47
|
-
raise ParseError, acpc_card
|
|
48
34
|
end
|
|
49
|
-
end
|
|
50
35
|
|
|
51
|
-
|
|
36
|
+
alias_new :from_components
|
|
52
37
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
38
|
+
def initialize(rank, suit)
|
|
39
|
+
@rank = AcpcPokerTypes::Rank.new rank
|
|
40
|
+
@suit = AcpcPokerTypes::Suit.new suit
|
|
41
|
+
end
|
|
57
42
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
43
|
+
def to_i
|
|
44
|
+
AcpcPokerTypes::Card.acpc_card_number(@rank, @suit)
|
|
45
|
+
end
|
|
61
46
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
47
|
+
def to_str
|
|
48
|
+
@rank.to_s + @suit.to_s
|
|
49
|
+
end
|
|
65
50
|
|
|
66
|
-
|
|
51
|
+
alias_method :to_s, :to_str
|
|
67
52
|
|
|
68
|
-
|
|
69
|
-
|
|
53
|
+
def to_acpc
|
|
54
|
+
@rank.to_acpc + @suit.to_acpc
|
|
55
|
+
end
|
|
70
56
|
end
|
|
71
|
-
end
|
|
57
|
+
end
|
|
@@ -1,38 +1,38 @@
|
|
|
1
|
-
|
|
2
1
|
require 'dmorrill10-utils/class'
|
|
3
|
-
|
|
4
2
|
require 'delegate'
|
|
5
3
|
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
module AcpcPokerTypes
|
|
5
|
+
class ChipStack < DelegateClass(Rational)
|
|
6
|
+
exceptions :illegal_number_of_chips
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
# @param [#to_i] number_of_chips The number of chips to be made into a stack.
|
|
9
|
+
# @raise (see #assert_valid_value)
|
|
10
|
+
def initialize(number_of_chips=0)
|
|
11
|
+
@value = number_of_chips.to_i
|
|
13
12
|
|
|
14
|
-
|
|
13
|
+
assert_valid_value
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
super @value
|
|
16
|
+
end
|
|
18
17
|
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
def receive!(number_of_chips)
|
|
19
|
+
@value += number_of_chips
|
|
21
20
|
|
|
22
|
-
|
|
21
|
+
assert_valid_value
|
|
23
22
|
|
|
24
|
-
|
|
23
|
+
__setobj__ @value
|
|
25
24
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
25
|
+
self
|
|
26
|
+
end
|
|
27
|
+
def give!(number_of_chips)
|
|
28
|
+
receive!(-number_of_chips)
|
|
29
|
+
end
|
|
31
30
|
|
|
32
|
-
|
|
31
|
+
private
|
|
33
32
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
# @raise IllegalNumberOfChips
|
|
34
|
+
def assert_valid_value
|
|
35
|
+
raise IllegalNumberOfChips if @value < 0
|
|
36
|
+
end
|
|
37
37
|
end
|
|
38
|
-
end
|
|
38
|
+
end
|
|
@@ -8,332 +8,334 @@ require 'acpc_poker_types/suit'
|
|
|
8
8
|
require 'acpc_poker_types/rank'
|
|
9
9
|
|
|
10
10
|
# Class that parses and manages game definition information from a game definition file.
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
list
|
|
11
|
+
module AcpcPokerTypes
|
|
12
|
+
class GameDefinition
|
|
13
|
+
exceptions :parse_error
|
|
14
|
+
|
|
15
|
+
# @return [String] The string designating the betting type.
|
|
16
|
+
attr_reader :betting_type
|
|
17
|
+
|
|
18
|
+
# @return [Integer] The number of players.
|
|
19
|
+
attr_reader :number_of_players
|
|
20
|
+
|
|
21
|
+
# @return [Integer] The number of rounds.
|
|
22
|
+
attr_reader :number_of_rounds
|
|
23
|
+
|
|
24
|
+
# @return [Array] The number of board cards in each round.
|
|
25
|
+
# @example The usual Texas hold'em sequence would look like this:
|
|
26
|
+
# number_of_board_cards == [0, 3, 1, 1]
|
|
27
|
+
attr_reader :number_of_board_cards
|
|
28
|
+
|
|
29
|
+
# @return [Array] The minimum wager in each round.
|
|
30
|
+
attr_reader :min_wagers
|
|
31
|
+
|
|
32
|
+
# @return [Array] The position relative to the dealer that is first to act
|
|
33
|
+
# in each round, indexed from 0.
|
|
34
|
+
# @example The usual Texas hold'em sequence would look like this:
|
|
35
|
+
# first_player_positions == [1, 0, 0, 0]
|
|
36
|
+
attr_reader :first_player_positions
|
|
37
|
+
|
|
38
|
+
# @return [Array] The maximum number of wagers in each round.
|
|
39
|
+
attr_reader :max_number_of_wagers
|
|
40
|
+
|
|
41
|
+
# @return [Array] The list containing the initial stack size for every player.
|
|
42
|
+
attr_reader :chip_stacks
|
|
43
|
+
|
|
44
|
+
# @return [Integer] The number of suits in the deck.
|
|
45
|
+
attr_reader :number_of_suits
|
|
46
|
+
|
|
47
|
+
# @return [Integer] The number of ranks in the deck.
|
|
48
|
+
attr_reader :number_of_ranks
|
|
49
|
+
|
|
50
|
+
# @return [Integer] The number of hole cards that each player is dealt.
|
|
51
|
+
attr_reader :number_of_hole_cards
|
|
52
|
+
|
|
53
|
+
# @return [Array] The list of blind sizes.
|
|
54
|
+
attr_reader :blinds
|
|
55
|
+
|
|
56
|
+
# @return [Integer] The maximum value of an eight bit unsigned integer (for consistency with the ACPC Dealer).
|
|
57
|
+
UINT8_MAX = 2**8 - 1
|
|
58
|
+
|
|
59
|
+
DEFAULT_MAX_NUMBER_OF_WAGERS = UINT8_MAX
|
|
60
|
+
|
|
61
|
+
# @return [Integer] The maximum value of a 32 bit signed integer (for consistency with the ACPC Dealer).
|
|
62
|
+
INT32_MAX = 2**31 - 1
|
|
63
|
+
|
|
64
|
+
DEFAULT_CHIP_STACK = INT32_MAX
|
|
65
|
+
|
|
66
|
+
# @return [Hash] Maximum game parameter values.
|
|
67
|
+
MIN_VALUES = {
|
|
68
|
+
:@number_of_rounds => 1,
|
|
69
|
+
:@number_of_players => 2,
|
|
70
|
+
:@number_of_hole_cards => 1,
|
|
71
|
+
:@number_of_suits => 1,
|
|
72
|
+
:@number_of_ranks => 2
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
MAX_VALUES = {
|
|
76
|
+
:@number_of_suits => AcpcPokerTypes::Suit::DOMAIN.length,
|
|
77
|
+
:@number_of_ranks => AcpcPokerTypes::Rank::DOMAIN.length
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
# @return [Hash] Betting types understood by this class.
|
|
81
|
+
BETTING_TYPES = {
|
|
82
|
+
:limit => 'limit',
|
|
83
|
+
:nolimit => 'nolimit'
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
DEFINITIONS = {
|
|
87
|
+
:@chip_stacks => 'stack',
|
|
88
|
+
:@number_of_players => 'numPlayers',
|
|
89
|
+
:@blinds => 'blind',
|
|
90
|
+
:@raise_sizes => 'raiseSize',
|
|
91
|
+
:@number_of_rounds => 'numRounds',
|
|
92
|
+
:@first_player_positions => 'firstPlayer',
|
|
93
|
+
:@max_number_of_wagers => 'maxRaises',
|
|
94
|
+
:@number_of_suits => 'numSuits',
|
|
95
|
+
:@number_of_ranks => 'numRanks',
|
|
96
|
+
:@number_of_hole_cards => 'numHoleCards',
|
|
97
|
+
:@number_of_board_cards => 'numBoardCards'
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
def self.default_first_player_positions(number_of_rounds)
|
|
101
|
+
number_of_rounds.to_i.times.inject([]) do |list, i|
|
|
102
|
+
list << 0
|
|
103
|
+
end
|
|
102
104
|
end
|
|
103
|
-
end
|
|
104
105
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
106
|
+
# @return [Array] The default maximum raise in each round.
|
|
107
|
+
def self.default_max_number_of_wagers(number_of_rounds)
|
|
108
|
+
number_of_rounds.to_i.times.inject([]) do |list, i|
|
|
109
|
+
list << DEFAULT_MAX_NUMBER_OF_WAGERS
|
|
110
|
+
end
|
|
109
111
|
end
|
|
110
|
-
end
|
|
111
112
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
113
|
+
# @param [Integer] number_of_players The number of players that require stacks.
|
|
114
|
+
# @return [Array<AcpcPokerTypes::ChipStack>] The default list of initial stacks for every player.
|
|
115
|
+
def self.default_chip_stacks(number_of_players)
|
|
116
|
+
number_of_players.to_i.times.inject([]) do |list, i|
|
|
117
|
+
list << AcpcPokerTypes::ChipStack.new(DEFAULT_CHIP_STACK)
|
|
118
|
+
end
|
|
117
119
|
end
|
|
118
|
-
end
|
|
119
120
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
121
|
+
# @param [Array] array The array to flatten into a single element.
|
|
122
|
+
# @return +array+ if +array+ has more than one element, the single element in +array+ otherwise.
|
|
123
|
+
def self.flatten_if_single_element_array(array)
|
|
124
|
+
if 1 == array.length then array[0] else array end
|
|
125
|
+
end
|
|
125
126
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
127
|
+
# Checks if the given line is a comment beginning with '#' or ';', or empty.
|
|
128
|
+
#
|
|
129
|
+
# @param [String] line
|
|
130
|
+
# @return [Boolean] True if +line+ is a comment or empty, false otherwise.
|
|
131
|
+
def self.line_is_comment_or_empty?(line)
|
|
132
|
+
line.nil? || line.match(/^\s*[#;]/) || line.empty?
|
|
133
|
+
end
|
|
133
134
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
135
|
+
# Checks a given line from a game definition file for a game
|
|
136
|
+
# definition name and returns the given default value unless there is a match.
|
|
137
|
+
#
|
|
138
|
+
# @param [String, #match] line A line from a game definition file.
|
|
139
|
+
# @param [String] definition_name The name of the game definition that is
|
|
140
|
+
# being checked for in +line+.
|
|
141
|
+
# @return The game definition value in +line+ if +line+ contains the game definition
|
|
142
|
+
# referred to by +definition_name+, +nil+ otherwise.
|
|
143
|
+
def self.check_game_def_line_for_definition(line, definition_name)
|
|
144
|
+
if line.match(/^\s*#{definition_name}\s*=\s*([\d\s]+)/i)
|
|
145
|
+
values = $1.chomp.split(/\s+/)
|
|
146
|
+
(0..values.length-1).each do |i|
|
|
147
|
+
values[i] = values[i].to_i
|
|
148
|
+
end
|
|
149
|
+
flatten_if_single_element_array values
|
|
147
150
|
end
|
|
148
|
-
flatten_if_single_element_array values
|
|
149
151
|
end
|
|
150
|
-
end
|
|
151
152
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
153
|
+
# Checks if the given line from a game definition file is informative or not
|
|
154
|
+
# (in which case the line is either: a comment beginning with '#', empty, or
|
|
155
|
+
# contains 'gamedef').
|
|
156
|
+
#
|
|
157
|
+
# @return [String] line The line to check.
|
|
158
|
+
# @return [Boolean] +true+ if the line is not informative, +false+ otherwise.
|
|
159
|
+
def self.game_def_line_not_informative?(line)
|
|
160
|
+
line_is_comment_or_empty?(line) || line.match(/\s*gamedef\s*/i)
|
|
161
|
+
end
|
|
161
162
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
163
|
+
# @param [String] game_definition_file_name The name of the game definition file that this instance should parse.
|
|
164
|
+
def self.parse_file(game_definition_file_name)
|
|
165
|
+
File.open(game_definition_file_name, 'r') { |file| parse file }
|
|
166
|
+
end
|
|
166
167
|
|
|
167
|
-
|
|
168
|
+
alias_new :parse
|
|
168
169
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
170
|
+
def initialize(definitions)
|
|
171
|
+
initialize_members!
|
|
172
|
+
parse_definitions! definitions
|
|
172
173
|
|
|
173
|
-
|
|
174
|
+
@chip_stacks = AcpcPokerTypes::GameDefinition.default_chip_stacks(@number_of_players) if @chip_stacks.empty?
|
|
174
175
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
sanity_check_game_definitions!
|
|
180
|
-
end
|
|
176
|
+
unless @first_player_positions.any? { |pos| pos <= 0 }
|
|
177
|
+
@first_player_positions.map! { |position| position - 1 }
|
|
178
|
+
end
|
|
181
179
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
end
|
|
180
|
+
sanity_check_game_definitions!
|
|
181
|
+
end
|
|
185
182
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
list_of_lines = []
|
|
190
|
-
list_of_lines << BETTING_TYPES[@betting_type] if @betting_type
|
|
191
|
-
list_of_lines << "stack = #{@chip_stacks.join(' ')}" unless @chip_stacks.empty?
|
|
192
|
-
list_of_lines << "numPlayers = #{@number_of_players}" if @number_of_players
|
|
193
|
-
list_of_lines << "blind = #{@blinds.join(' ')}" unless @blinds.empty?
|
|
194
|
-
list_of_lines << "raiseSize = #{min_wagers.join(' ')}" unless min_wagers.empty?
|
|
195
|
-
list_of_lines << "numRounds = #{@number_of_rounds}" if @number_of_rounds
|
|
196
|
-
list_of_lines << "firstPlayer = #{(@first_player_positions.map{|p| p + 1}).join(' ')}" unless @first_player_positions.empty?
|
|
197
|
-
list_of_lines << "maxRaises = #{@max_number_of_wagers.join(' ')}" unless @max_number_of_wagers.empty?
|
|
198
|
-
list_of_lines << "numSuits = #{@number_of_suits}" if @number_of_suits
|
|
199
|
-
list_of_lines << "numRanks = #{@number_of_ranks}" if @number_of_ranks
|
|
200
|
-
list_of_lines << "numHoleCards = #{@number_of_hole_cards}" if @number_of_hole_cards
|
|
201
|
-
list_of_lines << "numBoardCards = #{@number_of_board_cards.join(' ')}" unless @number_of_board_cards.empty?
|
|
202
|
-
list_of_lines
|
|
203
|
-
end
|
|
183
|
+
def to_s
|
|
184
|
+
to_a.join("\n")
|
|
185
|
+
end
|
|
204
186
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
187
|
+
alias_method :to_str, :to_s
|
|
188
|
+
|
|
189
|
+
def to_a
|
|
190
|
+
list_of_lines = []
|
|
191
|
+
list_of_lines << BETTING_TYPES[@betting_type] if @betting_type
|
|
192
|
+
list_of_lines << "stack = #{@chip_stacks.join(' ')}" unless @chip_stacks.empty?
|
|
193
|
+
list_of_lines << "numPlayers = #{@number_of_players}" if @number_of_players
|
|
194
|
+
list_of_lines << "blind = #{@blinds.join(' ')}" unless @blinds.empty?
|
|
195
|
+
list_of_lines << "raiseSize = #{min_wagers.join(' ')}" unless min_wagers.empty?
|
|
196
|
+
list_of_lines << "numRounds = #{@number_of_rounds}" if @number_of_rounds
|
|
197
|
+
list_of_lines << "firstPlayer = #{(@first_player_positions.map{|p| p + 1}).join(' ')}" unless @first_player_positions.empty?
|
|
198
|
+
list_of_lines << "maxRaises = #{@max_number_of_wagers.join(' ')}" unless @max_number_of_wagers.empty?
|
|
199
|
+
list_of_lines << "numSuits = #{@number_of_suits}" if @number_of_suits
|
|
200
|
+
list_of_lines << "numRanks = #{@number_of_ranks}" if @number_of_ranks
|
|
201
|
+
list_of_lines << "numHoleCards = #{@number_of_hole_cards}" if @number_of_hole_cards
|
|
202
|
+
list_of_lines << "numBoardCards = #{@number_of_board_cards.join(' ')}" unless @number_of_board_cards.empty?
|
|
203
|
+
list_of_lines
|
|
204
|
+
end
|
|
208
205
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
@raise_sizes
|
|
212
|
-
else
|
|
213
|
-
@number_of_rounds.times.map { |i| @blinds.max }
|
|
206
|
+
def ==(other_game_definition)
|
|
207
|
+
Set.new(to_a) == Set.new(other_game_definition.to_a)
|
|
214
208
|
end
|
|
215
|
-
end
|
|
216
209
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
@number_of_board_cards = @number_of_rounds.times.inject([]) { |cards, i| cards << 0 }
|
|
225
|
-
@first_player_positions = AcpcPokerTypes::GameDefinition.default_first_player_positions @number_of_rounds
|
|
226
|
-
@max_number_of_wagers = AcpcPokerTypes::GameDefinition.default_max_number_of_wagers @number_of_rounds
|
|
227
|
-
@chip_stacks = AcpcPokerTypes::GameDefinition.default_chip_stacks @number_of_players
|
|
228
|
-
@number_of_suits = MIN_VALUES[:@number_of_suits]
|
|
229
|
-
@number_of_ranks = MIN_VALUES[:@number_of_ranks]
|
|
230
|
-
@number_of_hole_cards = MIN_VALUES[:@number_of_hole_cards]
|
|
231
|
-
|
|
232
|
-
self
|
|
233
|
-
end
|
|
210
|
+
def min_wagers
|
|
211
|
+
if @raise_sizes
|
|
212
|
+
@raise_sizes
|
|
213
|
+
else
|
|
214
|
+
@number_of_rounds.times.map { |i| @blinds.max }
|
|
215
|
+
end
|
|
216
|
+
end
|
|
234
217
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
218
|
+
private
|
|
219
|
+
|
|
220
|
+
def initialize_members!
|
|
221
|
+
@betting_type = BETTING_TYPES[:limit]
|
|
222
|
+
@number_of_players = MIN_VALUES[:@number_of_players]
|
|
223
|
+
@blinds = @number_of_players.times.inject([]) { |blinds, i| blinds << 0 }
|
|
224
|
+
@number_of_rounds = MIN_VALUES[:@number_of_rounds]
|
|
225
|
+
@number_of_board_cards = @number_of_rounds.times.inject([]) { |cards, i| cards << 0 }
|
|
226
|
+
@first_player_positions = AcpcPokerTypes::GameDefinition.default_first_player_positions @number_of_rounds
|
|
227
|
+
@max_number_of_wagers = AcpcPokerTypes::GameDefinition.default_max_number_of_wagers @number_of_rounds
|
|
228
|
+
@chip_stacks = AcpcPokerTypes::GameDefinition.default_chip_stacks @number_of_players
|
|
229
|
+
@number_of_suits = MIN_VALUES[:@number_of_suits]
|
|
230
|
+
@number_of_ranks = MIN_VALUES[:@number_of_ranks]
|
|
231
|
+
@number_of_hole_cards = MIN_VALUES[:@number_of_hole_cards]
|
|
232
|
+
|
|
233
|
+
self
|
|
245
234
|
end
|
|
246
|
-
end
|
|
247
235
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
AcpcPokerTypes::GameDefinition.game_def_line_not_informative?(line) ||
|
|
253
|
-
BETTING_TYPES.any? do |type_and_name|
|
|
254
|
-
type = type_and_name.first
|
|
255
|
-
name = type_and_name[1]
|
|
256
|
-
if line.match(/\b#{name}\b/i)
|
|
257
|
-
@betting_type = type
|
|
258
|
-
true
|
|
259
|
-
else
|
|
260
|
-
false
|
|
261
|
-
end
|
|
262
|
-
end ||
|
|
263
|
-
DEFINITIONS.any? do |symbol, string|
|
|
264
|
-
set_defintion_if_present!(symbol, line, string)
|
|
265
|
-
end
|
|
236
|
+
def set_defintion_if_present!(definition_symbol, line, definition_label_in_line)
|
|
237
|
+
new_definition = AcpcPokerTypes::GameDefinition.check_game_def_line_for_definition(
|
|
238
|
+
line,
|
|
239
|
+
definition_label_in_line
|
|
266
240
|
)
|
|
241
|
+
if new_definition
|
|
242
|
+
instance_variable_set(definition_symbol, new_definition)
|
|
243
|
+
true
|
|
244
|
+
else
|
|
245
|
+
false
|
|
246
|
+
end
|
|
267
247
|
end
|
|
268
248
|
|
|
269
|
-
|
|
270
|
-
|
|
249
|
+
def parse_definitions!(definitions)
|
|
250
|
+
definitions.each do |line|
|
|
251
|
+
break if line.match(/\bend\s*gamedef\b/i)
|
|
252
|
+
next if (
|
|
253
|
+
AcpcPokerTypes::GameDefinition.game_def_line_not_informative?(line) ||
|
|
254
|
+
BETTING_TYPES.any? do |type_and_name|
|
|
255
|
+
type = type_and_name.first
|
|
256
|
+
name = type_and_name[1]
|
|
257
|
+
if line.match(/\b#{name}\b/i)
|
|
258
|
+
@betting_type = type
|
|
259
|
+
true
|
|
260
|
+
else
|
|
261
|
+
false
|
|
262
|
+
end
|
|
263
|
+
end ||
|
|
264
|
+
DEFINITIONS.any? do |symbol, string|
|
|
265
|
+
set_defintion_if_present!(symbol, line, string)
|
|
266
|
+
end
|
|
267
|
+
)
|
|
268
|
+
end
|
|
271
269
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
adjust_definitions_if_necessary!
|
|
270
|
+
self
|
|
271
|
+
end
|
|
275
272
|
|
|
276
|
-
raise ParseError
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
273
|
+
# @raise ParseError
|
|
274
|
+
def sanity_check_game_definitions!
|
|
275
|
+
adjust_definitions_if_necessary!
|
|
276
|
+
|
|
277
|
+
raise ParseError, "list of player stacks not specified" unless @chip_stacks
|
|
278
|
+
raise ParseError, "list of blinds not specified" unless @blinds
|
|
279
|
+
raise ParseError, "raise size in each round not specified" unless min_wagers
|
|
280
|
+
raise ParseError, "first player position in each round not specified" unless @first_player_positions
|
|
281
|
+
raise ParseError, "maximum raise in each round not specified" unless @max_number_of_wagers
|
|
282
|
+
raise ParseError, "number of board cards in each round not specified" unless @number_of_board_cards
|
|
283
|
+
|
|
284
|
+
MIN_VALUES.each do |symbol, min_value|
|
|
285
|
+
if instance_variable_get(symbol) < min_value
|
|
286
|
+
raise(
|
|
287
|
+
ParseError,
|
|
288
|
+
"Invalid definition, #{DEFINITION[symbol]} must be greater than #{min_value} but was set to #{instance_variable_get(symbol)}"
|
|
289
|
+
)
|
|
290
|
+
end
|
|
291
|
+
end
|
|
282
292
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
293
|
+
(0..@number_of_players-1).each do |i|
|
|
294
|
+
if @blinds[i] > @chip_stacks[i]
|
|
295
|
+
raise(
|
|
296
|
+
ParseError,
|
|
297
|
+
"Blind for player #{i+1} (#{@blinds[i]}) is greater than stack size (#{@chip_stacks[i]})"
|
|
298
|
+
)
|
|
299
|
+
end
|
|
289
300
|
end
|
|
290
|
-
end
|
|
291
301
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
302
|
+
@number_of_rounds.times do |i|
|
|
303
|
+
unless @first_player_positions[i].seat_in_bounds? @number_of_players
|
|
304
|
+
raise(
|
|
305
|
+
ParseError,
|
|
306
|
+
"Invalid first player #{@first_player_positions[i]} on round #{i+1}"
|
|
307
|
+
)
|
|
308
|
+
end
|
|
298
309
|
end
|
|
299
|
-
end
|
|
300
310
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
311
|
+
MAX_VALUES.each do |symbol, max_value|
|
|
312
|
+
if instance_variable_get(symbol) > max_value
|
|
313
|
+
raise(
|
|
314
|
+
ParseError,
|
|
315
|
+
"Invalid definition, #{DEFINITIONS[symbol]} must be less than #{max_value} but was set to #{instance_variable_get(symbol)}"
|
|
316
|
+
)
|
|
317
|
+
end
|
|
307
318
|
end
|
|
308
|
-
end
|
|
309
319
|
|
|
310
|
-
|
|
311
|
-
|
|
320
|
+
number_of_cards_required = (@number_of_hole_cards * @number_of_players) + @number_of_board_cards.sum
|
|
321
|
+
|
|
322
|
+
if number_of_cards_required > (@number_of_suits * @number_of_ranks)
|
|
312
323
|
raise(
|
|
313
324
|
ParseError,
|
|
314
|
-
"
|
|
325
|
+
"Too many hole and board cards (#{number_of_cards_required}) for specified deck (#{(@number_of_suits * @number_of_ranks)})"
|
|
315
326
|
)
|
|
316
327
|
end
|
|
317
328
|
end
|
|
318
329
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
def adjust_definitions_if_necessary!
|
|
330
|
-
@number_of_players.times do |i|
|
|
331
|
-
@blinds << 0 unless @blinds.length > i
|
|
332
|
-
@chip_stacks << DEFAULT_CHIP_STACK unless @chip_stacks.length > i
|
|
333
|
-
end
|
|
334
|
-
@number_of_rounds.times do |i|
|
|
335
|
-
@first_player_positions << 0 unless @first_player_positions.length > i
|
|
336
|
-
@number_of_board_cards << 0 unless @number_of_board_cards.length > i
|
|
330
|
+
def adjust_definitions_if_necessary!
|
|
331
|
+
@number_of_players.times do |i|
|
|
332
|
+
@blinds << 0 unless @blinds.length > i
|
|
333
|
+
@chip_stacks << DEFAULT_CHIP_STACK unless @chip_stacks.length > i
|
|
334
|
+
end
|
|
335
|
+
@number_of_rounds.times do |i|
|
|
336
|
+
@first_player_positions << 0 unless @first_player_positions.length > i
|
|
337
|
+
@number_of_board_cards << 0 unless @number_of_board_cards.length > i
|
|
338
|
+
end
|
|
337
339
|
end
|
|
338
340
|
end
|
|
339
|
-
end
|
|
341
|
+
end
|