acpc_poker_types 0.0.10 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +7 -4
  3. data/acpc_poker_types.gemspec +4 -2
  4. data/lib/acpc_poker_types.rb +13 -12
  5. data/lib/acpc_poker_types/acpc_dealer_data.rb +9 -0
  6. data/lib/acpc_poker_types/acpc_dealer_data/action_messages.rb +133 -0
  7. data/lib/acpc_poker_types/acpc_dealer_data/hand_data.rb +182 -0
  8. data/lib/acpc_poker_types/acpc_dealer_data/hand_results.rb +79 -0
  9. data/lib/acpc_poker_types/acpc_dealer_data/log_file.rb +5 -0
  10. data/lib/acpc_poker_types/acpc_dealer_data/match_definition.rb +54 -0
  11. data/lib/acpc_poker_types/acpc_dealer_data/poker_match_data.rb +393 -0
  12. data/lib/acpc_poker_types/board_cards.rb +4 -4
  13. data/lib/acpc_poker_types/card.rb +16 -16
  14. data/lib/acpc_poker_types/chip_stack.rb +1 -1
  15. data/lib/acpc_poker_types/game_definition.rb +34 -38
  16. data/lib/acpc_poker_types/hand.rb +5 -5
  17. data/lib/acpc_poker_types/match_state.rb +31 -32
  18. data/lib/acpc_poker_types/pile_of_cards.rb +1 -1
  19. data/lib/acpc_poker_types/player.rb +16 -15
  20. data/lib/acpc_poker_types/poker_action.rb +6 -6
  21. data/lib/acpc_poker_types/rank.rb +2 -2
  22. data/lib/acpc_poker_types/suit.rb +4 -4
  23. data/lib/acpc_poker_types/version.rb +1 -1
  24. data/spec/action_messages_spec.rb +450 -0
  25. data/spec/board_cards_spec.rb +9 -9
  26. data/spec/card_spec.rb +20 -20
  27. data/spec/chip_stack_spec.rb +28 -29
  28. data/spec/game_definition_spec.rb +11 -11
  29. data/spec/hand_data_spec.rb +295 -0
  30. data/spec/hand_results_spec.rb +292 -0
  31. data/spec/hand_spec.rb +11 -11
  32. data/spec/match_definition_spec.rb +95 -0
  33. data/spec/match_state_spec.rb +105 -287
  34. data/spec/pile_of_cards_spec.rb +14 -14
  35. data/spec/player_spec.rb +61 -61
  36. data/spec/poker_action_spec.rb +49 -49
  37. data/spec/poker_match_data_spec.rb +388 -0
  38. data/spec/rank_spec.rb +19 -19
  39. data/spec/suit_spec.rb +19 -19
  40. data/spec/support/spec_helper.rb +28 -6
  41. metadata +55 -10
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b64a898b7daba254af2ce7e70ee95148595a3d19
4
- data.tar.gz: 59be100328bdb941a5308fd477cdb92b080e1106
3
+ metadata.gz: 2cf33f094690cf356dd7bf7e367a3256308da9cf
4
+ data.tar.gz: 6310cec2471926602154f1f1483a95a3a7b3b682
5
5
  SHA512:
6
- metadata.gz: 936b7b4b35c17d22adc2ba8e0b444307435dbb310ed6aed0606a5789a17fef283f199a602aa55e4461336924ac152132c9c007de066a9c7da4b38104f980a416
7
- data.tar.gz: ea4ddaa471833908ef114cb0cc6d3400e0de9789ff80128f7583ea101fcbee0bdb08afe96f2b253e5a97ae11b5d40af34fc6f737c1dfb584867b7b06690460c0
6
+ metadata.gz: 7956c953263284117336feb0546745d697fe525611329472a630a69ba50003686aa350f4b90aa510516e153155dab2a774477fa88e80e67609523d4e8a61b30b
7
+ data.tar.gz: 6549e5f8b25318cae85297116808ce3a2e934c4617685979ad8910849bcab9e1a7e7722025c366a1540d03e5b1cc6d91186f7c2a9a4d195c8440c03f84e72dc3
data/Rakefile CHANGED
@@ -1,9 +1,12 @@
1
1
  #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
2
3
 
3
- require 'bundler/gem_tasks'
4
4
  require 'rake'
