acpc_poker_types 6.1.2 → 6.2.0
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/lib/acpc_poker_types/hand_player.rb +4 -8
- data/lib/acpc_poker_types/match_state.rb +44 -22
- data/lib/acpc_poker_types/player_group.rb +6 -0
- data/lib/acpc_poker_types/seat.rb +36 -32
- data/lib/acpc_poker_types/version.rb +1 -1
- data/spec/match_state_spec.rb +64 -40
- data/spec/seat_spec.rb +59 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fbed7f982f75101fa5ea0655986ed7e2d39ea77e
|
4
|
+
data.tar.gz: bdc7f86c7351298a819751e1cb9cda56ad9746ff
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b8feecf734cd9636bed880b3a8be93bbbb6c8e21c4b77212c127d80f130098287691b326343b7b3ce2e6d3afc5cf0fef6edd4f414e4a9c103e5a4b39caf11600
|
7
|
+
data.tar.gz: aad719143fe546905d0ff49207f2ae4f284c7c83f3a38a50c49a8caf1f71ab54ca4033f4231553f079106a8d3dd73584332c2fcb7ce205af5c5566f804325d5d
|
@@ -87,17 +87,13 @@ class HandPlayer
|
|
87
87
|
l_actions
|
88
88
|
end
|
89
89
|
|
90
|
-
# @param round [Integer] The round in which the largest wager by size is desired.
|
91
|
-
# defaults to +nil+.
|
92
|
-
# @return [ChipStack] The largest wager by size this player has made.
|
93
|
-
# Checks only in the specified +round+ or over the entire hand if round is +nil+.
|
94
|
-
# def largest_wager_by(round=nil)
|
95
|
-
# @todo
|
96
|
-
# end
|
97
|
-
|
98
90
|
def append_action!(action, round_num = round)
|
99
91
|
raise Inactive if inactive?
|
100
92
|
|
93
|
+
while @actions.length <= round_num
|
94
|
+
@actions << []
|
95
|
+
end
|
96
|
+
|
101
97
|
@actions[round_num] ||= []
|
102
98
|
@actions[round_num] << action
|
103
99
|
|
@@ -51,12 +51,8 @@ class MatchState
|
|
51
51
|
# @return [String] The ACPC string created by the given betting sequence.
|
52
52
|
attr_reader :betting_sequence_string
|
53
53
|
|
54
|
-
# @todo Move this @return [Array<Hand>] The list of visible hole card sets for each player.
|
55
|
-
|
56
54
|
attr_reader :hands_string
|
57
55
|
|
58
|
-
# @todo Move this @return [BoardCards] All visible community cards on the board.
|
59
|
-
|
60
56
|
attr_reader :community_cards_string
|
61
57
|
|
62
58
|
# @return [String] Label for match state strings.
|
@@ -107,6 +103,7 @@ class MatchState
|
|
107
103
|
@hands_string = $4
|
108
104
|
@community_cards_string = $5
|
109
105
|
end
|
106
|
+
@min_wager_by = nil
|
110
107
|
end
|
111
108
|
|
112
109
|
# @return [String] The MatchState in raw text form.
|
@@ -129,6 +126,7 @@ class MatchState
|
|
129
126
|
another_match_state.to_s == to_s
|
130
127
|
end
|
131
128
|
|
129
|
+
# @return [Array<Hand>] The list of hole card hands for each player.
|
132
130
|
def all_hands
|
133
131
|
@all_hands ||= -> do
|
134
132
|
lcl_hole_card_hands = all_string_hands(@hands_string).map do |string_hand|
|
@@ -160,6 +158,7 @@ class MatchState
|
|
160
158
|
end
|
161
159
|
end
|
162
160
|
|
161
|
+
# @return [BoardCards] All visible community cards on the board.
|
163
162
|
def community_cards
|
164
163
|
@community_cards ||= -> do
|
165
164
|
lcl_community_cards = BoardCards.new(
|
@@ -264,20 +263,23 @@ class MatchState
|
|
264
263
|
@players = players_at_hand_start game_def.chip_stacks, game_def.blinds
|
265
264
|
|
266
265
|
last_round = -1
|
267
|
-
|
266
|
+
@next_to_act = nil
|
268
267
|
@player_acting_sequence = []
|
268
|
+
@min_wager_by = game_def.min_wagers.first
|
269
269
|
every_action_token do |action, round|
|
270
270
|
if round != last_round
|
271
|
-
|
271
|
+
@min_wager_by = game_def.min_wagers[round]
|
272
|
+
@next_to_act = @players.position_of_first_active_player(
|
273
|
+
game_def.first_player_positions[round]
|
274
|
+
)
|
272
275
|
@player_acting_sequence << []
|
273
276
|
last_round = round
|
274
277
|
end
|
275
278
|
|
276
|
-
|
277
|
-
|
278
|
-
)
|
279
|
+
@player_acting_sequence.last << @next_to_act
|
280
|
+
acting_player_position = @player_acting_sequence.last.last
|
279
281
|
|
280
|
-
@
|
282
|
+
@next_to_act = @players.next_to_act(@next_to_act)
|
281
283
|
|
282
284
|
cost = @players.action_cost(
|
283
285
|
acting_player_position,
|
@@ -285,20 +287,13 @@ class MatchState
|
|
285
287
|
game_def.min_wagers[round]
|
286
288
|
)
|
287
289
|
|
288
|
-
|
289
|
-
if cost > 0
|
290
|
-
action = PokerAction.new(action.to_s, cost: cost)
|
291
|
-
else
|
292
|
-
action
|
293
|
-
end,
|
294
|
-
round
|
295
|
-
)
|
290
|
+
action = PokerAction.new(action.to_s, cost: cost) if cost > 0
|
296
291
|
|
297
|
-
|
292
|
+
adjust_min_wager!(action, acting_player_position)
|
298
293
|
|
299
|
-
|
300
|
-
|
301
|
-
|
294
|
+
@players[acting_player_position].append_action!(action, round)
|
295
|
+
|
296
|
+
yield action, round, acting_player_position, @players if block_given?
|
302
297
|
end
|
303
298
|
|
304
299
|
distribute_chips!(game_def) if hand_ended?(game_def)
|
@@ -306,6 +301,12 @@ class MatchState
|
|
306
301
|
@players
|
307
302
|
end
|
308
303
|
|
304
|
+
def next_to_act(game_def)
|
305
|
+
every_action(game_def) unless @next_to_act
|
306
|
+
|
307
|
+
@next_to_act
|
308
|
+
end
|
309
|
+
|
309
310
|
def players(game_def)
|
310
311
|
@players ||= every_action(game_def)
|
311
312
|
end
|
@@ -337,6 +338,13 @@ class MatchState
|
|
337
338
|
@pot ||= players(game_def).map { |player| player.contributions }.flatten.inject(:+)
|
338
339
|
end
|
339
340
|
|
341
|
+
# @return [ChipStack] Minimum wager by.
|
342
|
+
def min_wager_by(game_def)
|
343
|
+
every_action(game_def) unless @min_wager_by
|
344
|
+
|
345
|
+
@min_wager_by
|
346
|
+
end
|
347
|
+
|
340
348
|
private
|
341
349
|
|
342
350
|
# Distribute chips to all winning players
|
@@ -388,5 +396,19 @@ class MatchState
|
|
388
396
|
def actions_from_acpc_characters(action_sequence)
|
389
397
|
action_sequence.scan(/[^#{BETTING_SEQUENCE_SEPARATOR}\d]\d*/)
|
390
398
|
end
|
399
|
+
|
400
|
+
def adjust_min_wager!(action, acting_player_position)
|
401
|
+
return self unless PokerAction::MODIFIABLE_ACTIONS.include?(action.action)
|
402
|
+
|
403
|
+
wager_size = ChipStack.new(
|
404
|
+
action.cost.to_f - @players.amount_to_call(acting_player_position)
|
405
|
+
)
|
406
|
+
|
407
|
+
return self unless wager_size > @min_wager_by
|
408
|
+
|
409
|
+
@min_wager_by = wager_size
|
410
|
+
|
411
|
+
self
|
412
|
+
end
|
391
413
|
end
|
392
414
|
end
|
@@ -1,42 +1,46 @@
|
|
1
1
|
require 'delegate'
|
2
2
|
|
3
3
|
module AcpcPokerTypes
|
4
|
-
class Seat < DelegateClass(Integer)
|
5
|
-
attr_reader :seat, :table_size
|
6
4
|
|
7
|
-
|
8
|
-
|
9
|
-
def self.in_bounds?(seat, num_seats)
|
10
|
-
seat < num_seats && seat >= 0
|
11
|
-
end
|
5
|
+
class Seat < DelegateClass(Integer)
|
6
|
+
attr_reader :seat, :table_size
|
12
7
|
|
13
|
-
|
14
|
-
|
15
|
-
|
8
|
+
# @return [Bool] Reports whether or not +seat+ represents an out of
|
9
|
+
# bounds seat for the number of seats, +num_seats+.
|
10
|
+
def self.in_bounds?(seat, num_seats)
|
11
|
+
seat < num_seats && seat >= 0
|
12
|
+
end
|
16
13
|
|
17
|
-
|
18
|
-
|
19
|
-
|
14
|
+
def initialize(seat, num_seats_at_table)
|
15
|
+
@seat = (seat_number(seat) % num_seats_at_table).to_i
|
16
|
+
@table_size = num_seats_at_table
|
20
17
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
18
|
+
super @seat
|
19
|
+
end
|
20
|
+
def seats_to(other_player)
|
21
|
+
other_seat = self.class.new(other_player, @table_size)
|
22
|
+
|
23
|
+
if @seat > other_seat
|
24
|
+
other_seat + @table_size
|
25
|
+
else
|
26
|
+
other_seat
|
27
|
+
end - @seat
|
28
|
+
end
|
29
|
+
def seats_from(other_player)
|
30
|
+
self.class.new(other_player, @table_size).seats_to(@seat)
|
31
|
+
end
|
32
|
+
def n_seats_away(n)
|
33
|
+
Seat.new((n + @seat) % @table_size, @table_size)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def seat_number(player_or_seat)
|
39
|
+
if player_or_seat.respond_to?(:seat)
|
40
|
+
player_or_seat.seat
|
41
|
+
else
|
42
|
+
player_or_seat
|
40
43
|
end
|
41
44
|
end
|
45
|
+
end
|
42
46
|
end
|
data/spec/match_state_spec.rb
CHANGED
@@ -9,6 +9,7 @@ require_relative "../lib/acpc_poker_types/suit"
|
|
9
9
|
require_relative "../lib/acpc_poker_types/hand"
|
10
10
|
require_relative "../lib/acpc_poker_types/card"
|
11
11
|
require_relative "../lib/acpc_poker_types/game_definition"
|
12
|
+
require_relative "../lib/acpc_poker_types/acpc_dealer_data/poker_match_data"
|
12
13
|
|
13
14
|
module MapWithIndex
|
14
15
|
refine Array do
|
@@ -269,7 +270,7 @@ describe MatchState do
|
|
269
270
|
end[0..-2]
|
270
271
|
|
271
272
|
match_state =
|
272
|
-
"#{MatchState::LABEL}:#{position}:0:crcc/ccc/rrfc:#{hand_string}"
|
273
|
+
"#{MatchState::LABEL}:#{position}:0:crcc/ccc/rrfc:#{hand_string}"
|
273
274
|
|
274
275
|
MatchState.new(
|
275
276
|
match_state
|
@@ -377,7 +378,7 @@ describe MatchState do
|
|
377
378
|
end[0..-2]
|
378
379
|
|
379
380
|
match_state =
|
380
|
-
"#{MatchState::LABEL}:#{position}:0:crcc/ccc/rrfc/crc:#{hand_string}"
|
381
|
+
"#{MatchState::LABEL}:#{position}:0:crcc/ccc/rrfc/crc:#{hand_string}"
|
381
382
|
|
382
383
|
MatchState.new(match_state).every_action(x_game_def) do |action, round, acting_player_position|
|
383
384
|
x_yields = x_actions.shift
|
@@ -390,7 +391,7 @@ describe MatchState do
|
|
390
391
|
end
|
391
392
|
end
|
392
393
|
describe '#players' do
|
393
|
-
it '
|
394
|
+
it 'returns proper player states' do
|
394
395
|
wager_size = 10
|
395
396
|
x_game_def = GameDefinition.new(
|
396
397
|
first_player_positions: [3, 2, 2],
|
@@ -574,37 +575,37 @@ describe MatchState do
|
|
574
575
|
end
|
575
576
|
end
|
576
577
|
end
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
578
|
+
end
|
579
|
+
describe '#pot' do
|
580
|
+
it 'works without side pots' do
|
581
|
+
wager_size = 10
|
582
|
+
x_game_def = GameDefinition.new(
|
583
|
+
first_player_positions: [3, 2, 2, 2],
|
584
|
+
chip_stacks: [100, 200, 150],
|
585
|
+
blinds: [0, 10, 5],
|
586
|
+
raise_sizes: [wager_size]*4,
|
587
|
+
number_of_ranks: 3
|
588
|
+
)
|
589
|
+
x_total_contributions = [2 * 10, 5 * 10, 5 * 10]
|
588
590
|
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
591
|
+
(0..x_game_def.number_of_players-1).each do |position|
|
592
|
+
hands = x_game_def.number_of_players.times.map do |i|
|
593
|
+
Hand.from_acpc "Ac2#{['s', 'h', 'd', 'c'][i%4]}"
|
594
|
+
end
|
593
595
|
|
594
|
-
|
595
|
-
|
596
|
-
|
596
|
+
hand_string = hands.inject('') do |hand_string, hand|
|
597
|
+
hand_string << "#{hand}#{MatchState::HAND_SEPARATOR}"
|
598
|
+
end[0..-2]
|
597
599
|
|
598
|
-
|
599
|
-
|
600
|
+
match_state =
|
601
|
+
"#{MatchState::LABEL}:#{position}:0:crcc/ccc/rrfc/crc:#{hand_string}"
|
600
602
|
|
601
|
-
|
602
|
-
end
|
603
|
+
MatchState.new(match_state).pot(x_game_def).must_equal x_total_contributions.inject(:+)
|
603
604
|
end
|
604
605
|
end
|
605
606
|
end
|
606
|
-
describe '#
|
607
|
-
it '
|
607
|
+
describe '#player_acting_sequence' do
|
608
|
+
it 'works' do
|
608
609
|
wager_size = 10
|
609
610
|
x_game_def = GameDefinition.new(
|
610
611
|
first_player_positions: [3, 2, 2, 2],
|
@@ -704,7 +705,7 @@ describe MatchState do
|
|
704
705
|
end
|
705
706
|
end
|
706
707
|
end
|
707
|
-
describe 'hand_ended?' do
|
708
|
+
describe '#hand_ended?' do
|
708
709
|
it 'works when there is a showdown' do
|
709
710
|
wager_size = 10
|
710
711
|
x_game_def = GameDefinition.new(
|
@@ -781,6 +782,40 @@ describe MatchState do
|
|
781
782
|
end
|
782
783
|
end
|
783
784
|
end
|
785
|
+
describe '#min_wager_by' do
|
786
|
+
it 'return proper player states' do
|
787
|
+
wager_size = 10
|
788
|
+
x_game_def = GameDefinition.new(
|
789
|
+
first_player_positions: [0, 0, 0],
|
790
|
+
chip_stacks: [100, 200, 150],
|
791
|
+
blinds: [0, 10, 5],
|
792
|
+
raise_sizes: [wager_size]*3,
|
793
|
+
number_of_ranks: 3
|
794
|
+
)
|
795
|
+
|
796
|
+
x_min_wagers = [[wager_size], [wager_size, 20, 70, 70, 70], [wager_size, wager_size, wager_size], [wager_size, wager_size, 20, 30, 30]]
|
797
|
+
|
798
|
+
(0..x_game_def.number_of_players-1).each do |position|
|
799
|
+
actions = ''
|
800
|
+
[[''], ['c', 'r30', 'r100', 'c', 'c'], ['c', 'c', 'c'], ['c', 'r110', 'r130', 'r160', 'c']].each_with_index do |actions_per_round, i|
|
801
|
+
actions_per_round.each_with_index do |action, j|
|
802
|
+
actions << action
|
803
|
+
|
804
|
+
hands = x_game_def.number_of_players.times.map { |i| "Ac#{i+2}h" }
|
805
|
+
|
806
|
+
hand_string = hands.inject('') do |string, hand|
|
807
|
+
string << "#{hand}#{MatchState::HAND_SEPARATOR}"
|
808
|
+
end[0..-2]
|
809
|
+
|
810
|
+
match_state = "#{MatchState::LABEL}:#{position}:0:#{actions}:#{hand_string}"
|
811
|
+
|
812
|
+
MatchState.new(match_state).min_wager_by(x_game_def).must_equal x_min_wagers[i][j]
|
813
|
+
end
|
814
|
+
actions << '/' unless actions_per_round.first.empty?
|
815
|
+
end
|
816
|
+
end
|
817
|
+
end
|
818
|
+
end
|
784
819
|
end
|
785
820
|
|
786
821
|
def for_every_card
|
@@ -797,9 +832,6 @@ def for_every_hand
|
|
797
832
|
end
|
798
833
|
end
|
799
834
|
end
|
800
|
-
def test_match_state_initialization_error(incomplete_match_state)
|
801
|
-
->{MatchState.parse incomplete_match_state}.must_raise(MatchState::IncompleteMatchState)
|
802
|
-
end
|
803
835
|
def test_match_state_success(match_state)
|
804
836
|
patient = MatchState.parse match_state
|
805
837
|
patient.to_s.must_equal match_state
|
@@ -828,14 +860,6 @@ def arbitrary_roll_out(rounds)
|
|
828
860
|
community_cards
|
829
861
|
end
|
830
862
|
|
831
|
-
# Construct an arbitrary hole card hand.
|
832
|
-
#
|
833
|
-
# @return [Hand] An arbitrary hole card hand.
|
834
863
|
def arbitrary_hole_card_hand
|
835
|
-
Hand.from_acpc(
|
836
|
-
Rank::DOMAIN[:two][:acpc_character] +
|
837
|
-
Suit::DOMAIN[:spades][:acpc_character] +
|
838
|
-
Rank::DOMAIN[:three][:acpc_character] +
|
839
|
-
Suit::DOMAIN[:hearts][:acpc_character]
|
840
|
-
)
|
864
|
+
Hand.from_acpc('2s3h')
|
841
865
|
end
|
data/spec/seat_spec.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require_relative 'support/spec_helper'
|
2
|
+
|
3
|
+
require 'acpc_poker_types/seat'
|
4
|
+
|
5
|
+
include AcpcPokerTypes
|
6
|
+
|
7
|
+
describe Seat do
|
8
|
+
it 'acts like an integer' do
|
9
|
+
x_int = 2
|
10
|
+
patient = Seat.new x_int, 4
|
11
|
+
|
12
|
+
patient.must_equal x_int
|
13
|
+
(patient + x_int).must_equal x_int * 2
|
14
|
+
end
|
15
|
+
it 'accepts players as well as seats' do
|
16
|
+
Struct.new 'Player', :seat
|
17
|
+
|
18
|
+
x_player = Struct::Player.new(1)
|
19
|
+
Seat.new(x_player, 4).must_equal x_player.seat
|
20
|
+
end
|
21
|
+
it 'accepts seats that are larger than the table size by wrapping' do
|
22
|
+
x_seat = 2
|
23
|
+
|
24
|
+
Seat.new(5, 3).must_equal x_seat
|
25
|
+
end
|
26
|
+
describe '#seats_to' do
|
27
|
+
it 'works for seats on the left' do
|
28
|
+
Seat.new(2, 5).seats_to(4).must_equal 2
|
29
|
+
end
|
30
|
+
it 'works for seats on the right' do
|
31
|
+
Seat.new(2, 5).seats_to(0).must_equal 3
|
32
|
+
end
|
33
|
+
it 'works for its own seat' do
|
34
|
+
Seat.new(1, 2).seats_to(1).must_equal 0
|
35
|
+
end
|
36
|
+
end
|
37
|
+
describe '#seats_from' do
|
38
|
+
it 'works for seats on the left' do
|
39
|
+
Seat.new(2, 5).seats_from(4).must_equal 3
|
40
|
+
end
|
41
|
+
it 'works for seats on the right' do
|
42
|
+
Seat.new(2, 5).seats_from(0).must_equal 2
|
43
|
+
end
|
44
|
+
it 'works for its own seat' do
|
45
|
+
Seat.new(1, 2).seats_from(1).must_equal 0
|
46
|
+
end
|
47
|
+
end
|
48
|
+
describe '#n_seats_away' do
|
49
|
+
it 'works for positive n' do
|
50
|
+
Seat.new(2, 5).n_seats_away(2).must_equal 4
|
51
|
+
end
|
52
|
+
it 'works for negative n' do
|
53
|
+
Seat.new(2, 5).n_seats_away(-2).must_equal 0
|
54
|
+
end
|
55
|
+
it 'works for n larger than the size of the table' do
|
56
|
+
Seat.new(1, 5).n_seats_away(8).must_equal 4
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: acpc_poker_types
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 6.
|
4
|
+
version: 6.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dustin Morrill
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-08-
|
11
|
+
date: 2013-08-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: process_runner
|
@@ -206,6 +206,7 @@ files:
|
|
206
206
|
- spec/suit_spec.rb
|
207
207
|
- spec/hand_results_spec.rb
|
208
208
|
- spec/hand_spec.rb
|
209
|
+
- spec/seat_spec.rb
|
209
210
|
- spec/poker_match_data_spec.rb
|
210
211
|
- spec/coverage/index.html
|
211
212
|
- spec/coverage/assets/0.7.1/application.js
|
@@ -298,6 +299,7 @@ test_files:
|
|
298
299
|
- spec/suit_spec.rb
|
299
300
|
- spec/hand_results_spec.rb
|
300
301
|
- spec/hand_spec.rb
|
302
|
+
- spec/seat_spec.rb
|
301
303
|
- spec/poker_match_data_spec.rb
|
302
304
|
- spec/coverage/index.html
|
303
305
|
- spec/coverage/assets/0.7.1/application.js
|