acpc_poker_types 6.1.2 → 6.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|