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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1bceefd96ab22bcbccd8ed8f9ddee93eb1808462
4
- data.tar.gz: c0811aafbf5f500fffa97e431c51a30240e04a80
3
+ metadata.gz: fbed7f982f75101fa5ea0655986ed7e2d39ea77e
4
+ data.tar.gz: bdc7f86c7351298a819751e1cb9cda56ad9746ff
5
5
  SHA512:
6
- metadata.gz: 4009749b1e934b1c4d8d9248e1fe0f495bb8a52378c1c9d8f04e213cab0c244f0d8b37298e9e612ae24ad7180ff1ae3013406573ef16f25f8111d1ca271091a5
7
- data.tar.gz: bb713825016560c9cbd079b2f2290154d741250e4e02bdb47747a48fa53b1532fb8c5050321f28aefdb6e3692ebd740a94f605e04abe005756dbeabd036fc1b2
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
- acting_player_position = nil
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
- acting_player_position = game_def.first_player_positions[round]
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
- acting_player_position = @players.position_of_first_active_player(
277
- acting_player_position
278
- )
279
+ @player_acting_sequence.last << @next_to_act
280
+ acting_player_position = @player_acting_sequence.last.last
279
281
 
280
- @player_acting_sequence.last << acting_player_position
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
- @players[acting_player_position].append_action!(
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
- yield action, round, acting_player_position, @players if block_given?
292
+ adjust_min_wager!(action, acting_player_position)
298
293
 
299
- acting_player_position = @players.next_player_position(
300
- acting_player_position
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
@@ -58,5 +58,11 @@ class PlayerGroup < DelegateClass(Array)
58
58
  ].min
59
59
  )
60
60
  end
61
+
62
+ def next_to_act(acting_player_position=-1)
63
+ position_of_first_active_player(
64
+ next_player_position(acting_player_position)
65
+ )
66
+ end
61
67
  end
62
68
  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
- # @return [Bool] Reports whether or not +seat+ represents an out of
8
- # bounds seat for the number of seats, +num_seats+.
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
- def initialize(seat, num_seats_at_table)
14
- @seat = seat.to_i
15
- @table_size = num_seats_at_table.to_i
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
- unless in_bounds?
18
- raise "Seat #{@seat} out of bounds for #{num_seats_at_table} players"
19
- end
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
- super @seat
22
- end
23
- def seats_to(other_seat_number)
24
- other_seat = self.class.new(other_seat_number, @table_size)
25
-
26
- if @seat > other_seat
27
- other_seat + @table_size
28
- else
29
- other_seat
30
- end - @seat
31
- end
32
- def seats_from(other_seat_number)
33
- Seat.new(other_seat_number, @table_size).seats_to(@seat)
34
- end
35
- def n_seats_away(n)
36
- Seat.new((n + @seat) % @table_size, @table_size)
37
- end
38
- def in_bounds?
39
- self.class.in_bounds?(@seat, @table_size)
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
@@ -1,3 +1,3 @@
1
1
  module AcpcPokerTypes
2
- VERSION = '6.1.2'
2
+ VERSION = '6.2.0'
3
3
  end
@@ -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 'return proper player states' do
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
- describe '#pot' do
578
- it 'works without side pots' do
579
- wager_size = 10
580
- x_game_def = GameDefinition.new(
581
- first_player_positions: [3, 2, 2, 2],
582
- chip_stacks: [100, 200, 150],
583
- blinds: [0, 10, 5],
584
- raise_sizes: [wager_size]*4,
585
- number_of_ranks: 3
586
- )
587
- x_total_contributions = [2 * 10, 5 * 10, 5 * 10]
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
- (0..x_game_def.number_of_players-1).each do |position|
590
- hands = x_game_def.number_of_players.times.map do |i|
591
- Hand.from_acpc "Ac2#{['s', 'h', 'd', 'c'][i%4]}"
592
- end
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
- hand_string = hands.inject('') do |hand_string, hand|
595
- hand_string << "#{hand}#{MatchState::HAND_SEPARATOR}"
596
- end[0..-2]
596
+ hand_string = hands.inject('') do |hand_string, hand|
597
+ hand_string << "#{hand}#{MatchState::HAND_SEPARATOR}"
598
+ end[0..-2]
597
599
 
598
- match_state =
599
- "#{MatchState::LABEL}:#{position}:0:crcc/ccc/rrfc/crc:#{hand_string}"
600
+ match_state =
601
+ "#{MatchState::LABEL}:#{position}:0:crcc/ccc/rrfc/crc:#{hand_string}"
600
602
 
601
- MatchState.new(match_state).pot(x_game_def).must_equal x_total_contributions.inject(:+)
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 '#every_action' do
607
- it 'yields every action, plus the round number, and the acting player position relative to the dealer' do
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.1.2
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-02 00:00:00.000000000 Z
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