5
- require 'rspec/core/rake_task'
5
+ require 'rake/testtask'
6
6
 
7
- RSpec::Core::RakeTask.new(:spec) do |t|
8
- ruby_opts = "-w"
7
+ Rake::TestTask.new do |t|
8
+ t.libs << "lib" << 'spec/support'
9
+ t.test_files = FileList['spec/**/*_spec.rb']
10
+ t.verbose = false
11
+ t.warning = false # pry-rescue has a lot of warnings
9
12
  end
@@ -13,9 +13,11 @@ Gem::Specification.new do |s|
13
13
  s.add_dependency 'dmorrill10-utils'
14
14
  s.add_dependency 'acpc_dealer', '~> 0.0'
15
15
 
16
- s.add_development_dependency 'acpc_dealer_data', '~> 1.0'
17
16
  s.add_development_dependency 'celluloid', '~> 0.13'
18
- s.add_development_dependency 'rspec'
17
+ s.add_development_dependency 'awesome_print'
18
+ s.add_development_dependency 'minitest'
19
+ s.add_development_dependency 'turn'
20
+ s.add_development_dependency 'pry-rescue'
19
21
  s.add_development_dependency 'mocha'
20
22
  s.add_development_dependency 'simplecov'
21
23
 
@@ -1,15 +1,16 @@
1
- require File.expand_path("../acpc_poker_types/version", __FILE__)
1
+ require "acpc_poker_types/version"
2
2
 
3
- require File.expand_path("../acpc_poker_types/board_cards", __FILE__)
4
- require File.expand_path("../acpc_poker_types/card", __FILE__)
5
- require File.expand_path("../acpc_poker_types/chip_stack", __FILE__)
6
- require File.expand_path("../acpc_poker_types/game_definition", __FILE__)
7
- require File.expand_path("../acpc_poker_types/hand", __FILE__)
8
- require File.expand_path("../acpc_poker_types/match_state", __FILE__)
9
- require File.expand_path("../acpc_poker_types/pile_of_cards", __FILE__)
10
- require File.expand_path("../acpc_poker_types/player", __FILE__)
11
- require File.expand_path("../acpc_poker_types/rank", __FILE__)
12
- require File.expand_path("../acpc_poker_types/suit", __FILE__)
3
+ require "acpc_poker_types/board_cards"
4
+ require "acpc_poker_types/card"
5
+ require "acpc_poker_types/chip_stack"
6
+ require "acpc_poker_types/game_definition"
7
+ require "acpc_poker_types/hand"
8
+ require "acpc_poker_types/match_state"
9
+ require "acpc_poker_types/pile_of_cards"
10
+ require "acpc_poker_types/player"
11
+ require "acpc_poker_types/rank"
12
+ require "acpc_poker_types/suit"
13
+ require "acpc_poker_types/acpc_dealer_data"
13
14
 
14
15
  module AcpcPokerTypes
15
- end
16
+ end
@@ -0,0 +1,9 @@
1
+ require 'acpc_poker_types/acpc_dealer_data/action_messages'
2
+ require 'acpc_poker_types/acpc_dealer_data/hand_data'
3
+ require 'acpc_poker_types/acpc_dealer_data/hand_results'
4
+ require 'acpc_poker_types/acpc_dealer_data/poker_match_data'
5
+ require 'acpc_poker_types/acpc_dealer_data/match_definition'
6
+ require 'acpc_poker_types/acpc_dealer_data/log_file'
7
+
8
+ module AcpcPokerTypes::AcpcDealerData
9
+ end
@@ -0,0 +1,133 @@
1
+
2
+ require 'acpc_poker_types/match_state'
3
+ require 'acpc_poker_types/poker_action'
4
+
5
+ require 'acpc_poker_types/acpc_dealer_data/match_definition'
6
+ require 'acpc_poker_types/acpc_dealer_data/log_file'
7
+
8
+ module AcpcPokerTypes::AcpcDealerData
9
+ class ActionMessages
10
+ attr_reader(
11
+ :data, :final_score, :match_def
12
+ )
13
+
14
+ ToMessage = Struct.new(
15
+ # @returns [Integer] Seat of the player receiving the message
16
+ :seat,
17
+ # @returns [AcpcPokerTypes::MatchState] Match state received by the player
18
+ :state
19
+ )
20
+
21
+ FromMessage = Struct.new(
22
+ # @returns [Integer] Seat of the player acting
23
+ :seat,
24
+ # @returns [AcpcPokerTypes::MatchState] Match state on which the action was taken
25
+ :state,
26
+ # @returns [AcpcPokerTypes::PokerAction] Action taken
27
+ :action
28
+ )
29
+
30
+ # @param [String] to_message TO message (message to player)
31
+ def self.parse_to_message(to_message)
32
+ if to_message.strip.match(
33
+ /^TO\s*(\d+)\s*at\s*[\d\.]+\s+(\S+)$/
34
+ )
35
+ ToMessage.new(
36
+ $1.to_i - 1,
37
+ AcpcPokerTypes::MatchState.parse($2)
38
+ )
39
+ else
40
+ nil
41
+ end
42
+ end
43
+
44
+ CONCATONATED_ACTIONS = AcpcPokerTypes::PokerAction::LEGAL_ACPC_CHARACTERS.to_a.join('')
45
+
46
+ # @param [String] from_message FROM message (message from player)
47
+ def self.parse_from_message(from_message)
48
+ if from_message.strip.match(
49
+ /^FROM\s*(\d+)\s*at\s*[\d\.]+\s*(#{AcpcPokerTypes::MatchState::LABEL}\S+):([#{CONCATONATED_ACTIONS}]\s*\d*)$/
50
+ )
51
+ FromMessage.new(
52
+ $1.to_i - 1,
53
+ AcpcPokerTypes::MatchState.parse($2),
54
+ AcpcPokerTypes::PokerAction.new($3)
55
+ )
56
+ else
57
+ nil
58
+ end
59
+ end
60
+
61
+ def self.parse_score(score_string)
62
+ if score_string.strip.match(
63
+ /^SCORE:([\d\-\.|]+):([\w|]+)$/
64
+ )
65
+
66
+ stack_changes = $1.split '|'
67
+ players = $2.split '|'
68
+
69
+ players.each_index.inject({}) do |player_results, j|
70
+ player_results[players[j].to_sym] = stack_changes[j].to_r
71
+ player_results
72
+ end
73
+ else
74
+ nil
75
+ end
76
+ end
77
+
78
+ def self.parse_to_or_from_message(message)
79
+ parsed_message = AcpcPokerTypes::AcpcDealerData::ActionMessages.parse_to_message(message)
80
+ if parsed_message.nil?
81
+ AcpcPokerTypes::AcpcDealerData::ActionMessages.parse_from_message(message)
82
+ else
83
+ parsed_message
84
+ end
85
+ end
86
+
87
+ def self.parse_file(
88
+ acpc_log_file_path,
89
+ player_names,
90
+ game_def_directory,
91
+ num_hands=nil
92
+ )
93
+ AcpcPokerTypes::AcpcDealerData::LogFile.open(acpc_log_file_path, 'r') do |file|
94
+ AcpcPokerTypes::AcpcDealerData::ActionMessages.parse file, player_names, game_def_directory, num_hands
95
+ end
96
+ end
97
+
98
+ alias_new :parse
99
+
100
+ def initialize(
101
+ acpc_log_statements,
102
+ player_names,
103
+ game_def_directory,
104
+ num_hands=nil
105
+ )
106
+ @final_score = nil
107
+ @match_def = nil
108
+ @data = acpc_log_statements.inject([]) do |accumulating_data, log_line|
109
+ if @match_def.nil?
110
+ @match_def = AcpcPokerTypes::AcpcDealerData::MatchDefinition.parse(log_line, player_names, game_def_directory)
111
+ else
112
+ parsed_message = AcpcPokerTypes::AcpcDealerData::ActionMessages.parse_to_or_from_message(log_line)
113
+ if parsed_message
114
+ if (
115
+ accumulating_data.empty? ||
116
+ accumulating_data.last.first[:state].hand_number != parsed_message[:state].hand_number
117
+ )
118
+ break accumulating_data if accumulating_data.length == num_hands
119
+
120
+ accumulating_data << []
121
+ end
122
+
123
+ accumulating_data.last << parsed_message
124
+ else
125
+ @final_score = AcpcPokerTypes::AcpcDealerData::ActionMessages.parse_score(log_line) unless @final_score
126
+ end
127
+ end
128
+
129
+ accumulating_data
130
+ end
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,182 @@
1
+
2
+ require 'dmorrill10-utils/class'
3
+
4
+ require 'acpc_poker_types/acpc_dealer_data/match_definition'
5
+
6
+ # Monkey patch for easy boundary checking
7
+ class Array
8
+ def in_bounds?(i)
9
+ i < length
10
+ end
11
+ end
12
+
13
+ module AcpcPokerTypes::AcpcDealerData
14
+ class HandData
15
+ exceptions :match_definitions_do_not_match, :invalid_data
16
+
17
+ attr_accessor(
18
+ # @returns [Array<Numeric>] Chip distribution at the end of the hand
19
+ :chip_distribution,
20
+ # @returns [MatchDefinition] Game definition and match parameters
21
+ :match_def,
22
+ # @returns [Integer] Zero-index turn number within the hand
23
+ :turn_number,
24
+ # @returns [Turn] Turn data
25
+ :data,
26
+ # @returns [Integer] Seat of the active player
27
+ :seat
28
+ )
29
+
30
+ # State messages are organized by seat
31
+ Turn = Struct.new(
32
+ # @returns [Array<MatchState>] Match states sent during this turn arranged by seat
33
+ :state_messages,
34
+ # @returns [ActionMessages::FromMessage] Action message sent during this turn
35
+ :action_message
36
+ )
37
+
38
+ def initialize(match_def, action_data, result)
39
+ @match_def = match_def
40
+
41
+ set_chip_distribution! result
42
+
43
+ set_data! action_data
44
+
45
+ @turn_number = nil
46
+ @seat = nil
47
+ end
48
+
49
+ def ==(other)
50
+ @match_def == other.match_def &&
51
+ @chip_distribution == other.chip_distribution &&
52
+ @data == other.data
53
+ end
54
+
55
+ def for_every_turn!(seat=0)
56
+ @seat = seat
57
+ @data.each_index do |i|
58
+ @turn_number = i
59
+
60
+ yield @turn_number
61
+ end
62
+
63
+ @turn_number = nil
64
+ self
65
+ end
66
+
67
+ def current_match_state(seat=@seat)
68
+ if @turn_number
69
+ @data[@turn_number].state_messages[seat]
70
+ else
71
+ nil
72
+ end
73
+ end
74
+
75
+ # @return [ActionMessage] Next action in the hand to be taken in the current turn.
76
+ def next_action
77
+ if @turn_number
78
+ @data[@turn_number].action_message
79
+ else
80
+ nil
81
+ end
82
+ end
83
+
84
+ def last_match_state(seat=@seat)
85
+ if @turn_number && @turn_number != 0
86
+ @data[@turn_number-1].state_messages[seat]
87
+ else
88
+ nil
89
+ end
90
+ end
91
+
92
+ def last_action
93
+ if @turn_number && @turn_number != 0
94
+ @data[@turn_number-1].action_message
95
+ else
96
+ nil
97
+ end
98
+ end
99
+
100
+ def final_turn?
101
+ if @turn_number
102
+ @turn_number >= @data.length - 1
103
+ else
104
+ nil
105
+ end
106
+ end
107
+
108
+ protected
109
+
110
+ def set_chip_distribution!(result)
111
+ @chip_distribution = []
112
+ result.each do |player_name, amount|
113
+ begin
114
+ @chip_distribution[@match_def.player_names.index(player_name.to_s)] = amount
115
+ rescue TypeError
116
+ raise PlayerNamesDoNotMatch
117
+ end
118
+ end
119
+ end
120
+
121
+ def set_data!(action_data)
122
+ number_of_state_messages = @match_def.game_def.number_of_players
123
+
124
+ @data = []
125
+ message_number = 0
126
+ while message_number < action_data.length
127
+ state_messages = action_data[message_number..message_number+number_of_state_messages-1]
128
+
129
+ assert_messages_have_no_actions state_messages
130
+
131
+ state_messages = process_state_messages state_messages
132
+
133
+ assert_messages_are_well_defined state_messages
134
+
135
+ message_number += number_of_state_messages
136
+
137
+ action_message = if action_data.in_bounds?(message_number) &&
138
+ action_data[message_number].respond_to?(:action)
139
+
140
+ message_number += 1
141
+ action_data[message_number-1]
142
+ else
143
+ assert_message_is_from_final_turn action_data, message_number, state_messages
144
+
145
+ nil
146
+ end
147
+
148
+ @data << Turn.new(state_messages, action_message)
149
+ end
150
+ end
151
+
152
+ private
153
+
154
+ def process_state_messages(state_messages)
155
+ state_messages.inject([]) do |messages, raw_messages|
156
+ messages[raw_messages.seat] = raw_messages.state
157
+ messages
158
+ end
159
+ end
160
+
161
+ def assert_messages_have_no_actions(state_messages)
162
+ if state_messages.any? { |message| message.respond_to?(:action) }
163
+ raise InvalidData, state_messages.find do |message|
164
+ !message.action.nil?
165
+ end.inspect
166
+ end
167
+ end
168
+
169
+ def assert_messages_are_well_defined(state_messages)
170
+ if state_messages.any? { |message| message.nil? }
171
+ raise InvalidData, state_messages.find { |message| message.nil? }.inspect
172
+ end
173
+ end
174
+
175
+ def assert_message_is_from_final_turn(action_data, message_number, state_messages)
176
+ if action_data.in_bounds?(message_number+1) &&
177
+ state_messages.last.round == action_data[message_number+1].state.round
178
+ raise InvalidData, action_data[message_number].inspect
179
+ end
180
+ end
181
+ end
182
+ end
@@ -0,0 +1,79 @@
1
+
2
+ require 'dmorrill10-utils/class'
3
+
4
+ require 'acpc_poker_types/acpc_dealer_data/match_definition'
5
+ require 'acpc_poker_types/acpc_dealer_data/log_file'
6
+
7
+ module AcpcPokerTypes::AcpcDealerData
8
+ class HandResults
9
+ attr_reader :data, :final_score, :match_def
10
+
11
+ def self.parse_state(state_string)
12
+ if state_string.strip.match(
13
+ /^STATE:\d+:[cfr\d\/]+:[^:]+:([\d\-\.|]+):([\w|]+)$/
14
+ )
15
+
16
+ stack_changes = $1.split '|'
17
+ players = $2.split '|'
18
+
19
+ players.each_index.inject({}) do |player_results, j|
20
+ player_results[players[j].to_sym] = stack_changes[j].to_r
21
+ player_results
22
+ end
23
+ else
24
+ nil
25
+ end
26
+ end
27
+
28
+ def self.parse_score(score_string)
29
+ if score_string.strip.match(
30
+ /^SCORE:([\d\-\.|]+):([\w|]+)$/
31
+ )
32
+
33
+ stack_changes = $1.split '|'
34
+ players = $2.split '|'
35
+
36
+ players.each_index.inject({}) do |player_results, j|
37
+ player_results[players[j].to_sym] = stack_changes[j].to_r
38
+ player_results
39
+ end
40
+ else
41
+ nil
42
+ end
43
+ end
44
+
45
+ def self.parse_file(
46
+ acpc_log_file_path,
47
+ player_names,
48
+ game_def_directory,
49
+ num_hands=nil
50
+ )
51
+ AcpcPokerTypes::AcpcDealerData::LogFile.open(acpc_log_file_path, 'r') do |file|
52
+ AcpcPokerTypes::AcpcDealerData::HandResults.parse file, player_names, game_def_directory, num_hands
53
+ end
54
+ end
55
+
56
+ alias_new :parse
57
+
58
+ def initialize(acpc_log_statements, player_names, game_def_directory, num_hands=nil)
59
+ @final_score = nil
60
+ @match_def = nil
61
+
62
+ @data = acpc_log_statements.inject([]) do |accumulating_data, log_line|
63
+ if @match_def.nil?
64
+ @match_def = AcpcPokerTypes::AcpcDealerData::MatchDefinition.parse(log_line, player_names, game_def_directory)
65
+ else
66
+ parsed_message = AcpcPokerTypes::AcpcDealerData::HandResults.parse_state(log_line)
67
+ if parsed_message
68
+ accumulating_data << parsed_message
69
+ break accumulating_data if accumulating_data.length == num_hands
70
+ else
71
+ @final_score = AcpcPokerTypes::AcpcDealerData::HandResults.parse_score(log_line) unless @final_score
72
+ end
73
+ end
74
+
75
+ accumulating_data
76
+ end
77
+ end
78
+ end
79
+ end