pokerstats 2.0.13 → 2.0.14
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.
- data/VERSION +1 -1
- data/lib/pokerstats/hand_classification.rb +23 -5
- data/lib/pokerstats/hand_constants.rb +8 -2
- data/lib/pokerstats/hand_statistics.rb +25 -4
- data/lib/pokerstats/hand_statistics_api.rb +1 -1
- data/lib/pokerstats/plugins/aggression_statistics.rb +1 -1
- data/lib/pokerstats/plugins/cash_statistics.rb +74 -16
- data/lib/pokerstats/plugins/street_bet_statistics.rb +219 -0
- data/lib/pokerstats/plugins/street_statistics.rb +94 -0
- data/lib/pokerstats/pokerstars_hand_history_parser.rb +76 -13
- data/pokerstats.gemspec +4 -2
- data/spec/hand_statistics_spec.rb +1770 -774
- data/spec/hand_statistics_spec_helper.rb +14 -3
- data/spec/pokerstars_hand_history_parser_spec.rb +77 -10
- data/spec/zpokerstars_hand_history_parser_integration.rb.txt +28 -28
- metadata +4 -2
@@ -0,0 +1,94 @@
|
|
1
|
+
module Pokerstats
|
2
|
+
class StreetStatistics < HandStatistics::Plugin
|
3
|
+
|
4
|
+
def self.report_specification
|
5
|
+
[
|
6
|
+
# [key, sql_type, function]
|
7
|
+
[:saw_flop, 'boolean', :saw_flop],
|
8
|
+
[:saw_turn, 'boolean', :saw_turn],
|
9
|
+
[:saw_river, 'boolean', :saw_river],
|
10
|
+
[:saw_showdown, 'boolean', :saw_showdown],
|
11
|
+
[:won_preflop, 'boolean', :won_preflop],
|
12
|
+
[:won_flop, 'boolean', :won_flop],
|
13
|
+
[:won_turn, 'boolean', :won_turn],
|
14
|
+
[:won_river, 'boolean', :won_river],
|
15
|
+
[:won_showdown, 'boolean', :won_showdown]
|
16
|
+
]
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize handstatistics
|
20
|
+
super handstatistics
|
21
|
+
@saw = {}
|
22
|
+
@won = {}
|
23
|
+
end
|
24
|
+
|
25
|
+
def saw_flop player
|
26
|
+
@saw[player] && @saw[player][:flop]
|
27
|
+
end
|
28
|
+
|
29
|
+
def saw_turn player
|
30
|
+
@saw[player] && @saw[player][:turn]
|
31
|
+
end
|
32
|
+
|
33
|
+
def saw_river player
|
34
|
+
@saw[player] && @saw[player][:river]
|
35
|
+
end
|
36
|
+
|
37
|
+
def saw_showdown player
|
38
|
+
@saw[player] && @saw[player][:showdown]
|
39
|
+
end
|
40
|
+
|
41
|
+
def won_preflop player
|
42
|
+
@won[player] && @won[player][:preflop]
|
43
|
+
end
|
44
|
+
|
45
|
+
def won_flop player
|
46
|
+
@won[player] && @won[player][:flop]
|
47
|
+
end
|
48
|
+
|
49
|
+
def won_turn player
|
50
|
+
@won[player] && @won[player][:turn]
|
51
|
+
end
|
52
|
+
|
53
|
+
def won_river player
|
54
|
+
@won[player] && @won[player][:river]
|
55
|
+
end
|
56
|
+
|
57
|
+
def won_showdown player
|
58
|
+
@won[player] && @won[player][:showdown]
|
59
|
+
end
|
60
|
+
|
61
|
+
def register_player screen_name, street, player
|
62
|
+
@saw[screen_name] = {}
|
63
|
+
@won[screen_name] = {}
|
64
|
+
end
|
65
|
+
|
66
|
+
def street_transition street
|
67
|
+
end
|
68
|
+
|
69
|
+
def street_transition_for_player street, player
|
70
|
+
end
|
71
|
+
|
72
|
+
def apply_action action, street
|
73
|
+
# saw_* statistics for ftrs
|
74
|
+
screen_name = action[:screen_name]
|
75
|
+
if [:flop, :turn, :river, :showdown].include? street
|
76
|
+
@saw[screen_name][street] = true
|
77
|
+
end
|
78
|
+
# won_* statistics for pftrs
|
79
|
+
if [:preflop, :flop, :turn, :river, :showdown].include? street
|
80
|
+
if action[:result] == :win
|
81
|
+
@won[screen_name][street] = true
|
82
|
+
if street == :showdown
|
83
|
+
@won[screen_name][@hand_statistics.last_street] = true
|
84
|
+
end
|
85
|
+
elsif @won[screen_name][street].nil?
|
86
|
+
@won[screen_name][street] = false
|
87
|
+
if street == :showdown
|
88
|
+
@won[screen_name][@hand_statistics.last_street] = false
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -1,9 +1,57 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/hand_constants')
|
2
2
|
require File.expand_path(File.dirname(__FILE__) + '/hand_statistics')
|
3
|
+
require 'tzinfo'
|
3
4
|
|
4
5
|
module Pokerstats
|
5
6
|
CASH = "[0-9$,.]+"
|
7
|
+
|
8
|
+
class PokerstarsTimeStringConverter
|
9
|
+
attr_accessor :timestring
|
10
|
+
|
11
|
+
def initialize(timestring)
|
12
|
+
@timestring = timestring
|
13
|
+
parse_timestring
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
def as_utc_datetime
|
18
|
+
time_converter.local_to_utc(DateTime.parse(@timestring))
|
19
|
+
end
|
6
20
|
|
21
|
+
private
|
22
|
+
|
23
|
+
def parse_timestring
|
24
|
+
if @timestring =~ /^(.*)(UTC|PT|MT|CT|ET|AT|BRT|WET|CET|EET|MSK|CCT|JST|AWST|ACST|AEST|NZT)$/
|
25
|
+
@localtime = $1
|
26
|
+
@ps_timezone_string = $2
|
27
|
+
else
|
28
|
+
raise ArgumentError, "time string does not end with a valid Pokerstars time zone suffix"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def time_converter
|
33
|
+
case @ps_timezone_string
|
34
|
+
when "ACST" then TZInfo::Timezone.get('Australia/Adelaide')
|
35
|
+
when "AEST" then TZInfo::Timezone.get('Australia/Melbourne')
|
36
|
+
when "AT" then TZInfo::Timezone.get('Canada/Atlantic')
|
37
|
+
when "AWST" then TZInfo::Timezone.get('Australia/West')
|
38
|
+
when "BRT" then TZInfo::Timezone.get('Brazil/East')
|
39
|
+
when "CCT" then TZInfo::Timezone.get('Indian/Cocos')
|
40
|
+
when "CET" then TZInfo::Timezone.get('Europe/Amsterdam')
|
41
|
+
when "CT" then TZInfo::Timezone.get('US/Central')
|
42
|
+
when "ET" then TZInfo::Timezone.get('US/Eastern')
|
43
|
+
when "EET" then TZInfo::Timezone.get('EET')
|
44
|
+
when "JST" then TZInfo::Timezone.get('Japan')
|
45
|
+
when "MSK" then TZInfo::Timezone.get('Europe/Moscow')
|
46
|
+
when "MT" then TZInfo::Timezone.get('US/Mountain')
|
47
|
+
when "NZT" then TZInfo::Timezone.get('NZ')
|
48
|
+
when "PT" then TZInfo::Timezone.get('US/Pacific')
|
49
|
+
when "UTC" then TZInfo::Timezone.get('UTC')
|
50
|
+
when "WET" then TZInfo::Timezone.get('WET')
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
7
55
|
class HandHistoryParseError < RuntimeError
|
8
56
|
end
|
9
57
|
class PokerstarsHandHistoryParser
|
@@ -36,16 +84,15 @@ module Pokerstats
|
|
36
84
|
|
37
85
|
def ignorable?(line)
|
38
86
|
regular_expressions_for_ignorable_phrases = [
|
39
|
-
/(.*): doesn't show hand/,
|
40
87
|
/(.*) has timed out/,
|
41
88
|
/(.*) has returned/,
|
42
89
|
/(.*) leaves the table/,
|
43
90
|
/(.*) joins the table at seat #[0-9]+/,
|
44
91
|
/(.*) sits out/,
|
45
|
-
/(.*) mucks hand/,
|
46
92
|
/(.*) is sitting out/,
|
47
93
|
/(.*) is (dis)?connected/,
|
48
94
|
/(.*) said,/,
|
95
|
+
/(.*): doesn't show hand/,
|
49
96
|
/(.*) will be allowed to play after the button/,
|
50
97
|
/(.*) was removed from the table for failing to post/,
|
51
98
|
/(.*) re-buys and receives (.*) chips for (.*)/,
|
@@ -61,12 +108,24 @@ module Pokerstats
|
|
61
108
|
|
62
109
|
def parse(line)
|
63
110
|
case line
|
64
|
-
when /PokerStars Game #([0-9]+): Tournament #([0-9]+), (
|
65
|
-
@stats.update_hand :name => "PS#{$1}", :description=> "#{$2}, #{$3}
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
111
|
+
when /PokerStars Game #([0-9]+): Tournament #([0-9]+), (#{CASH})\+(#{CASH}) Hold'em No Limit - Level ([IVXL]+) \((#{CASH})\/(#{CASH})\) - (.*)$/
|
112
|
+
@stats.update_hand :name => "PS#{$1}", :description=> "#{$2}, #{$3}+#{$4} Hold'em No Limit", :tournament=> $2,
|
113
|
+
:sb=> $6.to_d, :bb=> $7.to_d, :ante => "0.0".to_d,
|
114
|
+
:played_at=> PokerstarsTimeStringConverter.new($8).as_utc_datetime,
|
115
|
+
:street => :prelude, :board => "", :max_players => 0, :number_players => 0, :table_name => "",
|
116
|
+
:game_type => "Hold'em", :limit_type => "No Limit", :stakes_type => cash_to_d($3)
|
117
|
+
when /PokerStars Game #([0-9]+): +([^(]*)Hold'em No Limit \((#{CASH})\/(#{CASH})\) - (.*)$/
|
118
|
+
@stats.update_hand :name => "PS#{$1}", :description=> "#{$2}Hold'em No Limit (#{$3}/#{$4})", :tournament=> nil,
|
119
|
+
:sb=> cash_to_d($3), :bb=> cash_to_d($4), :ante => "0.0".to_d,
|
120
|
+
:played_at=> PokerstarsTimeStringConverter.new($5).as_utc_datetime,
|
121
|
+
:street => :prelude, :board => "", :max_players => 0, :number_players => 0, :table_name => "",
|
122
|
+
:game_type => "Hold'em", :limit_type => "No Limit", :stakes_type => cash_to_d($4)
|
123
|
+
when /PokerStars Game #([0-9]+): +([^(]*)Hold'em No Limit \((#{CASH})\/(#{CASH}) USD\) - (.*)$/
|
124
|
+
@stats.update_hand :name => "PS#{$1}", :description=> "#{$2}Hold'em No LImit (#{$3}/#{$4})", :tournament=> nil,
|
125
|
+
:sb=> cash_to_d($3), :bb=> cash_to_d($4), :ante => "0.0".to_d,
|
126
|
+
:played_at=> PokerstarsTimeStringConverter.new($5).as_utc_datetime,
|
127
|
+
:street => :prelude, :board => "", :max_players => 0, :number_players => 0, :table_name => "",
|
128
|
+
:game_type => "Hold'em", :limit_type => "No Limit", :stakes_type => cash_to_d($4)
|
70
129
|
when /PokerStars Game #([0-9]+):/
|
71
130
|
raise HandHistoryParseError, "invalid hand record: #{line}"
|
72
131
|
when /\*\*\* HOLE CARDS \*\*\*/
|
@@ -92,16 +151,18 @@ module Pokerstats
|
|
92
151
|
@stats.update_hand(:total_pot => cash_to_d($1), :rake => cash_to_d($8))
|
93
152
|
when /Total pot (#{CASH}) Main pot (#{CASH}).( Side pot-[0-9]+ (#{CASH}).)* | Rake (#{CASH})/
|
94
153
|
raise HandHistoryParseError, "popo!"
|
95
|
-
when /Seat ([0-9]+): (.+) \(#{CASH} in chips\)( is sitting out)?/
|
96
|
-
@stats.register_player(:seat => $1.to_i, :screen_name => $2)
|
154
|
+
when /Seat ([0-9]+): (.+) \((#{CASH}) in chips\)( is sitting out)?/
|
155
|
+
@stats.register_player(:seat => $1.to_i, :screen_name => $2, :starting_stack => cash_to_d($3))
|
97
156
|
when /(.*): posts ((small)|(big)|(small \& big)) blind(s)? (#{CASH})/
|
98
157
|
@stats.register_action($1, 'posts', :result => :post, :amount => cash_to_d($7))
|
99
158
|
when /(.*): posts the ante (#{CASH})/
|
100
159
|
@stats.register_action($1, 'antes', :result => :post, :amount => cash_to_d($2))
|
101
|
-
|
102
|
-
|
103
|
-
|
160
|
+
@stats.update_hand(:ante => [cash_to_d($2), @stats.hand_information(:ante)].max)
|
161
|
+
# when /Table '([0-9]+) ([0-9]+)' ([0-9]+)-max Seat #([0-9]+) is the button/
|
162
|
+
# @stats.register_button($4.to_i)
|
163
|
+
when /Table '(.*)' ([0-9]+)-max Seat #([0-9]+) is the button/
|
104
164
|
@stats.register_button($3.to_i)
|
165
|
+
@stats.update_hand(:table_name => $1, :max_players => $2.to_i)
|
105
166
|
when /Uncalled bet \((.*)\) returned to (.*)/
|
106
167
|
@stats.register_action($2, 'return', :result => :win, :amount => cash_to_d($1))
|
107
168
|
when /(.+): ((folds)|(checks))/
|
@@ -112,6 +173,8 @@ module Pokerstats
|
|
112
173
|
@stats.register_action($1, 'raises', :result => :pay_to, :amount => cash_to_d($3))
|
113
174
|
when /(.*) collected (.*) from ((side )|(main ))?pot/
|
114
175
|
@stats.register_action($1, "wins", :result => :win, :amount => cash_to_d($2))
|
176
|
+
when /(.*) mucks hand/
|
177
|
+
@stats.register_action($1, 'mucks', :result => :neutral)
|
115
178
|
when /Seat [0-9]+: (.*) (\((small blind)|(big blind)|(button)\) )?showed \[([^\]]+)\] and ((won) \(#{CASH}\)|(lost)) with (.*)/
|
116
179
|
when /Seat [0-9]+: (.*) mucked \[([^\]]+)\]/
|
117
180
|
else
|
data/pokerstats.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{pokerstats}
|
8
|
-
s.version = "2.0.
|
8
|
+
s.version = "2.0.14"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Andrew C. Greenberg"]
|
12
|
-
s.date = %q{2009-11-
|
12
|
+
s.date = %q{2009-11-18}
|
13
13
|
s.default_executable = %q{checkps}
|
14
14
|
s.description = %q{a library for extracting, computing and reporting statistics of poker hands parsed from hand history files}
|
15
15
|
s.email = %q{wizardwerdna@gmail.com}
|
@@ -42,6 +42,8 @@ Gem::Specification.new do |s|
|
|
42
42
|
"lib/pokerstats/plugins/cash_statistics.rb",
|
43
43
|
"lib/pokerstats/plugins/continuation_bet_statistics.rb",
|
44
44
|
"lib/pokerstats/plugins/preflop_raise_statistics.rb",
|
45
|
+
"lib/pokerstats/plugins/street_bet_statistics.rb",
|
46
|
+
"lib/pokerstats/plugins/street_statistics.rb",
|
45
47
|
"lib/pokerstats/poker-edge.rb",
|
46
48
|
"lib/pokerstats/pokerstars_file.rb",
|
47
49
|
"lib/pokerstats/pokerstars_hand_history_parser.rb",
|
@@ -23,838 +23,1834 @@ Spec::Matchers.define :have_all_and_only_keys do |keylist|
|
|
23
23
|
end
|
24
24
|
end
|
25
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
|
-
|
26
|
+
Spec::Matchers.define :have_won_street_statistics_specified_by do |hash_of_hashes|
|
27
|
+
match do |hand_statistics|
|
28
|
+
@errors = []
|
29
|
+
hash_of_hashes.keys.each do |match_player|
|
30
|
+
hash_of_hashes[match_player].keys.each do |match_street|
|
31
|
+
expected_result = hash_of_hashes[match_player][match_street]
|
32
|
+
actual_result = case match_street
|
33
|
+
when :preflop then hand_statistics.won_preflop(match_player)
|
34
|
+
when :flop then hand_statistics.won_flop(match_player)
|
35
|
+
when :turn then hand_statistics.won_turn(match_player)
|
36
|
+
when :river then hand_statistics.won_river(match_player)
|
37
|
+
when :showdown then hand_statistics.won_showdown(match_player)
|
38
|
+
end
|
39
|
+
unless actual_result == expected_result
|
40
|
+
@errors << {:player => match_player, :street => match_street, :expected => expected_result, :actual => actual_result}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
@errors.empty?
|
45
|
+
end
|
46
|
+
failure_message_for_should do |hand_statistics|
|
47
|
+
@errors.collect do |each|
|
48
|
+
"expected won_#{each[:street]}(#{each[:player].inspect}) to be #{each[:expected].inspect}, obtained #{each[:actual].inspect}"
|
49
|
+
end.join("; \n")
|
50
|
+
end
|
51
|
+
failure_message_for_should_not do |hand_statistics|
|
52
|
+
"the actual results conformed to the expected results"
|
53
|
+
end
|
54
|
+
description do
|
55
|
+
"have conforming won_street statistics"
|
53
56
|
end
|
54
|
-
end
|
55
|
-
|
56
|
-
it "should not produce hand records having extra keys" do
|
57
|
-
@stats.update_hand(sample_hand)
|
58
|
-
@stats.update_hand(:street => :river)
|
59
|
-
@stats.hand_record.should have_all_and_only_keys HAND_INFORMATION_KEYS
|
60
|
-
end
|
61
57
|
end
|
62
58
|
|
63
|
-
|
59
|
+
Spec::Matchers.define :have_saw_street_statistics_specified_by do |hash_of_hashes|
|
60
|
+
match do |hand_statistics|
|
61
|
+
@errors = []
|
62
|
+
hash_of_hashes.keys.each do |match_player|
|
63
|
+
hash_of_hashes[match_player].keys.each do |match_street|
|
64
|
+
expected_result = hash_of_hashes[match_player][match_street]
|
65
|
+
actual_result = case match_street
|
66
|
+
when :flop then hand_statistics.saw_flop(match_player)
|
67
|
+
when :turn then hand_statistics.saw_turn(match_player)
|
68
|
+
when :river then hand_statistics.saw_river(match_player)
|
69
|
+
when :showdown then hand_statistics.saw_showdown(match_player)
|
70
|
+
end
|
71
|
+
unless actual_result == expected_result
|
72
|
+
@errors << {:player => match_player, :street => match_street, :expected => expected_result, :actual => actual_result}
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
@errors.empty?
|
77
|
+
end
|
78
|
+
failure_message_for_should do |hand_statistics|
|
79
|
+
@errors.collect do |each|
|
80
|
+
"expected saw_#{each[:street]}(#{each[:player].inspect}) to be #{each[:expected].inspect}, obtained #{each[:actual].inspect}"
|
81
|
+
end.join("; \n")
|
82
|
+
end
|
83
|
+
failure_message_for_should_not do |hand_statistics|
|
84
|
+
"the actual results conformed to the expected results"
|
85
|
+
end
|
86
|
+
description do
|
87
|
+
"have conforming saw_street statistics"
|
88
|
+
end
|
89
|
+
end
|
64
90
|
|
65
|
-
|
66
|
-
|
67
|
-
|
91
|
+
def bet_statistics_proc_symbol(street, bet, prefix = "")
|
92
|
+
"#{prefix}#{street}_#{bet}bet".to_s
|
93
|
+
end
|
68
94
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
lambda {
|
89
|
-
@stats.register_action sample_action[:screen_name], sample_action[:action], sample_action
|
90
|
-
}.should raise_error(/#{PLAYER_RECORDS_UNREGISTERED_PLAYER}/)
|
91
|
-
end
|
95
|
+
Spec::Matchers.define :have_street_bet_statistics_specified_by do |street_hash, prefix|
|
96
|
+
match do |hand_statistics|
|
97
|
+
@errors = []
|
98
|
+
for match_street in street_hash.keys
|
99
|
+
for match_bet in 1..4
|
100
|
+
unless match_street == :preflop && match_bet == 1 # no such thing as a preflop 1-bet
|
101
|
+
for match_player in street_hash[match_street][match_bet].keys
|
102
|
+
expected_result = street_hash[match_street][match_bet][match_player]
|
103
|
+
proc_symbol = bet_statistics_proc_symbol(match_street, match_bet, prefix)
|
104
|
+
actual_result = hand_statistics.send(proc_symbol, match_player)
|
105
|
+
unless actual_result == expected_result
|
106
|
+
@errors << {:symbol => proc_symbol, :player => match_player, :expected => expected_result, :actual => actual_result}
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
@errors.empty?
|
113
|
+
end
|
92
114
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
it "should complain when asked to generate player records without a registered player" do
|
99
|
-
@stats.register_button(3)
|
100
|
-
lambda{@stats.player_records}.should raise_error(PLAYER_RECORDS_NO_PLAYER_REGISTERED)
|
101
|
-
end
|
102
|
-
|
103
|
-
it "should complain when asked to generate player records without a registered button" do
|
104
|
-
@stats.register_player sample_player
|
105
|
-
lambda{@stats.player_records}.should raise_error(PLAYER_RECORDS_NO_BUTTON_REGISTERED)
|
106
|
-
end
|
107
|
-
end
|
115
|
+
failure_message_for_should do |hand_statistics|
|
116
|
+
@errors.collect do |each|
|
117
|
+
"expected #{each[:symbol]}(#{each[:player].inspect}) to be #{each[:expected].inspect}, obtained #{each[:actual].inspect}"
|
118
|
+
end.join("; \n")
|
119
|
+
end
|
108
120
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
end
|
113
|
-
|
114
|
-
it "should initially have street state set to :prelude" do
|
115
|
-
@stats.street.should == :prelude
|
116
|
-
end
|
117
|
-
|
118
|
-
it "should change street state on an explicit call to #street_transition" do
|
119
|
-
@stats.street_transition(:foo)
|
120
|
-
@stats.street.should == :foo
|
121
|
-
end
|
122
|
-
|
123
|
-
it "should not transition when hand_update does not change street state" do
|
124
|
-
@stats.should_not_receive(:street_transition)
|
125
|
-
@stats.update_hand(:street => :prelude)
|
126
|
-
end
|
127
|
-
|
128
|
-
it "should transition when hand_update chances to a new state" do
|
129
|
-
@stats.should_receive(:street_transition).with(:preflop)
|
130
|
-
@stats.update_hand(:street => :preflop)
|
131
|
-
end
|
132
|
-
end
|
121
|
+
failure_message_for_should_not do |hand_statistics|
|
122
|
+
"the actual results conformed to the expected results"
|
123
|
+
end
|
133
124
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
@stats.register_player @seat2 = next_sample_player(:seat => 2, :screen_name => "seat2")
|
138
|
-
@stats.register_player @seat4 = next_sample_player(:seat => 4, :screen_name => "seat4")
|
139
|
-
@stats.register_player @seat6 = next_sample_player(:seat => 6, :screen_name => "seat6")
|
140
|
-
end
|
141
|
-
it "should correctly identify position with the button on a chair" do
|
142
|
-
@stats.register_button(6)
|
143
|
-
@stats.should_not be_cutoff("seat4")
|
144
|
-
@stats.should be_button("seat6")
|
145
|
-
@stats.should be_sbpos("seat2")
|
146
|
-
@stats.should be_bbpos("seat4")
|
147
|
-
end
|
148
|
-
it "should correctly identify position with the button to the left of the first chair" do
|
149
|
-
@stats.register_button(1)
|
150
|
-
@stats.should_not be_cutoff("seat4")
|
151
|
-
@stats.should be_button("seat6")
|
152
|
-
@stats.should be_sbpos("seat2")
|
153
|
-
@stats.should be_bbpos("seat4")
|
154
|
-
end
|
155
|
-
it "should correctly identify position with the button to the right of the last chair" do
|
156
|
-
@stats.register_button(9)
|
157
|
-
@stats.should_not be_cutoff("seat6")
|
158
|
-
@stats.should be_button("seat6")
|
159
|
-
@stats.should be_sbpos("seat2")
|
160
|
-
@stats.should be_bbpos("seat4")
|
161
|
-
end
|
162
|
-
it "should correctly identify position with the button between two middle chairs" do
|
163
|
-
@stats.register_button(5)
|
164
|
-
@stats.should_not be_cutoff("seat2")
|
165
|
-
@stats.should be_button("seat4")
|
166
|
-
@stats.should be_sbpos("seat6")
|
167
|
-
@stats.should be_bbpos("seat2")
|
168
|
-
end
|
125
|
+
description do
|
126
|
+
"have conforming #{prefix}street_bet statistics"
|
127
|
+
end
|
169
128
|
end
|
170
129
|
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
end
|
186
|
-
it "should correctly identify position with the button to the left of the first chair" do
|
187
|
-
@stats.register_button(1)
|
188
|
-
@stats.should be_cutoff("seat6")
|
189
|
-
@stats.should be_button("seat8")
|
190
|
-
@stats.should be_sbpos("seat2")
|
191
|
-
@stats.should be_bbpos("seat4")
|
192
|
-
end
|
193
|
-
it "should correctly identify position with the button to the right of the last chair" do
|
194
|
-
@stats.register_button(9)
|
195
|
-
@stats.should be_cutoff("seat6")
|
196
|
-
@stats.should be_button("seat8")
|
197
|
-
@stats.should be_sbpos("seat2")
|
198
|
-
@stats.should be_bbpos("seat4")
|
199
|
-
end
|
200
|
-
it "should correctly identify position with the button between two middle chairs" do
|
201
|
-
@stats.register_button(5)
|
202
|
-
@stats.should be_cutoff("seat2")
|
203
|
-
@stats.should be_button("seat4")
|
204
|
-
@stats.should be_sbpos("seat6")
|
205
|
-
@stats.should be_bbpos("seat8")
|
206
|
-
end
|
207
|
-
end
|
130
|
+
Spec::Matchers.define :have_last_aggr do |street, screen_name|
|
131
|
+
match do |hand_statistics|
|
132
|
+
@errors = []
|
133
|
+
for player in hand_statistics.players
|
134
|
+
actual = hand_statistics.send("last_aggr_#{street}", player)
|
135
|
+
expected = if screen_name != player
|
136
|
+
nil
|
137
|
+
else
|
138
|
+
true
|
139
|
+
end
|
140
|
+
@errors << {:player => player, :expected => expected, :actual => actual} unless expected == actual
|
141
|
+
end
|
142
|
+
@errors.empty?
|
143
|
+
end
|
208
144
|
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
@hand_statistics.street_transition(:foo)
|
223
|
-
end
|
224
|
-
it "should notify plugins whenever there is a street transition for a player" do
|
225
|
-
@plugins.each{|each_plugin| each_plugin.should_receive(:street_transition_for_player).with(:foo, :bar)}
|
226
|
-
@hand_statistics.street_transition_for_player(:foo, :bar)
|
227
|
-
end
|
228
|
-
it "should notify plugins whenever a player is registered" do
|
229
|
-
@plugins.each{|each_plugin| each_plugin.should_receive(:register_player).with("andy", :prelude)}
|
230
|
-
@hand_statistics.register_player({:screen_name => "andy"})
|
231
|
-
end
|
145
|
+
failure_message_for_should do |hand_statistics|
|
146
|
+
@errors.collect do |each|
|
147
|
+
"expected last_aggr_#{street}(#{each[:player].inspect}) to be #{each[:expected].inspect}, obtained #{each[:actual].inspect}"
|
148
|
+
end.join("; \n")
|
149
|
+
end
|
150
|
+
|
151
|
+
failure_message_for_should_not do |hand_statistics|
|
152
|
+
"the actual results conformed to the expected results"
|
153
|
+
end
|
154
|
+
|
155
|
+
description do
|
156
|
+
"have conforming last_aggression_#{street} statistics"
|
157
|
+
end
|
232
158
|
end
|
233
159
|
|
234
|
-
describe HandStatistics
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
@stats.street_transition :preflop
|
240
|
-
end
|
241
|
-
|
242
|
-
it "should post correctly" do
|
243
|
-
post_action = lambda{register_post(sample_player, "5".to_d)}
|
244
|
-
post_action.should change{@stats.posted(sample_player[:screen_name])}.by("5".to_d)
|
245
|
-
post_action.should change{@stats.profit(sample_player[:screen_name])}.by("5".to_d * -1)
|
246
|
-
post_action.should change{@stats.posted_in_bb(sample_player[:screen_name])}.by("2.5".to_d)
|
247
|
-
post_action.should change{@stats.profit_in_bb(sample_player[:screen_name])}.by("2.5".to_d * -1)
|
248
|
-
post_action.should_not change{@stats.paid(sample_player[:screen_name])}
|
249
|
-
post_action.should_not change{@stats.won(sample_player[:screen_name])}
|
250
|
-
end
|
160
|
+
describe HandStatistics do
|
161
|
+
context "when created" do
|
162
|
+
before(:each) do
|
163
|
+
@stats = HandStatistics.new
|
164
|
+
end
|
251
165
|
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
ante_action.should change{@stats.profit(sample_player[:screen_name])}.by("5".to_d * -1)
|
256
|
-
ante_action.should change{@stats.posted_in_bb(sample_player[:screen_name])}.by("2.5".to_d)
|
257
|
-
ante_action.should change{@stats.profit_in_bb(sample_player[:screen_name])}.by("2.5".to_d * -1)
|
258
|
-
ante_action.should_not change{@stats.paid(sample_player[:screen_name])}
|
259
|
-
ante_action.should_not change{@stats.won(sample_player[:screen_name])}
|
260
|
-
end
|
261
|
-
|
262
|
-
it "should pay correctly" do
|
263
|
-
pay_action = lambda{register_bet(sample_player, "5".to_d)}
|
264
|
-
pay_action.should change{@stats.paid(sample_player[:screen_name])}.by("5".to_d)
|
265
|
-
pay_action.should change{@stats.profit(sample_player[:screen_name])}.by("5".to_d * -1)
|
266
|
-
pay_action.should change{@stats.paid_in_bb(sample_player[:screen_name])}.by("2.5".to_d)
|
267
|
-
pay_action.should change{@stats.profit_in_bb(sample_player[:screen_name])}.by("2.5".to_d * -1)
|
268
|
-
pay_action.should_not change{@stats.posted(sample_player[:screen_name])}
|
269
|
-
pay_action.should_not change{@stats.won(sample_player[:screen_name])}
|
270
|
-
end
|
166
|
+
it "should return an empty player list" do
|
167
|
+
@stats.should have(0).players
|
168
|
+
end
|
271
169
|
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
win_action.should change{@stats.won_in_bb(sample_player[:screen_name])}.by("2.5".to_d)
|
277
|
-
win_action.should change{@stats.profit_in_bb(sample_player[:screen_name])}.by("2.5".to_d)
|
278
|
-
win_action.should_not change{@stats.paid(sample_player[:screen_name])}
|
279
|
-
win_action.should_not change{@stats.posted(sample_player[:screen_name])}
|
280
|
-
end
|
170
|
+
it "should properly chain updates of hand record information" do
|
171
|
+
sample_hand.each{|key, value| @stats.update_hand(key => value)}
|
172
|
+
@stats.hand_record.should == sample_hand
|
173
|
+
end
|
281
174
|
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
175
|
+
it "should not complain when asked to generate hand record with all HAND_INFORMATION_KEYS filled out" do
|
176
|
+
@stats.update_hand(sample_hand)
|
177
|
+
lambda{@stats.hand_record}.should_not raise_error(/#{HAND_RECORD_INCOMPLETE_MESSAGE}/)
|
178
|
+
end
|
179
|
+
|
180
|
+
it "should complain when asked to generate hand record if no information is given" do
|
181
|
+
lambda{@stats.hand_record}.should raise_error(/#{HAND_RECORD_INCOMPLETE_MESSAGE}/)
|
182
|
+
end
|
287
183
|
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
184
|
+
HandStatistics::HAND_INFORMATION_KEYS.each do |thing|
|
185
|
+
unless [:ante, :number_players].include?(thing)
|
186
|
+
it "should complain when asked to generate hand record without a #{thing.to_s}" do
|
187
|
+
@stats.update_hand(sample_hand.except(thing))
|
188
|
+
lambda{@stats.hand_record}.should raise_error(/#{HAND_RECORD_INCOMPLETE_MESSAGE}/)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
293
192
|
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
end
|
193
|
+
it "should not produce hand records having extra keys" do
|
194
|
+
@stats.update_hand(sample_hand)
|
195
|
+
@stats.update_hand(:street => :river)
|
196
|
+
@stats.hand_record.should have_all_and_only_keys HAND_INFORMATION_KEYS
|
197
|
+
end
|
198
|
+
end
|
301
199
|
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
200
|
+
context "when managing game activity registration" do
|
201
|
+
|
202
|
+
before(:each) do
|
203
|
+
@stats = HandStatistics.new
|
204
|
+
end
|
205
|
+
|
206
|
+
it "should allow you to register a player" do
|
207
|
+
@stats.register_player sample_player
|
208
|
+
@stats.should have(1).player_records_without_validation
|
209
|
+
@stats.hand_information(:number_players).should == 1
|
210
|
+
@stats.player_records_without_validation.first[:screen_name].should == sample_player[:screen_name]
|
211
|
+
@stats.player_records_without_validation.first[:seat].should == sample_player[:seat]
|
212
|
+
@stats.player_records_without_validation.first[:starting_stack].should == sample_player[:starting_stack]
|
213
|
+
end
|
311
214
|
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
}.should change{@stats.paid(@second_player[:screen_name])}.by(7)
|
317
|
-
end
|
215
|
+
it "should complain when registering a player twice" do
|
216
|
+
@stats.register_player sample_player
|
217
|
+
lambda{@stats.register_player sample_player}.should raise_error(/#{PLAYER_RECORDS_DUPLICATE_PLAYER_NAME}/)
|
218
|
+
end
|
318
219
|
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
register_street :preflop
|
325
|
-
register_raise_to @first_player, "7".to_d
|
326
|
-
}.should change{@stats.paid(@first_player[:screen_name])}.by("6".to_d)
|
327
|
-
end
|
220
|
+
it "should allow you to register a button" do
|
221
|
+
@stats.button.should be_nil
|
222
|
+
@stats.register_button(3)
|
223
|
+
@stats.button.should == 3
|
224
|
+
end
|
328
225
|
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
register_raise_to @second_player, "7".to_d
|
335
|
-
}.should change{@stats.paid(@second_player[:screen_name])}.by("7".to_d)
|
336
|
-
lambda{
|
337
|
-
#TODO FIX THIS TEST
|
338
|
-
@stats.register_action @first_player[:screen_name], "sample_reraise", :result => :pay_to, :amount => "14".to_d
|
339
|
-
}.should change{@stats.paid(@first_player[:screen_name])}.by("11".to_d)
|
340
|
-
end
|
341
|
-
end
|
226
|
+
it "should complain when registering action for an unregistered player" do
|
227
|
+
lambda {
|
228
|
+
@stats.register_action sample_action[:screen_name], sample_action[:action], sample_action
|
229
|
+
}.should raise_error(/#{PLAYER_RECORDS_UNREGISTERED_PLAYER}/)
|
230
|
+
end
|
342
231
|
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
end
|
353
|
-
|
354
|
-
it "should pay_to correctly for regular raise" do
|
355
|
-
register_street :preflop
|
356
|
-
lambda{
|
357
|
-
register_raise_to @second_player, 7
|
358
|
-
}.should change{@stats.paid(@second_player[:screen_name])}.by(7)
|
359
|
-
end
|
360
|
-
|
361
|
-
it "should pay_to correctly for re-raise" do
|
362
|
-
@stats.register_action @second_player[:screen_name], "**************", :result => :neutral
|
363
|
-
register_post(@second_player, 2)
|
364
|
-
register_street :preflop
|
365
|
-
lambda{
|
366
|
-
register_street :preflop
|
367
|
-
register_raise_to @first_player, "7".to_d
|
368
|
-
}.should change{@stats.paid(@first_player[:screen_name])}.by("6".to_d)
|
369
|
-
end
|
232
|
+
it "should allow you to register an action" do
|
233
|
+
@stats.register_player sample_player
|
234
|
+
lambda{@stats.register_action sample_action[:screen_name], sample_action[:action], sample_action}.should_not raise_error
|
235
|
+
end
|
236
|
+
|
237
|
+
it "should complain when asked to generate player records without a registered player" do
|
238
|
+
@stats.register_button(3)
|
239
|
+
lambda{@stats.player_records}.should raise_error(PLAYER_RECORDS_NO_PLAYER_REGISTERED)
|
240
|
+
end
|
370
241
|
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
register_raise_to @second_player, "7".to_d
|
377
|
-
}.should change{@stats.paid(@second_player[:screen_name])}.by("7".to_d)
|
378
|
-
lambda{
|
379
|
-
#TODO FIX THIS TEST
|
380
|
-
@stats.register_action @first_player[:screen_name], "sample_reraise", :result => :pay_to, :amount => "14".to_d
|
381
|
-
}.should change{@stats.paid(@first_player[:screen_name])}.by("11".to_d)
|
382
|
-
end
|
383
|
-
end
|
242
|
+
it "should complain when asked to generate player records without a registered button" do
|
243
|
+
@stats.register_player sample_player
|
244
|
+
lambda{@stats.player_records}.should raise_error(PLAYER_RECORDS_NO_BUTTON_REGISTERED)
|
245
|
+
end
|
246
|
+
end
|
384
247
|
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
248
|
+
context "when managing street state" do
|
249
|
+
before(:each) do
|
250
|
+
@stats = HandStatistics.new
|
251
|
+
end
|
252
|
+
|
253
|
+
it "should initially have street state set to :prelude" do
|
254
|
+
@stats.street.should == :prelude
|
255
|
+
end
|
256
|
+
|
257
|
+
it "should change street state on an explicit call to #street_transition" do
|
258
|
+
@stats.street_transition(:foo)
|
259
|
+
@stats.street.should == :foo
|
260
|
+
end
|
261
|
+
|
262
|
+
it "should not transition when hand_update does not change street state" do
|
263
|
+
@stats.should_not_receive(:street_transition)
|
264
|
+
@stats.update_hand(:street => :prelude)
|
265
|
+
end
|
266
|
+
|
267
|
+
it "should transition when hand_update chances to a new state" do
|
268
|
+
@stats.should_receive(:street_transition).with(:preflop)
|
269
|
+
@stats.update_hand(:street => :preflop)
|
270
|
+
end
|
271
|
+
|
272
|
+
it "should remember the last street" do
|
273
|
+
@stats.last_street.should be_nil
|
274
|
+
@stats.street_transition(:foo)
|
275
|
+
@stats.last_street.should == :prelude
|
276
|
+
@stats.street_transition(:bar)
|
277
|
+
@stats.last_street.should == :foo
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
context "when managing plugins" do
|
282
|
+
before(:each) do
|
283
|
+
@hand_statistics = HandStatistics.new
|
284
|
+
@plugins = @hand_statistics.plugins
|
285
|
+
end
|
286
|
+
it "should install specific plugins upon initialization" do
|
287
|
+
HandStatistics.new.plugins.map{|each| each.class}.should include(CashStatistics)
|
288
|
+
end
|
289
|
+
it "should install all the plugins identified upon initialization" do
|
290
|
+
HandStatistics.new.plugins.map{|each| each.class}.should include(*HandStatistics.plugin_factory)
|
291
|
+
end
|
292
|
+
it "should notify plugins whenever there is a street transition" do
|
293
|
+
@plugins.each{|each_plugin| each_plugin.should_receive(:street_transition).with(:foo)}
|
294
|
+
@hand_statistics.street_transition(:foo)
|
295
|
+
end
|
296
|
+
it "should notify plugins whenever there is a street transition for a player" do
|
297
|
+
@plugins.each{|each_plugin| each_plugin.should_receive(:street_transition_for_player).with(:foo, :bar)}
|
298
|
+
@hand_statistics.street_transition_for_player(:foo, :bar)
|
299
|
+
end
|
300
|
+
it "should notify plugins whenever a player is registered" do
|
301
|
+
@plugins.each{|each_plugin| each_plugin.should_receive(:register_player).with("andy", :prelude, {:screen_name => "andy"})}
|
302
|
+
@hand_statistics.register_player({:screen_name => "andy"})
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
context "when registering standard actions" do
|
307
|
+
before(:each) do
|
308
|
+
@stats = HandStatistics.new
|
309
|
+
@stats.update_hand sample_hand
|
310
|
+
@stats.register_player sample_player
|
311
|
+
@stats.street_transition :preflop
|
312
|
+
end
|
313
|
+
|
314
|
+
it "should post correctly" do
|
315
|
+
post_action = lambda{register_post(sample_player, "5".to_d)}
|
316
|
+
post_action.should change{@stats.posted(sample_player[:screen_name])}.by("5".to_d)
|
317
|
+
post_action.should change{@stats.profit(sample_player[:screen_name])}.by("5".to_d * -1)
|
318
|
+
post_action.should change{@stats.posted_in_bb(sample_player[:screen_name])}.by("1.25".to_d)
|
319
|
+
post_action.should change{@stats.profit_in_bb(sample_player[:screen_name])}.by("1.25".to_d * -1)
|
320
|
+
post_action.should_not change{@stats.paid(sample_player[:screen_name])}
|
321
|
+
post_action.should_not change{@stats.won(sample_player[:screen_name])}
|
322
|
+
end
|
323
|
+
|
324
|
+
it "should ante correctly" do
|
325
|
+
ante_action = lambda{register_ante(sample_player, "5".to_d)}
|
326
|
+
ante_action.should change{@stats.posted(sample_player[:screen_name])}.by("5".to_d)
|
327
|
+
ante_action.should change{@stats.profit(sample_player[:screen_name])}.by("5".to_d * -1)
|
328
|
+
ante_action.should change{@stats.posted_in_bb(sample_player[:screen_name])}.by("1.25".to_d)
|
329
|
+
ante_action.should change{@stats.profit_in_bb(sample_player[:screen_name])}.by("1.25".to_d * -1)
|
330
|
+
ante_action.should_not change{@stats.paid(sample_player[:screen_name])}
|
331
|
+
ante_action.should_not change{@stats.won(sample_player[:screen_name])}
|
332
|
+
end
|
333
|
+
|
334
|
+
it "should pay correctly" do
|
335
|
+
pay_action = lambda{register_bet(sample_player, "5".to_d)}
|
336
|
+
pay_action.should change{@stats.paid(sample_player[:screen_name])}.by("5".to_d)
|
337
|
+
pay_action.should change{@stats.profit(sample_player[:screen_name])}.by("5".to_d * -1)
|
338
|
+
pay_action.should change{@stats.paid_in_bb(sample_player[:screen_name])}.by("1.25".to_d)
|
339
|
+
pay_action.should change{@stats.profit_in_bb(sample_player[:screen_name])}.by("1.25".to_d * -1)
|
340
|
+
pay_action.should_not change{@stats.posted(sample_player[:screen_name])}
|
341
|
+
pay_action.should_not change{@stats.won(sample_player[:screen_name])}
|
342
|
+
end
|
343
|
+
|
344
|
+
it "should win correctly" do
|
345
|
+
win_action = lambda{register_win(sample_player, "5".to_d)}
|
346
|
+
win_action.should change{@stats.won(sample_player[:screen_name])}.by("5".to_d)
|
347
|
+
win_action.should change{@stats.profit(sample_player[:screen_name])}.by("5".to_d)
|
348
|
+
win_action.should change{@stats.won_in_bb(sample_player[:screen_name])}.by("1.25".to_d)
|
349
|
+
win_action.should change{@stats.profit_in_bb(sample_player[:screen_name])}.by("1.25".to_d)
|
350
|
+
win_action.should_not change{@stats.paid(sample_player[:screen_name])}
|
351
|
+
win_action.should_not change{@stats.posted(sample_player[:screen_name])}
|
352
|
+
end
|
353
|
+
|
354
|
+
it "should check correctly" do
|
355
|
+
lambda {
|
356
|
+
register_check(sample_player)
|
357
|
+
}.should_not change{@stats}
|
358
|
+
end
|
359
|
+
|
360
|
+
it "should fold correctly" do
|
361
|
+
lambda {
|
362
|
+
register_fold(sample_player)
|
363
|
+
}.should_not change{@stats}
|
364
|
+
end
|
365
|
+
|
366
|
+
it "should show cards correctly" do
|
367
|
+
register_cards(sample_player, "AH KH")
|
368
|
+
@stats.cards(sample_player[:screen_name]).should == "AH KH"
|
369
|
+
@stats.card_category_index(sample_player[:screen_name]).should == Pokerstats::class_index_from_hand_string("AH KH")
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
context "when registering pay_to actions" do
|
374
|
+
before(:each) do
|
375
|
+
@stats = HandStatistics.new
|
376
|
+
@stats.update_hand sample_hand
|
377
|
+
@stats.register_player @first_player = next_sample_player
|
378
|
+
@stats.register_player @second_player = next_sample_player
|
379
|
+
@stats.register_button @first_player[:seat]
|
380
|
+
register_post @first_player, 1
|
381
|
+
end
|
382
|
+
|
383
|
+
it "should pay_to correctly for regular raise" do
|
384
|
+
register_street :preflop
|
385
|
+
lambda{
|
386
|
+
register_raise_to @second_player, 7
|
387
|
+
}.should change{@stats.paid(@second_player[:screen_name])}.by(7)
|
388
|
+
end
|
389
|
+
|
390
|
+
it "should pay_to correctly for re-raise" do
|
391
|
+
@stats.register_action @second_player[:screen_name], "**************", :result => :neutral
|
392
|
+
register_post(@second_player, 2)
|
393
|
+
register_street :preflop
|
394
|
+
lambda{
|
395
|
+
register_street :preflop
|
396
|
+
register_raise_to @first_player, "7".to_d
|
397
|
+
}.should change{@stats.paid(@first_player[:screen_name])}.by("6".to_d)
|
398
|
+
end
|
399
|
+
|
400
|
+
it "should pay_to correctly for re-raise after new phase" do
|
401
|
+
register_post @second_player, "2".to_d
|
402
|
+
register_street :flop
|
403
|
+
register_bet @first_player, "3".to_d
|
404
|
+
lambda{
|
405
|
+
register_raise_to @second_player, "7".to_d
|
406
|
+
}.should change{@stats.paid(@second_player[:screen_name])}.by("7".to_d)
|
407
|
+
lambda{
|
408
|
+
#TODO FIX THIS TEST
|
409
|
+
@stats.register_action @first_player[:screen_name], "sample_reraise", :result => :pay_to, :amount => "14".to_d
|
410
|
+
}.should change{@stats.paid(@first_player[:screen_name])}.by("11".to_d)
|
411
|
+
end
|
412
|
+
end
|
413
|
+
|
414
|
+
context "when registering pay_to actions after antes" do
|
415
|
+
before(:each) do
|
416
|
+
@stats = HandStatistics.new
|
417
|
+
@stats.update_hand sample_hand
|
418
|
+
@stats.register_player @first_player = next_sample_player
|
419
|
+
@stats.register_player @second_player = next_sample_player
|
420
|
+
register_post @first_player, 1
|
421
|
+
register_ante @first_player, 1
|
422
|
+
register_ante @second_player, 1
|
423
|
+
end
|
424
|
+
|
425
|
+
it "should pay_to correctly for regular raise" do
|
426
|
+
register_street :preflop
|
427
|
+
lambda{
|
428
|
+
register_raise_to @second_player, 7
|
429
|
+
}.should change{@stats.paid(@second_player[:screen_name])}.by(7)
|
430
|
+
end
|
431
|
+
|
432
|
+
it "should pay_to correctly for re-raise" do
|
433
|
+
@stats.register_action @second_player[:screen_name], "**************", :result => :neutral
|
434
|
+
register_post(@second_player, 2)
|
435
|
+
register_street :preflop
|
436
|
+
lambda{
|
437
|
+
register_street :preflop
|
438
|
+
register_raise_to @first_player, "7".to_d
|
439
|
+
}.should change{@stats.paid(@first_player[:screen_name])}.by("6".to_d)
|
440
|
+
end
|
441
|
+
|
442
|
+
it "should pay_to correctly for re-raise after new phase" do
|
443
|
+
register_post @second_player, "2".to_d
|
444
|
+
register_street :flop
|
445
|
+
register_bet @first_player, "3".to_d
|
446
|
+
lambda{
|
447
|
+
register_raise_to @second_player, "7".to_d
|
448
|
+
}.should change{@stats.paid(@second_player[:screen_name])}.by("7".to_d)
|
449
|
+
lambda{
|
450
|
+
#TODO FIX THIS TEST
|
451
|
+
@stats.register_action @first_player[:screen_name], "sample_reraise", :result => :pay_to, :amount => "14".to_d
|
452
|
+
}.should change{@stats.paid(@first_player[:screen_name])}.by("11".to_d)
|
453
|
+
end
|
454
|
+
end
|
455
|
+
|
456
|
+
context "when evaluating position" do
|
457
|
+
context "with three players" do
|
458
|
+
before(:each) do
|
459
|
+
@stats = HandStatistics.new
|
460
|
+
@stats.register_player @seat2 = next_sample_player(:seat => 2, :screen_name => "seat2")
|
461
|
+
@stats.register_player @seat4 = next_sample_player(:seat => 4, :screen_name => "seat4")
|
462
|
+
@stats.register_player @seat6 = next_sample_player(:seat => 6, :screen_name => "seat6")
|
463
|
+
end
|
464
|
+
it "should correctly identify position with the button on a chair" do
|
465
|
+
@stats.register_button(6)
|
466
|
+
@stats.should_not be_cutoff("seat4")
|
467
|
+
@stats.should be_button("seat6")
|
468
|
+
@stats.should be_sbpos("seat2")
|
469
|
+
@stats.should be_bbpos("seat4")
|
470
|
+
@stats.should be_betting_order("seat2", "seat4")
|
471
|
+
@stats.should be_betting_order("seat4", "seat6")
|
472
|
+
end
|
473
|
+
it "should correctly identify position with the button to the left of the first chair" do
|
474
|
+
@stats.register_button(1)
|
475
|
+
@stats.should_not be_cutoff("seat4")
|
476
|
+
@stats.should be_button("seat6")
|
477
|
+
@stats.should be_sbpos("seat2")
|
478
|
+
@stats.should be_bbpos("seat4")
|
479
|
+
end
|
480
|
+
it "should correctly identify position with the button to the right of the last chair" do
|
481
|
+
@stats.register_button(9)
|
482
|
+
@stats.should_not be_cutoff("seat6")
|
483
|
+
@stats.should be_button("seat6")
|
484
|
+
@stats.should be_sbpos("seat2")
|
485
|
+
@stats.should be_bbpos("seat4")
|
486
|
+
end
|
487
|
+
it "should correctly identify position with the button between two middle chairs" do
|
488
|
+
@stats.register_button(5)
|
489
|
+
@stats.should_not be_cutoff("seat2")
|
490
|
+
@stats.should be_button("seat4")
|
491
|
+
@stats.should be_sbpos("seat6")
|
492
|
+
@stats.should be_bbpos("seat2")
|
493
|
+
end
|
494
|
+
end
|
495
|
+
|
496
|
+
context "with four players" do
|
497
|
+
before(:each) do
|
498
|
+
@stats = HandStatistics.new
|
499
|
+
@stats.register_player @seat2 = next_sample_player(:seat => 2, :screen_name => "seat2")
|
500
|
+
@stats.register_player @seat4 = next_sample_player(:seat => 4, :screen_name => "seat4")
|
501
|
+
@stats.register_player @seat6 = next_sample_player(:seat => 6, :screen_name => "seat6")
|
502
|
+
@stats.register_player @seat8 = next_sample_player(:seat => 8, :screen_name => "seat8")
|
503
|
+
end
|
504
|
+
it "should correctly identify position with the button on a chair" do
|
505
|
+
@stats.register_button(6)
|
506
|
+
@stats.should be_cutoff("seat4")
|
507
|
+
@stats.should be_button("seat6")
|
508
|
+
@stats.should be_sbpos("seat8")
|
509
|
+
@stats.should be_bbpos("seat2")
|
510
|
+
@stats.should be_betting_order("seat8", "seat2")
|
511
|
+
@stats.should be_betting_order("seat2", "seat4")
|
512
|
+
@stats.should be_betting_order("seat4", "seat6")
|
513
|
+
end
|
514
|
+
it "should correctly identify position with the button to the left of the first chair" do
|
515
|
+
@stats.register_button(1)
|
516
|
+
@stats.should be_cutoff("seat6")
|
517
|
+
@stats.should be_button("seat8")
|
518
|
+
@stats.should be_sbpos("seat2")
|
519
|
+
@stats.should be_bbpos("seat4")
|
520
|
+
end
|
521
|
+
it "should correctly identify position with the button to the right of the last chair" do
|
522
|
+
@stats.register_button(9)
|
523
|
+
@stats.should be_cutoff("seat6")
|
524
|
+
@stats.should be_button("seat8")
|
525
|
+
@stats.should be_sbpos("seat2")
|
526
|
+
@stats.should be_bbpos("seat4")
|
527
|
+
end
|
528
|
+
it "should correctly identify position with the button between two middle chairs" do
|
529
|
+
@stats.register_button(5)
|
530
|
+
@stats.should be_cutoff("seat2")
|
531
|
+
@stats.should be_button("seat4")
|
532
|
+
@stats.should be_sbpos("seat6")
|
533
|
+
@stats.should be_bbpos("seat8")
|
534
|
+
end
|
535
|
+
end
|
536
|
+
end
|
537
|
+
|
538
|
+
context "when measuring statistics:" do
|
539
|
+
context "starting stack data" do
|
540
|
+
context "without an ante" do
|
541
|
+
before(:each) do
|
542
|
+
@stats = HandStatistics.new
|
543
|
+
@stats.update_hand(sample_hand.merge(:sb => "10".to_d, :bb => "20".to_d, :ante => "0".to_d))
|
544
|
+
@stats.register_player @me = next_sample_player.merge(:screen_name => "me", :starting_stack => "300".to_d)
|
545
|
+
end
|
546
|
+
it "should compute starting stack statistics correctly" do
|
547
|
+
@stats.starting_stack("me").should == "300".to_d
|
548
|
+
@stats.starting_stack_in_bb("me").should == "7.5".to_d
|
549
|
+
@stats.starting_pot.should == "30".to_d
|
550
|
+
@stats.starting_stack_as_M("me").should == "10".to_d
|
551
|
+
@stats.starting_stack_as_M_class("me").should == "yellow"
|
552
|
+
end
|
553
|
+
end
|
554
|
+
context "with an ante" do
|
555
|
+
before(:each) do
|
556
|
+
@stats = HandStatistics.new
|
557
|
+
@stats.update_hand(sample_hand.merge(:sb => "10".to_d, :bb => "20".to_d, :ante => "2".to_d, :number_players => "9".to_d))
|
558
|
+
@stats.register_player @me = next_sample_player.merge(:screen_name => "me", :starting_stack => "300".to_d)
|
559
|
+
end
|
560
|
+
it "should compute starting stack statistics correctly" do
|
561
|
+
@stats.starting_stack("me").should == "300".to_d
|
562
|
+
@stats.starting_stack_in_bb("me").should == "7.5".to_d
|
563
|
+
@stats.starting_pot.should == "50".to_d
|
564
|
+
@stats.starting_stack_as_M("me").should == "6.0".to_d
|
565
|
+
@stats.starting_stack_as_M_class("me").should == "orange"
|
566
|
+
end
|
567
|
+
end
|
568
|
+
end
|
569
|
+
|
570
|
+
context "pfr" do
|
571
|
+
before(:each) do
|
572
|
+
@stats = HandStatistics.new
|
573
|
+
@stats.register_player @first_player = next_sample_player
|
574
|
+
@stats.register_player @second_player = next_sample_player
|
575
|
+
register_post(@first_player, 1)
|
576
|
+
register_post(@second_player, 2)
|
577
|
+
register_street :preflop
|
578
|
+
end
|
394
579
|
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
580
|
+
it "should find a pfr opportunity if first actors limped" do
|
581
|
+
register_call(@first_player, 1)
|
582
|
+
register_check(@second_player)
|
583
|
+
@stats.should be_pfr_opportunity(@first_player[:screen_name])
|
584
|
+
@stats.should_not be_pfr_opportunity_taken(@first_player[:screen_name])
|
585
|
+
@stats.should be_pfr_opportunity(@second_player[:screen_name])
|
586
|
+
@stats.should_not be_pfr_opportunity_taken(@second_player[:screen_name])
|
587
|
+
end
|
403
588
|
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
589
|
+
it "should not find a pfr opportunity if another player raises first" do
|
590
|
+
register_raise_to(@first_player, 5)
|
591
|
+
register_call(@second_player, 3)
|
592
|
+
@stats.should be_pfr_opportunity(@first_player[:screen_name])
|
593
|
+
@stats.should be_pfr_opportunity_taken(@first_player[:screen_name])
|
594
|
+
@stats.should_not be_pfr_opportunity(@second_player[:screen_name])
|
595
|
+
end
|
411
596
|
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
597
|
+
it "should not find a pfr opportunity if player made a raise other than the first raise preflpp" do
|
598
|
+
register_raise_to(@first_player, 5)
|
599
|
+
register_raise_to(@second_player, 10)
|
600
|
+
register_call(@first_player, 5)
|
601
|
+
@stats.should be_pfr_opportunity(@first_player[:screen_name])
|
602
|
+
@stats.should be_pfr_opportunity_taken(@first_player[:screen_name])
|
603
|
+
@stats.should_not be_pfr_opportunity(@second_player[:screen_name])
|
604
|
+
end
|
420
605
|
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
end
|
606
|
+
it "should be unaffected by postflop bets and raises" do
|
607
|
+
register_call(@first_player, 1)
|
608
|
+
register_check(@second_player)
|
609
|
+
register_street :flop
|
610
|
+
register_bet(@first_player, 4)
|
611
|
+
register_bet(@second_player, 10)
|
612
|
+
register_call(@first_player, 6)
|
613
|
+
@stats.should be_pfr_opportunity(@first_player[:screen_name])
|
614
|
+
@stats.should be_pfr_opportunity(@second_player[:screen_name])
|
615
|
+
end
|
616
|
+
end
|
432
617
|
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
618
|
+
context "aggression" do
|
619
|
+
before(:each) do
|
620
|
+
@stats = HandStatistics.new
|
621
|
+
@stats.register_player @first_player = next_sample_player
|
622
|
+
@stats.register_player @second_player = next_sample_player
|
623
|
+
end
|
439
624
|
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
625
|
+
it "should all have zero values when no actions have been taken" do
|
626
|
+
@stats.preflop_passive(@first_player[:screen_name]).should be_zero
|
627
|
+
@stats.postflop_passive(@first_player[:screen_name]).should be_zero
|
628
|
+
@stats.preflop_aggressive(@first_player[:screen_name]).should be_zero
|
629
|
+
@stats.postflop_aggressive(@first_player[:screen_name]).should be_zero
|
630
|
+
end
|
446
631
|
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
632
|
+
it "should treat a call preflop as a passive move" do
|
633
|
+
register_street :preflop
|
634
|
+
lambda{register_call(@first_player, 1)}.should change{@stats.preflop_passive(@first_player[:screen_name])}.by(1)
|
635
|
+
end
|
451
636
|
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
637
|
+
it "should treat a call postflop as a passive move" do
|
638
|
+
register_street :flop
|
639
|
+
lambda{register_call(@first_player, 1)}.should change{@stats.postflop_passive(@first_player[:screen_name])}.by(1)
|
640
|
+
end
|
456
641
|
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
642
|
+
it "should treat a raise preflop as an aggressive move" do
|
643
|
+
register_street :preflop
|
644
|
+
lambda{register_raise_to(@first_player, 7)}.should change{@stats.preflop_aggressive(@first_player[:screen_name])}.by(1)
|
645
|
+
end
|
461
646
|
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
647
|
+
it "should treat a raise postflop as an aggressive move" do
|
648
|
+
register_street :flop
|
649
|
+
lambda{register_raise_to(@first_player, 7)}.should change{@stats.postflop_aggressive(@first_player[:screen_name])}.by(1)
|
650
|
+
end
|
466
651
|
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
652
|
+
it "should treat a bet postflop as an aggressive move" do
|
653
|
+
register_street :preflop
|
654
|
+
lambda{register_bet(@first_player, 5)}.should change{@stats.preflop_aggressive(@first_player[:screen_name])}.by(1)
|
655
|
+
end
|
471
656
|
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
657
|
+
it "should not treat a check as an aggressive or a passive move" do
|
658
|
+
register_street :preflop
|
659
|
+
lambda{register_check(@first_player)}.should_not change{@stats.preflop_aggressive(@first_player[:screen_name])}
|
660
|
+
lambda{register_check(@first_player)}.should_not change{@stats.preflop_passive(@first_player[:screen_name])}
|
661
|
+
lambda{register_check(@first_player)}.should_not change{@stats.postflop_aggressive(@first_player[:screen_name])}
|
662
|
+
lambda{register_check(@first_player)}.should_not change{@stats.postflop_aggressive(@first_player[:screen_name])}
|
663
|
+
end
|
479
664
|
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
end
|
665
|
+
it "should not treat a fold as an aggressive or a passive move" do
|
666
|
+
register_street :preflop
|
667
|
+
lambda{register_fold(@first_player)}.should_not change{@stats.preflop_aggressive(@first_player[:screen_name])}
|
668
|
+
lambda{register_fold(@first_player)}.should_not change{@stats.preflop_passive(@first_player[:screen_name])}
|
669
|
+
lambda{register_fold(@first_player)}.should_not change{@stats.postflop_aggressive(@first_player[:screen_name])}
|
670
|
+
lambda{register_fold(@first_player)}.should_not change{@stats.postflop_aggressive(@first_player[:screen_name])}
|
671
|
+
end
|
672
|
+
end
|
488
673
|
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
674
|
+
context "c-bets" do
|
675
|
+
before(:each) do
|
676
|
+
@stats = HandStatistics.new
|
677
|
+
@stats.register_player @button = next_sample_player(:screen_name => "button")
|
678
|
+
@stats.register_player @sb = next_sample_player(:screen_name => "small blind")
|
679
|
+
@stats.register_player @bb = next_sample_player(:screen_name => "big blind")
|
680
|
+
@stats.register_button @button[:seat]
|
681
|
+
register_street :prelude
|
682
|
+
register_post @sb, 1
|
683
|
+
register_post @bb, 2
|
684
|
+
register_street :preflop
|
685
|
+
end
|
686
|
+
it "should not find preflop opportunity without a preflop raise" do
|
687
|
+
register_call @button, 2
|
688
|
+
register_call @sb, 1
|
689
|
+
register_check @bb
|
690
|
+
register_street :flop
|
691
|
+
register_bet @button, 2
|
692
|
+
@stats.should_not be_cbet_opportunity(@button[:screen_name])
|
693
|
+
@stats.should_not be_cbet_opportunity(@sb[:screen_name])
|
694
|
+
@stats.should_not be_cbet_opportunity(@bb[:screen_name])
|
695
|
+
end
|
696
|
+
it "should not find c-bet opportunity with two preflop raises" do
|
697
|
+
register_raise_to @button, 7
|
698
|
+
register_raise_to @sb, 14
|
699
|
+
register_fold @bb
|
700
|
+
register_street :flop
|
701
|
+
register_bet @button, 2
|
702
|
+
@stats.should_not be_cbet_opportunity(@button[:screen_name])
|
703
|
+
@stats.should_not be_cbet_opportunity(@sb[:screen_name])
|
704
|
+
@stats.should_not be_cbet_opportunity(@bb[:screen_name])
|
705
|
+
end
|
706
|
+
it "should not find c-bet opportunity if player raise is not the preflop raiser" do
|
707
|
+
register_call @button, 2
|
708
|
+
register_raise_to @sb, 7
|
709
|
+
register_fold @bb
|
710
|
+
register_call @button, 5
|
711
|
+
register_street :flop
|
712
|
+
register_bet @button, 2
|
713
|
+
@stats.should_not be_cbet_opportunity(@button[:screen_name])
|
714
|
+
end
|
715
|
+
it "should not find c-bet opportunity if non-raiser acts first" do
|
716
|
+
register_call @button, 2
|
717
|
+
register_raise_to @sb, 7
|
718
|
+
register_fold @bb
|
719
|
+
register_call @button, 5
|
720
|
+
register_street :flop
|
721
|
+
register_bet @button, 2
|
722
|
+
register_call @sb, 2
|
723
|
+
@stats.should_not be_cbet_opportunity(@button[:screen_name])
|
724
|
+
end
|
540
725
|
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
end
|
726
|
+
it "should find c-bet opportunity taken when lone pre-flop raiser makes first-in bet post-flop in position" do
|
727
|
+
register_fold @button
|
728
|
+
register_call @sb, 1
|
729
|
+
register_raise_to @bb, 7
|
730
|
+
register_call @sb, 5
|
731
|
+
register_street :flop
|
732
|
+
register_check @sb
|
733
|
+
register_bet @bb, 7
|
734
|
+
@stats.should be_cbet_opportunity(@bb[:screen_name])
|
735
|
+
@stats.should be_cbet_opportunity_taken(@bb[:screen_name])
|
736
|
+
@stats.should_not be_cbet_opportunity(@button[:screen_name])
|
737
|
+
@stats.should_not be_cbet_opportunity(@sb[:screen_name])
|
738
|
+
end
|
739
|
+
it "should find c-bet opportunity taken when lone pre-flop raiser makes first-in bet post-flop out of position" do
|
740
|
+
register_fold @button
|
741
|
+
register_raise_to @sb, 7
|
742
|
+
register_call @bb, 5
|
743
|
+
register_street :flop
|
744
|
+
register_bet @sb, 7
|
745
|
+
@stats.should be_cbet_opportunity(@sb[:screen_name])
|
746
|
+
@stats.should be_cbet_opportunity_taken(@sb[:screen_name])
|
747
|
+
@stats.should_not be_cbet_opportunity(@button[:screen_name])
|
748
|
+
@stats.should_not be_cbet_opportunity(@bb[:screen_name])
|
749
|
+
end
|
750
|
+
it "should find c-bet opportunity declined when lone pre-flop raiser does not make first-in bet post-flop in position" do
|
751
|
+
register_fold @button
|
752
|
+
register_call @sb, 1
|
753
|
+
register_raise_to @bb, 7
|
754
|
+
register_call @sb, 5
|
755
|
+
register_street :flop
|
756
|
+
register_check @sb
|
757
|
+
register_check @bb
|
758
|
+
@stats.should be_cbet_opportunity(@bb[:screen_name])
|
759
|
+
@stats.should_not be_cbet_opportunity_taken(@bb[:screen_name])
|
760
|
+
@stats.should_not be_cbet_opportunity(@button[:screen_name])
|
761
|
+
@stats.should_not be_cbet_opportunity(@sb[:screen_name])
|
762
|
+
end
|
763
|
+
it "should find c-bet opportunity declined when lone pre-flop raiser does not make first-in bet post-flop out of position" do
|
764
|
+
register_fold @button
|
765
|
+
register_raise_to @sb, 7
|
766
|
+
register_call @bb, 5
|
767
|
+
register_street :flop
|
768
|
+
register_check @sb
|
769
|
+
register_check @bb
|
770
|
+
@stats.should be_cbet_opportunity(@sb[:screen_name])
|
771
|
+
@stats.should_not be_cbet_opportunity_taken(@sb[:screen_name])
|
772
|
+
@stats.should_not be_cbet_opportunity(@button[:screen_name])
|
773
|
+
@stats.should_not be_cbet_opportunity(@bb[:screen_name])
|
774
|
+
end
|
775
|
+
end
|
591
776
|
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
777
|
+
context "blind attacks" do
|
778
|
+
before(:each) do
|
779
|
+
@stats = HandStatistics.new
|
780
|
+
register_street :prelude
|
781
|
+
@stats.register_player @utg = next_sample_player(:screen_name => "utg", :seat => 2)
|
782
|
+
@stats.register_player @cutoff = next_sample_player(:screen_name => "cutoff", :seat => 4)
|
783
|
+
@stats.register_player @button = next_sample_player(:screen_name => "button", :seat => 6)
|
784
|
+
@stats.register_player @sb = next_sample_player(:screen_name => "sb", :seat => 8)
|
785
|
+
@stats.register_player @bb = next_sample_player(:screen_name => "bb", :seat => 10)
|
786
|
+
@stats.register_button(@button[:seat])
|
787
|
+
register_post(@sb, 1)
|
788
|
+
register_post(@bb, 2)
|
789
|
+
register_street :preflop
|
790
|
+
end
|
606
791
|
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
792
|
+
it "should identify cutoff opportunities if everybody folds to him" do
|
793
|
+
register_fold(@utg)
|
794
|
+
register_call(@cutoff, 2)
|
795
|
+
register_call(@button, 2)
|
796
|
+
register_call(@sb, 1)
|
797
|
+
register_check(@bb)
|
798
|
+
@stats.should be_blind_attack_opportunity("cutoff")
|
799
|
+
@stats.should_not be_blind_attack_opportunity_taken("cutoff")
|
800
|
+
@stats.should_not be_blind_attack_opportunity("button")
|
801
|
+
@stats.should_not be_blind_attack_opportunity("utg")
|
802
|
+
@stats.should_not be_blind_attack_opportunity("sb")
|
803
|
+
@stats.should_not be_blind_attack_opportunity("bb")
|
804
|
+
end
|
620
805
|
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
806
|
+
it "should properly identify cutoff and button opportunities if everybody folds to button" do
|
807
|
+
register_fold(@utg)
|
808
|
+
register_fold(@cutoff)
|
809
|
+
register_call(@button, 2)
|
810
|
+
register_call(@sb, 1)
|
811
|
+
register_check(@bb)
|
812
|
+
@stats.should be_blind_attack_opportunity("cutoff")
|
813
|
+
@stats.should_not be_blind_attack_opportunity_taken("cutoff")
|
814
|
+
@stats.should be_blind_attack_opportunity("button")
|
815
|
+
@stats.should_not be_blind_attack_opportunity_taken("button")
|
816
|
+
@stats.should_not be_blind_attack_opportunity("utg")
|
817
|
+
@stats.should_not be_blind_attack_opportunity("sb")
|
818
|
+
@stats.should_not be_blind_attack_opportunity("bb")
|
819
|
+
end
|
635
820
|
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
821
|
+
it "should identify cutoff and button attack opportunities if button raises first-in" do
|
822
|
+
register_fold(@utg)
|
823
|
+
register_fold(@cutoff)
|
824
|
+
register_raise_to(@button, 7)
|
825
|
+
register_call(@sb, 6)
|
826
|
+
register_fold(@bb)
|
827
|
+
register_fold(@utg)
|
828
|
+
register_fold(@cutoff)
|
829
|
+
@stats.should be_blind_attack_opportunity("cutoff")
|
830
|
+
@stats.should_not be_blind_attack_opportunity_taken("cutoff")
|
831
|
+
@stats.should be_blind_attack_opportunity("button")
|
832
|
+
@stats.should be_blind_attack_opportunity_taken("button")
|
833
|
+
@stats.should_not be_blind_attack_opportunity("utg")
|
834
|
+
@stats.should_not be_blind_attack_opportunity("sb")
|
835
|
+
@stats.should_not be_blind_attack_opportunity("bb")
|
836
|
+
end
|
652
837
|
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
838
|
+
it "should identify no attack opportunities if utg raises first in" do
|
839
|
+
register_raise_to(@utg, 7)
|
840
|
+
register_call(@cutoff, 7)
|
841
|
+
register_call(@button, 7)
|
842
|
+
register_call(@sb, 6)
|
843
|
+
register_fold(@bb)
|
844
|
+
@stats.should_not be_blind_attack_opportunity("cutoff")
|
845
|
+
@stats.should_not be_blind_attack_opportunity("button")
|
846
|
+
@stats.should_not be_blind_attack_opportunity("utg")
|
847
|
+
@stats.should_not be_blind_attack_opportunity("sb")
|
848
|
+
@stats.should_not be_blind_attack_opportunity("bb")
|
849
|
+
end
|
665
850
|
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
end
|
851
|
+
it "should identify attack opportunities only for button if cutoff raises first in" do
|
852
|
+
register_raise_to(@utg, 7)
|
853
|
+
register_call(@cutoff, 7)
|
854
|
+
register_call(@button, 7)
|
855
|
+
register_call(@sb, 6)
|
856
|
+
register_fold(@bb)
|
857
|
+
@stats.should_not be_blind_attack_opportunity("cutoff")
|
858
|
+
@stats.should_not be_blind_attack_opportunity("button")
|
859
|
+
@stats.should_not be_blind_attack_opportunity("utg")
|
860
|
+
@stats.should_not be_blind_attack_opportunity("sb")
|
861
|
+
@stats.should_not be_blind_attack_opportunity("bb")
|
862
|
+
end
|
863
|
+
end
|
679
864
|
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
865
|
+
context "blind defense" do
|
866
|
+
before(:each) do
|
867
|
+
@stats = HandStatistics.new
|
868
|
+
register_street :prelude
|
869
|
+
@stats.register_player @utg = next_sample_player(:screen_name => "utg", :seat => 2)
|
870
|
+
@stats.register_player @cutoff = next_sample_player(:screen_name => "cutoff", :seat => 4)
|
871
|
+
@stats.register_player @button = next_sample_player(:screen_name => "button", :seat => 6)
|
872
|
+
@stats.register_player @sb = next_sample_player(:screen_name => "sb", :seat => 8)
|
873
|
+
@stats.register_player @bb = next_sample_player(:screen_name => "bb", :seat => 10)
|
874
|
+
@stats.register_button(@button[:seat])
|
875
|
+
register_post(@sb, 1)
|
876
|
+
register_post(@bb, 2)
|
877
|
+
register_street :preflop
|
878
|
+
end
|
694
879
|
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
880
|
+
it "should not identify a blind attack when nobody raises" do
|
881
|
+
register_fold(@utg)
|
882
|
+
register_call(@cutoff, 2)
|
883
|
+
register_call(@button, 2)
|
884
|
+
register_call(@sb, 1)
|
885
|
+
register_check(@bb)
|
886
|
+
@stats.should_not be_blind_defense_opportunity("sb")
|
887
|
+
@stats.should_not be_blind_defense_opportunity("bb")
|
888
|
+
@stats.should_not be_blind_defense_opportunity("utg")
|
889
|
+
@stats.should_not be_blind_defense_opportunity("cutoff")
|
890
|
+
@stats.should_not be_blind_defense_opportunity("button")
|
891
|
+
end
|
707
892
|
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
893
|
+
it "should not identify a blind attack when a non-attacker raises first" do
|
894
|
+
register_raise_to(@utg, 7)
|
895
|
+
register_fold(@cutoff)
|
896
|
+
register_call(@button, 7)
|
897
|
+
register_call(@sb, 6)
|
898
|
+
register_check(@bb)
|
899
|
+
@stats.should_not be_blind_defense_opportunity("sb")
|
900
|
+
@stats.should_not be_blind_defense_opportunity("bb")
|
901
|
+
@stats.should_not be_blind_defense_opportunity("utg")
|
902
|
+
@stats.should_not be_blind_defense_opportunity("cutoff")
|
903
|
+
@stats.should_not be_blind_defense_opportunity("button")
|
904
|
+
end
|
720
905
|
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
906
|
+
it "should not identify a blind attack when a non-attacker raises, even if attacker re-raises" do
|
907
|
+
register_raise_to(@utg, 7)
|
908
|
+
register_fold(@cutoff)
|
909
|
+
register_raise_to(@button, 15)
|
910
|
+
register_call(@sb, 14)
|
911
|
+
register_call(@bb, 13)
|
912
|
+
register_call(@utg, 8)
|
913
|
+
@stats.should_not be_blind_defense_opportunity("sb")
|
914
|
+
@stats.should_not be_blind_defense_opportunity("bb")
|
915
|
+
@stats.should_not be_blind_defense_opportunity("utg")
|
916
|
+
@stats.should_not be_blind_defense_opportunity("cutoff")
|
917
|
+
@stats.should_not be_blind_defense_opportunity("button")
|
918
|
+
end
|
734
919
|
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
920
|
+
it "should identify a blind attack when button raises first-in, taken when blind calls" do
|
921
|
+
register_fold(@utg)
|
922
|
+
register_fold(@cutoff)
|
923
|
+
register_raise_to(@button, 7)
|
924
|
+
register_call(@sb, 6)
|
925
|
+
register_fold(@bb)
|
926
|
+
register_fold(@utg)
|
927
|
+
register_fold(@cutoff)
|
928
|
+
@stats.should be_blind_defense_opportunity("sb")
|
929
|
+
@stats.should be_blind_defense_opportunity_taken("sb")
|
930
|
+
@stats.should_not be_blind_defense_opportunity("bb")
|
931
|
+
@stats.should_not be_blind_defense_opportunity("utg")
|
932
|
+
@stats.should_not be_blind_defense_opportunity("cutoff")
|
933
|
+
@stats.should_not be_blind_defense_opportunity("button")
|
934
|
+
end
|
750
935
|
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
|
936
|
+
it "should identify a blind attack when cutoff raises first-in and button folds, not taken on fold, and taken on raise" do
|
937
|
+
register_fold(@utg)
|
938
|
+
register_raise_to(@cutoff, 7)
|
939
|
+
register_fold(@button)
|
940
|
+
register_fold(@sb)
|
941
|
+
register_raise_to(@bb,200)
|
942
|
+
register_fold(@utg)
|
943
|
+
register_fold(@cutoff)
|
944
|
+
@stats.should be_blind_defense_opportunity("sb")
|
945
|
+
@stats.should_not be_blind_defense_opportunity_taken("sb")
|
946
|
+
@stats.should be_blind_defense_opportunity("bb")
|
947
|
+
@stats.should be_blind_defense_opportunity_taken("bb")
|
948
|
+
@stats.should_not be_blind_defense_opportunity("utg")
|
949
|
+
@stats.should_not be_blind_defense_opportunity("cutoff")
|
950
|
+
@stats.should_not be_blind_defense_opportunity("button")
|
951
|
+
end
|
767
952
|
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
953
|
+
it "should not identify a blind attack when cutoff raises first-in and button calls" do
|
954
|
+
register_fold(@utg)
|
955
|
+
register_raise_to(@cutoff, 7)
|
956
|
+
register_call(@button, 7)
|
957
|
+
register_call(@sb, 6)
|
958
|
+
register_fold(@bb)
|
959
|
+
register_fold(@utg)
|
960
|
+
@stats.should_not be_blind_defense_opportunity("sb")
|
961
|
+
@stats.should_not be_blind_defense_opportunity("bb")
|
962
|
+
@stats.should_not be_blind_defense_opportunity("utg")
|
963
|
+
@stats.should_not be_blind_defense_opportunity("cutoff")
|
964
|
+
@stats.should_not be_blind_defense_opportunity("button")
|
965
|
+
end
|
781
966
|
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
end
|
967
|
+
it "should not identify a blind attack when cutoff raises first-in and button re-raises" do
|
968
|
+
register_fold(@utg)
|
969
|
+
register_raise_to(@cutoff, 7)
|
970
|
+
register_raise_to(@button, 15)
|
971
|
+
register_call(@sb, 6)
|
972
|
+
register_fold(@bb)
|
973
|
+
register_fold(@utg)
|
974
|
+
@stats.should_not be_blind_defense_opportunity("sb")
|
975
|
+
@stats.should_not be_blind_defense_opportunity("bb")
|
976
|
+
@stats.should_not be_blind_defense_opportunity("utg")
|
977
|
+
@stats.should_not be_blind_defense_opportunity("cutoff")
|
978
|
+
@stats.should_not be_blind_defense_opportunity("button")
|
979
|
+
end
|
980
|
+
end
|
796
981
|
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
982
|
+
context "per street" do
|
983
|
+
before(:each) do
|
984
|
+
@stats = HandStatistics.new
|
985
|
+
register_street :prelude
|
986
|
+
@stats.register_player @utg = next_sample_player(:screen_name => "utg", :seat => 2)
|
987
|
+
@stats.register_player @cutoff = next_sample_player(:screen_name => "cutoff", :seat => 4)
|
988
|
+
@stats.register_player @button = next_sample_player(:screen_name => "button", :seat => 6)
|
989
|
+
@stats.register_player @sb = next_sample_player(:screen_name => "sb", :seat => 8)
|
990
|
+
@stats.register_player @bb = next_sample_player(:screen_name => "bb", :seat => 10)
|
991
|
+
@players = [@utg, @cutoff, @button, @sb, @bb]
|
992
|
+
@player_names = @players.collect{|each| each[:screen_name]}
|
993
|
+
@stats.register_button(@button[:seat])
|
994
|
+
register_post(@sb, 1)
|
995
|
+
register_post(@bb, 2)
|
996
|
+
@players.each{|each| register_ante(each, 0.25)}
|
997
|
+
register_street :preflop
|
998
|
+
@nil_saw_street_results = {:flop => nil, :turn => nil, :river => nil, :showdown => nil}
|
999
|
+
@nil_won_street_results = @nil_saw_street_results.merge(:preflop => nil)
|
1000
|
+
@saw_street_expected_results = {
|
1001
|
+
"utg" => @nil_saw_street_results.clone,
|
1002
|
+
"cutoff" => @nil_saw_street_results.clone,
|
1003
|
+
"button" => @nil_saw_street_results.clone,
|
1004
|
+
"sb" => @nil_saw_street_results.clone,
|
1005
|
+
"bb" => @nil_saw_street_results.clone
|
1006
|
+
}
|
1007
|
+
@won_street_expected_results = {
|
1008
|
+
"utg" => @nil_won_street_results.clone,
|
1009
|
+
"cutoff" => @nil_won_street_results.clone,
|
1010
|
+
"button" => @nil_won_street_results.clone,
|
1011
|
+
"sb" => @nil_won_street_results.clone,
|
1012
|
+
"bb" => @nil_won_street_results.clone
|
1013
|
+
}
|
1014
|
+
end
|
1015
|
+
context "with no action" do
|
1016
|
+
it {@stats.should have_saw_street_statistics_specified_by @saw_street_expected_results}
|
1017
|
+
it {@stats.should have_won_street_statistics_specified_by @won_street_expected_results}
|
1018
|
+
end
|
1019
|
+
context "with preflop action" do
|
1020
|
+
before(:each) do
|
1021
|
+
register_raise_to(@utg, 4)
|
1022
|
+
register_raise_to(@cutoff, 8)
|
1023
|
+
register_call(@button, 8)
|
1024
|
+
register_fold(@sb)
|
1025
|
+
for player in ["utg", "cutoff", "button", "sb", "bb"]
|
1026
|
+
@won_street_expected_results[player].update(:preflop => false)
|
1027
|
+
end
|
1028
|
+
end
|
1029
|
+
context "but no winner" do
|
1030
|
+
before(:each) do
|
1031
|
+
register_fold(@bb)
|
1032
|
+
register_call(@utg,4)
|
1033
|
+
end
|
1034
|
+
it {@stats.should have_saw_street_statistics_specified_by @saw_street_expected_results}
|
1035
|
+
it {@stats.should have_won_street_statistics_specified_by @won_street_expected_results}
|
1036
|
+
end
|
1037
|
+
context "and an uncontested winner" do
|
1038
|
+
before(:each) do
|
1039
|
+
register_raise_to(@bb, 100)
|
1040
|
+
register_fold(@utg)
|
1041
|
+
register_fold(@cutoff)
|
1042
|
+
register_fold(@button)
|
1043
|
+
register_win(@bb, 9.25)
|
1044
|
+
@won_street_expected_results["bb"][:preflop] = true
|
1045
|
+
end
|
1046
|
+
it {@stats.should have_saw_street_statistics_specified_by @saw_street_expected_results}
|
1047
|
+
it {@stats.should have_won_street_statistics_specified_by @won_street_expected_results}
|
1048
|
+
end
|
1049
|
+
context "and a showdown" do
|
1050
|
+
before(:each) do
|
1051
|
+
register_raise_to(@bb, 100)
|
1052
|
+
register_fold(@utg)
|
1053
|
+
register_fold(@cutoff)
|
1054
|
+
register_call(@button, 100)
|
1055
|
+
register_street(:showdown)
|
1056
|
+
register_muck(@button)
|
1057
|
+
register_win(@bb, 9.25)
|
1058
|
+
@won_street_expected_results["bb"][:preflop] = true
|
1059
|
+
@won_street_expected_results["bb"][:showdown] = true
|
1060
|
+
@won_street_expected_results["button"][:showdown] = false
|
1061
|
+
@saw_street_expected_results["bb"][:showdown] = true
|
1062
|
+
@saw_street_expected_results["button"][:showdown] = true
|
1063
|
+
end
|
1064
|
+
it {@stats.should have_saw_street_statistics_specified_by @saw_street_expected_results}
|
1065
|
+
it {@stats.should have_won_street_statistics_specified_by @won_street_expected_results}
|
1066
|
+
end
|
1067
|
+
context ", flop action" do
|
1068
|
+
before(:each) do
|
1069
|
+
register_call(@bb, 6)
|
1070
|
+
register_call(@utg, 4)
|
1071
|
+
register_street(:flop)
|
1072
|
+
register_check(@utg)
|
1073
|
+
register_bet(@cutoff, 10)
|
1074
|
+
register_fold(@button)
|
1075
|
+
["utg", "cutoff", "button", "bb"].each{|each|@saw_street_expected_results[each][:flop] = true}
|
1076
|
+
["utg", "cutoff", "button", "bb"].each{|each|@won_street_expected_results[each][:flop] = false}
|
1077
|
+
end
|
1078
|
+
context "but no winner" do
|
1079
|
+
before(:each) do
|
1080
|
+
register_raise_to(@bb, 20)
|
1081
|
+
register_call(@utg, 14)
|
1082
|
+
register_call(@cutoff, 10)
|
1083
|
+
end
|
1084
|
+
it {@stats.should have_saw_street_statistics_specified_by @saw_street_expected_results}
|
1085
|
+
it {@stats.should have_won_street_statistics_specified_by @won_street_expected_results}
|
1086
|
+
end
|
1087
|
+
context "and an uncontested winner" do
|
1088
|
+
before(:each) do
|
1089
|
+
register_fold(@bb)
|
1090
|
+
register_fold(@utg)
|
1091
|
+
register_win(@cutoff, 20)
|
1092
|
+
["utg", "cutoff", "button", "bb"].each{|each|@won_street_expected_results[each][:flop] = (each=="cutoff")}
|
1093
|
+
end
|
1094
|
+
it {@stats.should have_saw_street_statistics_specified_by @saw_street_expected_results}
|
1095
|
+
it {@stats.should have_won_street_statistics_specified_by @won_street_expected_results}
|
1096
|
+
end
|
1097
|
+
context "and a showdown" do
|
1098
|
+
before(:each) do
|
1099
|
+
register_fold(@bb)
|
1100
|
+
register_call(@utg, 10)
|
1101
|
+
register_street(:showdown)
|
1102
|
+
register_muck(@cutoff)
|
1103
|
+
register_win(@button, 20)
|
1104
|
+
["utg", "cutoff", "button", "bb"].each{|each|@won_street_expected_results[each][:flop] = (each=="button")}
|
1105
|
+
["cutoff", "button"].each{|each|@saw_street_expected_results[each][:showdown] = true}
|
1106
|
+
["cutoff", "button"].each{|each|@won_street_expected_results[each][:showdown] = (each=="button")}
|
1107
|
+
end
|
1108
|
+
it {@stats.should have_saw_street_statistics_specified_by @saw_street_expected_results}
|
1109
|
+
it {@stats.should have_won_street_statistics_specified_by @won_street_expected_results}
|
1110
|
+
end
|
1111
|
+
context ", turn action" do
|
1112
|
+
before(:each) do
|
1113
|
+
register_call(@bb, 10)
|
1114
|
+
register_call(@utg, 10)
|
1115
|
+
register_street(:turn)
|
1116
|
+
register_check(@bb)
|
1117
|
+
register_bet(@utg, 10)
|
1118
|
+
register_fold(@cutoff)
|
1119
|
+
["utg", "cutoff", "bb"].each{|each|@saw_street_expected_results[each][:turn] = true}
|
1120
|
+
["utg", "cutoff", "bb"].each{|each|@won_street_expected_results[each][:turn] = false}
|
1121
|
+
end
|
1122
|
+
context "but no winner" do
|
1123
|
+
before(:each) do
|
1124
|
+
register_call(@bb, 10)
|
1125
|
+
end
|
1126
|
+
it {@stats.should have_saw_street_statistics_specified_by @saw_street_expected_results}
|
1127
|
+
it {@stats.should have_won_street_statistics_specified_by @won_street_expected_results}
|
1128
|
+
end
|
1129
|
+
context "and an uncontested winner" do
|
1130
|
+
before(:each) do
|
1131
|
+
register_fold(@bb)
|
1132
|
+
register_win(@utg, 20)
|
1133
|
+
@won_street_expected_results["utg"][:turn] = true
|
1134
|
+
end
|
1135
|
+
it {@stats.should have_saw_street_statistics_specified_by @saw_street_expected_results}
|
1136
|
+
it {@stats.should have_won_street_statistics_specified_by @won_street_expected_results}
|
1137
|
+
end
|
1138
|
+
context "and a showdown" do
|
1139
|
+
before(:each) do
|
1140
|
+
register_call(@bb, 10)
|
1141
|
+
register_street(:showdown)
|
1142
|
+
register_muck(@utg)
|
1143
|
+
register_win(@bb, 20)
|
1144
|
+
@won_street_expected_results["bb"][:turn] = true
|
1145
|
+
@saw_street_expected_results["bb"][:showdown] = true
|
1146
|
+
@saw_street_expected_results["utg"][:showdown] = true
|
1147
|
+
@won_street_expected_results["bb"][:showdown] = true
|
1148
|
+
@won_street_expected_results["utg"][:showdown] = false
|
1149
|
+
end
|
1150
|
+
it {@stats.should have_saw_street_statistics_specified_by @saw_street_expected_results}
|
1151
|
+
it {@stats.should have_won_street_statistics_specified_by @won_street_expected_results}
|
1152
|
+
end
|
1153
|
+
context ", river action" do
|
1154
|
+
before(:each) do
|
1155
|
+
register_call(@bb, 10)
|
1156
|
+
register_street(:river)
|
1157
|
+
register_check(@bb)
|
1158
|
+
register_bet(@utg, 10)
|
1159
|
+
["utg", "cutoff", "bb"].each{|each|@saw_street_expected_results[each][:river] = true}
|
1160
|
+
["utg", "cutoff", "bb"].each{|each|@won_street_expected_results[each][:river] = false}
|
1161
|
+
end
|
1162
|
+
context "but no winner" do
|
1163
|
+
before(:each) do
|
1164
|
+
register_call(@cutoff, 10)
|
1165
|
+
end
|
1166
|
+
it {@stats.should have_saw_street_statistics_specified_by @saw_street_expected_results}
|
1167
|
+
it {@stats.should have_won_street_statistics_specified_by @won_street_expected_results}
|
1168
|
+
end
|
1169
|
+
context "and an uncontested winner" do
|
1170
|
+
before(:each) do
|
1171
|
+
register_fold(@cutoff)
|
1172
|
+
register_win(@utg, 10)
|
1173
|
+
@won_street_expected_results["utg"][:river] = true
|
1174
|
+
@won_street_expected_results["cutoff"][:river] = false
|
1175
|
+
end
|
1176
|
+
it {@stats.should have_saw_street_statistics_specified_by @saw_street_expected_results}
|
1177
|
+
it {@stats.should have_won_street_statistics_specified_by @won_street_expected_results}
|
1178
|
+
end
|
1179
|
+
context "and a showdown" do
|
1180
|
+
before(:each) do
|
1181
|
+
register_call(@cutoff, 10)
|
1182
|
+
register_street(:showdown)
|
1183
|
+
register_muck(@cutoff)
|
1184
|
+
register_win(@utg, 10)
|
1185
|
+
@won_street_expected_results["utg"][:river] = true
|
1186
|
+
@won_street_expected_results["cutoff"][:river] = false
|
1187
|
+
@saw_street_expected_results["utg"][:showdown] = true
|
1188
|
+
@saw_street_expected_results["cutoff"][:showdown] = true
|
1189
|
+
@won_street_expected_results["utg"][:showdown] = true
|
1190
|
+
@won_street_expected_results["cutoff"][:showdown] = false
|
1191
|
+
end
|
1192
|
+
it {@stats.should have_saw_street_statistics_specified_by @saw_street_expected_results}
|
1193
|
+
it {@stats.should have_won_street_statistics_specified_by @won_street_expected_results}
|
1194
|
+
end
|
1195
|
+
end
|
1196
|
+
end
|
1197
|
+
end
|
1198
|
+
end
|
1199
|
+
end
|
811
1200
|
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
1201
|
+
context "bet and raises by street" do
|
1202
|
+
before(:each) do
|
1203
|
+
@stats = HandStatistics.new
|
1204
|
+
register_street :prelude
|
1205
|
+
@stats.register_player @utg = next_sample_player(:screen_name => "utg", :seat => 2)
|
1206
|
+
@stats.register_player @cutoff = next_sample_player(:screen_name => "cutoff", :seat => 4)
|
1207
|
+
@stats.register_player @button = next_sample_player(:screen_name => "button", :seat => 6)
|
1208
|
+
@stats.register_player @sb = next_sample_player(:screen_name => "sb", :seat => 8)
|
1209
|
+
@stats.register_player @bb = next_sample_player(:screen_name => "bb", :seat => 10)
|
1210
|
+
@players = [@utg, @cutoff, @button, @sb, @bb]
|
1211
|
+
@player_names = @players.collect{|each| each[:screen_name]}
|
1212
|
+
@bet_specification = {}
|
1213
|
+
@call_bet_specification = {}
|
1214
|
+
@fold_to_bet_specification = {}
|
1215
|
+
for street in [:preflop, :flop, :turn, :river]
|
1216
|
+
@bet_specification[street] = []
|
1217
|
+
@call_bet_specification[street] = []
|
1218
|
+
@fold_to_bet_specification[street] = []
|
1219
|
+
for bet in 1..4
|
1220
|
+
@bet_specification[street][bet] = {}
|
1221
|
+
@call_bet_specification[street][bet] = {}
|
1222
|
+
@fold_to_bet_specification[street][bet] = {}
|
1223
|
+
for player in @player_names
|
1224
|
+
@bet_specification[street][bet][player] = nil
|
1225
|
+
@call_bet_specification[street][bet][player] = nil
|
1226
|
+
@fold_to_bet_specification[street][bet][player] = nil
|
1227
|
+
end
|
1228
|
+
end
|
1229
|
+
end
|
1230
|
+
@stats.register_button(@button[:seat])
|
1231
|
+
register_post(@sb, 1)
|
1232
|
+
register_post(@bb, 2)
|
1233
|
+
@players.each{|each| register_ante(each, 0.25)}
|
1234
|
+
register_street :preflop
|
1235
|
+
end
|
1236
|
+
context "with no raising" do
|
1237
|
+
before(:each) do
|
1238
|
+
[:flop, :turn, :river].each do |street|
|
1239
|
+
register_street street
|
1240
|
+
register_check(@sb)
|
1241
|
+
register_check(@bb)
|
1242
|
+
register_bet(@utg, 5)
|
1243
|
+
register_call(@cutoff, 5)
|
1244
|
+
register_fold(@button)
|
1245
|
+
@bet_specification[street][1]["sb"] = false
|
1246
|
+
@bet_specification[street][1]["bb"] = false
|
1247
|
+
@bet_specification[street][1]["utg"] = true
|
1248
|
+
@call_bet_specification[street][1]["cutoff"] = true
|
1249
|
+
@call_bet_specification[street][1]["button"] = false
|
1250
|
+
@fold_to_bet_specification[street][1]["cutoff"] = false
|
1251
|
+
@fold_to_bet_specification[street][1]["button"] = true
|
1252
|
+
@bet_specification[street][2]["cutoff"] = false
|
1253
|
+
@bet_specification[street][2]["button"] = false
|
1254
|
+
@stats.should have_last_aggr(street, "utg")
|
1255
|
+
end
|
1256
|
+
end
|
1257
|
+
it {@stats.should have_street_bet_statistics_specified_by @bet_specification, ""}
|
1258
|
+
it {@stats.should have_street_bet_statistics_specified_by @call_bet_specification, "call_"}
|
1259
|
+
it {@stats.should have_street_bet_statistics_specified_by @fold_to_bet_specification, "fold_to_"}
|
1260
|
+
end
|
1261
|
+
|
1262
|
+
context "after 1 raise" do
|
1263
|
+
context "preflop" do
|
1264
|
+
before(:each) do
|
1265
|
+
register_call(@utg, 2)
|
1266
|
+
register_fold(@cutoff)
|
1267
|
+
register_raise_to(@button, 5)
|
1268
|
+
register_call(@sb, 4)
|
1269
|
+
register_fold(@bb)
|
1270
|
+
@call_bet_specification[:preflop][1]["utg"] = true
|
1271
|
+
@fold_to_bet_specification[:preflop][1]["utg"] = false
|
1272
|
+
@bet_specification[:preflop][2]["utg"] = false
|
1273
|
+
@call_bet_specification[:preflop][1]["cutoff"] = false
|
1274
|
+
@fold_to_bet_specification[:preflop][1]["cutoff"] = true
|
1275
|
+
@bet_specification[:preflop][2]["cutoff"] = false
|
1276
|
+
@call_bet_specification[:preflop][1]["button"] = false
|
1277
|
+
@fold_to_bet_specification[:preflop][1]["button"] = false
|
1278
|
+
@bet_specification[:preflop][2]["button"] = true
|
1279
|
+
@call_bet_specification[:preflop][2]["sb"] = true
|
1280
|
+
@fold_to_bet_specification[:preflop][2]["sb"] = false
|
1281
|
+
@bet_specification[:preflop][3]["sb"] = false
|
1282
|
+
@call_bet_specification[:preflop][2]["bb"] = false
|
1283
|
+
@fold_to_bet_specification[:preflop][2]["bb"] = true
|
1284
|
+
@bet_specification[:preflop][3]["bb"] = false
|
1285
|
+
@stats.should have_last_aggr(:preflop, "button")
|
1286
|
+
end
|
1287
|
+
it {@stats.should have_street_bet_statistics_specified_by @bet_specification, ""}
|
1288
|
+
it {@stats.should have_street_bet_statistics_specified_by @call_bet_specification, "call_"}
|
1289
|
+
it {@stats.should have_street_bet_statistics_specified_by @fold_to_bet_specification, "fold_to_"}
|
1290
|
+
end
|
1291
|
+
context "other streets" do
|
1292
|
+
before(:each) do
|
1293
|
+
[:flop, :turn, :river].each do |street|
|
1294
|
+
register_street street
|
1295
|
+
register_bet(@utg, 5)
|
1296
|
+
register_raise_to(@cutoff, 10)
|
1297
|
+
register_fold(@button)
|
1298
|
+
register_call(@sb, 10)
|
1299
|
+
register_raise_to(@bb, 20)
|
1300
|
+
@bet_specification[street][1]["utg"] = true
|
1301
|
+
@call_bet_specification[street][1]["cutoff"] = false
|
1302
|
+
@fold_to_bet_specification[street][1]["cutoff"] = false
|
1303
|
+
@bet_specification[street][2]["cutoff"] = true
|
1304
|
+
@call_bet_specification[street][2]["button"] = false
|
1305
|
+
@fold_to_bet_specification[street][2]["button"] = true
|
1306
|
+
@bet_specification[street][3]["button"] = false
|
1307
|
+
@call_bet_specification[street][2]["sb"] = true
|
1308
|
+
@fold_to_bet_specification[street][2]["sb"] = false
|
1309
|
+
@bet_specification[street][3]["sb"] = false
|
1310
|
+
@call_bet_specification[street][2]["bb"] = false
|
1311
|
+
@fold_to_bet_specification[street][2]["bb"] = false
|
1312
|
+
@bet_specification[street][3]["bb"] = true
|
1313
|
+
@stats.should have_last_aggr(street, "bb")
|
1314
|
+
end
|
1315
|
+
end
|
1316
|
+
it {@stats.should have_street_bet_statistics_specified_by @bet_specification, ""}
|
1317
|
+
it {@stats.should have_street_bet_statistics_specified_by @call_bet_specification, "call_"}
|
1318
|
+
it {@stats.should have_street_bet_statistics_specified_by @fold_to_bet_specification, "fold_to_"}
|
1319
|
+
end
|
1320
|
+
end
|
1321
|
+
|
1322
|
+
context "after 2 raises" do
|
1323
|
+
context "preflop" do
|
1324
|
+
before(:each) do
|
1325
|
+
register_raise_to(@utg, 10)
|
1326
|
+
register_raise_to(@cutoff, 20)
|
1327
|
+
register_fold(@button)
|
1328
|
+
register_call(@sb, 19)
|
1329
|
+
register_raise_to(@bb, 50)
|
1330
|
+
@call_bet_specification[:preflop][1]["utg"] = false
|
1331
|
+
@fold_to_bet_specification[:preflop][1]["utg"] = false
|
1332
|
+
@bet_specification[:preflop][2]["utg"] = true
|
1333
|
+
@call_bet_specification[:preflop][2]["cutoff"] = false
|
1334
|
+
@fold_to_bet_specification[:preflop][2]["cutoff"] = false
|
1335
|
+
@bet_specification[:preflop][3]["cutoff"] = true
|
1336
|
+
@call_bet_specification[:preflop][3]["button"] = false
|
1337
|
+
@fold_to_bet_specification[:preflop][3]["button"] = true
|
1338
|
+
@bet_specification[:preflop][4]["button"] = false
|
1339
|
+
@call_bet_specification[:preflop][3]["sb"] = true
|
1340
|
+
@fold_to_bet_specification[:preflop][3]["sb"] = false
|
1341
|
+
@bet_specification[:preflop][4]["sb"] = false
|
1342
|
+
@call_bet_specification[:preflop][3]["bb"] = false
|
1343
|
+
@fold_to_bet_specification[:preflop][3]["bb"] = false
|
1344
|
+
@bet_specification[:preflop][4]["bb"] = true
|
1345
|
+
@stats.should have_last_aggr(:preflop, "bb")
|
1346
|
+
end
|
1347
|
+
it {@stats.should have_street_bet_statistics_specified_by @bet_specification, ""}
|
1348
|
+
it {@stats.should have_street_bet_statistics_specified_by @call_bet_specification, "call_"}
|
1349
|
+
it {@stats.should have_street_bet_statistics_specified_by @fold_to_bet_specification, "fold_to_"}
|
1350
|
+
end
|
1351
|
+
context "other streets" do
|
1352
|
+
before(:each) do
|
1353
|
+
[:flop, :turn, :river].each do |street|
|
1354
|
+
register_street street
|
1355
|
+
register_bet(@sb, 5)
|
1356
|
+
register_raise_to(@bb, 10)
|
1357
|
+
register_raise_to(@utg, 50)
|
1358
|
+
register_fold(@cutoff)
|
1359
|
+
register_call(@button, 50)
|
1360
|
+
register_raise_to(@sb, 250)
|
1361
|
+
@bet_specification[street][1]["sb"] = true
|
1362
|
+
@call_bet_specification[street][1]["bb"] = false
|
1363
|
+
@fold_to_bet_specification[street][1]["bb"] = false
|
1364
|
+
@bet_specification[street][2]["bb"] = true
|
1365
|
+
@call_bet_specification[street][2]["utg"] = false
|
1366
|
+
@fold_to_bet_specification[street][2]["utg"] = false
|
1367
|
+
@bet_specification[street][3]["utg"] = true
|
1368
|
+
@call_bet_specification[street][3]["cutoff"] = false
|
1369
|
+
@fold_to_bet_specification[street][3]["cutoff"] = true
|
1370
|
+
@bet_specification[street][4]["cutoff"] = false
|
1371
|
+
@call_bet_specification[street][3]["button"] = true
|
1372
|
+
@fold_to_bet_specification[street][3]["button"] = false
|
1373
|
+
@bet_specification[street][4]["button"] = false
|
1374
|
+
@call_bet_specification[street][3]["sb"] = false
|
1375
|
+
@fold_to_bet_specification[street][3]["sb"] = false
|
1376
|
+
@bet_specification[street][4]["sb"] = true
|
1377
|
+
@stats.should have_last_aggr(street,"sb")
|
1378
|
+
end
|
1379
|
+
end
|
1380
|
+
it {@stats.should have_street_bet_statistics_specified_by @bet_specification, ""}
|
1381
|
+
it {@stats.should have_street_bet_statistics_specified_by @call_bet_specification, "call_"}
|
1382
|
+
it {@stats.should have_street_bet_statistics_specified_by @fold_to_bet_specification, "fold_to_"}
|
1383
|
+
end
|
1384
|
+
end
|
1385
|
+
|
1386
|
+
context "after 3 raises" do
|
1387
|
+
context "preflop" do
|
1388
|
+
before(:each) do
|
1389
|
+
register_raise_to(@utg, 10)
|
1390
|
+
register_raise_to(@cutoff, 50)
|
1391
|
+
register_raise_to(@button, 150)
|
1392
|
+
register_fold(@sb)
|
1393
|
+
register_call(@bb, 148)
|
1394
|
+
register_raise_to(@utg, 480)
|
1395
|
+
@call_bet_specification[:preflop][1]["utg"] = false
|
1396
|
+
@fold_to_bet_specification[:preflop][1]["utg"] = false
|
1397
|
+
@bet_specification[:preflop][2]["utg"] = true
|
1398
|
+
@call_bet_specification[:preflop][2]["cutoff"] = false
|
1399
|
+
@fold_to_bet_specification[:preflop][2]["cutoff"] = false
|
1400
|
+
@bet_specification[:preflop][3]["cutoff"] = true
|
1401
|
+
@call_bet_specification[:preflop][3]["button"] = false
|
1402
|
+
@fold_to_bet_specification[:preflop][3]["button"] = false
|
1403
|
+
@bet_specification[:preflop][4]["button"] = true
|
1404
|
+
@call_bet_specification[:preflop][4]["sb"] = false
|
1405
|
+
@call_bet_specification[:preflop][4]["bb"] = true
|
1406
|
+
@call_bet_specification[:preflop][4]["utg"] = false
|
1407
|
+
@fold_to_bet_specification[:preflop][4]["sb"] = true
|
1408
|
+
@fold_to_bet_specification[:preflop][4]["bb"] = false
|
1409
|
+
@fold_to_bet_specification[:preflop][4]["utg"] = false
|
1410
|
+
@stats.should have_last_aggr(:preflop, "utg")
|
1411
|
+
end
|
1412
|
+
it {@stats.should have_street_bet_statistics_specified_by @bet_specification, ""}
|
1413
|
+
it {@stats.should have_street_bet_statistics_specified_by @call_bet_specification, "call_"}
|
1414
|
+
it {@stats.should have_street_bet_statistics_specified_by @fold_to_bet_specification, "fold_to_"}
|
1415
|
+
end
|
1416
|
+
context "other streets" do
|
1417
|
+
before(:each) do
|
1418
|
+
[:flop, :turn, :river].each do |street|
|
1419
|
+
register_street street
|
1420
|
+
register_bet(@sb, 5)
|
1421
|
+
register_raise_to(@bb, 10)
|
1422
|
+
register_raise_to(@utg, 50)
|
1423
|
+
register_raise_to(@cutoff, 150)
|
1424
|
+
register_fold(@button)
|
1425
|
+
register_call(@sb, 145)
|
1426
|
+
register_raise_to(@bb, 450)
|
1427
|
+
@bet_specification[street][1]["sb"] = true
|
1428
|
+
@call_bet_specification[street][1]["bb"] = false
|
1429
|
+
@fold_to_bet_specification[street][1]["bb"] = false
|
1430
|
+
@bet_specification[street][2]["bb"] = true
|
1431
|
+
@call_bet_specification[street][2]["utg"] = false
|
1432
|
+
@fold_to_bet_specification[street][2]["utg"] = false
|
1433
|
+
@bet_specification[street][3]["utg"] = true
|
1434
|
+
@call_bet_specification[street][3]["cutoff"] = false
|
1435
|
+
@fold_to_bet_specification[street][3]["cutoff"] = false
|
1436
|
+
@bet_specification[street][4]["cutoff"] = true
|
1437
|
+
@call_bet_specification[street][4]["button"] = false
|
1438
|
+
@call_bet_specification[street][4]["sb"] = true
|
1439
|
+
@call_bet_specification[street][4]["bb"] = false
|
1440
|
+
@fold_to_bet_specification[street][4]["button"] = true
|
1441
|
+
@fold_to_bet_specification[street][4]["sb"] = false
|
1442
|
+
@fold_to_bet_specification[street][4]["bb"] = false
|
1443
|
+
@stats.should have_last_aggr(street, "bb")
|
1444
|
+
end
|
1445
|
+
end
|
1446
|
+
it {@stats.should have_street_bet_statistics_specified_by @bet_specification, ""}
|
1447
|
+
it {@stats.should have_street_bet_statistics_specified_by @call_bet_specification, "call_"}
|
1448
|
+
it {@stats.should have_street_bet_statistics_specified_by @fold_to_bet_specification, "fold_to_"}
|
1449
|
+
end
|
1450
|
+
end
|
1451
|
+
|
1452
|
+
context "after 4 raises" do
|
1453
|
+
context "preflop" do
|
1454
|
+
before(:each) do
|
1455
|
+
register_raise_to(@utg, 10)
|
1456
|
+
register_raise_to(@cutoff, 50)
|
1457
|
+
register_raise_to(@button, 150)
|
1458
|
+
register_raise_to(@sb, 500)
|
1459
|
+
register_fold(@bb)
|
1460
|
+
register_call(@utg, 490)
|
1461
|
+
register_raise_to(@utg, 1000)
|
1462
|
+
@call_bet_specification[:preflop][1]["utg"] = false
|
1463
|
+
@fold_to_bet_specification[:preflop][1]["utg"] = false
|
1464
|
+
@bet_specification[:preflop][2]["utg"] = true
|
1465
|
+
@call_bet_specification[:preflop][2]["cutoff"] = false
|
1466
|
+
@fold_to_bet_specification[:preflop][2]["cutoff"] = false
|
1467
|
+
@bet_specification[:preflop][3]["cutoff"] = true
|
1468
|
+
@call_bet_specification[:preflop][3]["button"] = false
|
1469
|
+
@fold_to_bet_specification[:preflop][3]["button"] = false
|
1470
|
+
@bet_specification[:preflop][4]["button"] = true
|
1471
|
+
@call_bet_specification[:preflop][4]["sb"] = false
|
1472
|
+
@fold_to_bet_specification[:preflop][4]["sb"] = false
|
1473
|
+
@stats.should have_last_aggr(:preflop, "utg")
|
1474
|
+
end
|
1475
|
+
it {@stats.should have_street_bet_statistics_specified_by @bet_specification, ""}
|
1476
|
+
it {@stats.should have_street_bet_statistics_specified_by @call_bet_specification, "call_"}
|
1477
|
+
it {@stats.should have_street_bet_statistics_specified_by @fold_to_bet_specification, "fold_to_"}
|
1478
|
+
end
|
1479
|
+
context "other streets" do
|
1480
|
+
before(:each) do
|
1481
|
+
[:flop, :turn, :river].each do |street|
|
1482
|
+
register_street street
|
1483
|
+
register_bet(@sb, 5)
|
1484
|
+
register_raise_to(@bb, 10)
|
1485
|
+
register_raise_to(@utg, 50)
|
1486
|
+
register_raise_to(@cutoff, 150)
|
1487
|
+
register_raise_to(@button, 500)
|
1488
|
+
register_fold(@sb)
|
1489
|
+
register_call(@bb, 490)
|
1490
|
+
register_raise_to(@utg,1000)
|
1491
|
+
@bet_specification[street][1]["sb"] = true
|
1492
|
+
@call_bet_specification[street][1]["bb"] = false
|
1493
|
+
@fold_to_bet_specification[street][1]["bb"] = false
|
1494
|
+
@bet_specification[street][2]["bb"] = true
|
1495
|
+
@call_bet_specification[street][2]["utg"] = false
|
1496
|
+
@fold_to_bet_specification[street][2]["utg"] = false
|
1497
|
+
@bet_specification[street][3]["utg"] = true
|
1498
|
+
@call_bet_specification[street][3]["cutoff"] = false
|
1499
|
+
@fold_to_bet_specification[street][3]["cutoff"] = false
|
1500
|
+
@bet_specification[street][4]["cutoff"] = true
|
1501
|
+
@call_bet_specification[street][4]["button"] = false
|
1502
|
+
@fold_to_bet_specification[street][4]["button"] = false
|
1503
|
+
@stats.should have_last_aggr(street, "utg")
|
1504
|
+
end
|
1505
|
+
end
|
1506
|
+
it {@stats.should have_street_bet_statistics_specified_by @bet_specification, ""}
|
1507
|
+
it {@stats.should have_street_bet_statistics_specified_by @call_bet_specification, "call_"}
|
1508
|
+
it {@stats.should have_street_bet_statistics_specified_by @fold_to_bet_specification, "fold_to_"}
|
1509
|
+
end
|
1510
|
+
end
|
1511
|
+
end
|
1512
|
+
|
1513
|
+
context "cbets and dbets by street" do
|
1514
|
+
before(:each) do
|
1515
|
+
@stats = HandStatistics.new
|
1516
|
+
@stats.register_player @button = next_sample_player(:screen_name => "button")
|
1517
|
+
@stats.register_player @sb = next_sample_player(:screen_name => "sb")
|
1518
|
+
@stats.register_player @bb = next_sample_player(:screen_name => "bb")
|
1519
|
+
@stats.register_button @button[:seat]
|
1520
|
+
register_street :prelude
|
1521
|
+
register_post @sb, 1
|
1522
|
+
register_post @bb, 2
|
1523
|
+
register_street :preflop
|
1524
|
+
end
|
1525
|
+
|
1526
|
+
it "should not find cbet or dbet opportunity without a raise on the prior street" do
|
1527
|
+
register_call @button, 2
|
1528
|
+
register_call @sb, 1
|
1529
|
+
register_check @bb
|
1530
|
+
register_street :flop
|
1531
|
+
register_check @sb
|
1532
|
+
register_check @bb
|
1533
|
+
register_bet @button, 2
|
1534
|
+
puts "last_aggr_player = #{@stats.last_aggr_player.inspect}"
|
1535
|
+
["sb", "bb", "button"].each do |player|
|
1536
|
+
@stats.cbet_flop(player).should be_nil
|
1537
|
+
@stats.call_cbet_flop(player).should be_nil
|
1538
|
+
@stats.fold_to_cbet_flop(player).should be_nil
|
1539
|
+
@stats.dbet_flop(player).should be_nil
|
1540
|
+
@stats.call_dbet_flop(player).should be_nil
|
1541
|
+
@stats.fold_to_dbet_flop(player).should be_nil
|
1542
|
+
end
|
1543
|
+
end
|
1544
|
+
|
1545
|
+
context "when button last bets each street and bets first in on the next" do
|
1546
|
+
before(:each) do
|
1547
|
+
[:flop, :turn, :river].each do |street|
|
1548
|
+
if street == :flop
|
1549
|
+
register_raise_to(@button, 100)
|
1550
|
+
register_call(@sb, 99)
|
1551
|
+
register_call(@bb, 98)
|
1552
|
+
end
|
1553
|
+
register_street street
|
1554
|
+
register_check(@sb)
|
1555
|
+
register_check(@bb)
|
1556
|
+
register_bet(@button, 100)
|
1557
|
+
register_call(@sb, 100)
|
1558
|
+
register_fold(@bb)
|
1559
|
+
end
|
1560
|
+
end
|
1561
|
+
it "should correctly compute cbet stats" do
|
1562
|
+
[:flop, :turn, :river].each do |street|
|
1563
|
+
@stats.send("cbet_#{street}", "sb").should be_nil
|
1564
|
+
@stats.send("cbet_#{street}", "bb").should be_nil
|
1565
|
+
@stats.send("cbet_#{street}", "button").should be_true
|
1566
|
+
@stats.send("call_cbet_#{street}", "sb").should be_true
|
1567
|
+
@stats.send("call_cbet_#{street}", "bb").should be_false
|
1568
|
+
@stats.send("call_cbet_#{street}", "button").should be_nil
|
1569
|
+
@stats.send("fold_to_cbet_#{street}", "sb").should be_false
|
1570
|
+
@stats.send("fold_to_cbet_#{street}", "bb").should be_true
|
1571
|
+
@stats.send("fold_to_cbet_#{street}", "button").should be_nil
|
1572
|
+
@stats.send("dbet_#{street}", "sb").should be_false
|
1573
|
+
@stats.send("dbet_#{street}", "bb").should be_false
|
1574
|
+
@stats.send("dbet_#{street}", "button").should be_nil
|
1575
|
+
[:sb, :bb, :button].each do |player|
|
1576
|
+
@stats.send("call_dbet_#{street}", "sb").should be_nil
|
1577
|
+
@stats.send("fold_to_dbet_#{street}", "bb").should be_nil
|
1578
|
+
end
|
1579
|
+
end
|
1580
|
+
end
|
1581
|
+
end
|
1582
|
+
|
1583
|
+
context "when button last bets each street and bb donk bets" do
|
1584
|
+
before(:each) do
|
1585
|
+
[:flop, :turn, :river].each do |street|
|
1586
|
+
if street == :flop
|
1587
|
+
register_raise_to(@button, 100)
|
1588
|
+
register_call(@sb, 99)
|
1589
|
+
register_call(@bb, 98)
|
1590
|
+
end
|
1591
|
+
register_street street
|
1592
|
+
register_check(@sb)
|
1593
|
+
register_bet(@bb, 100)
|
1594
|
+
register_raise_to(@button, 200)
|
1595
|
+
register_fold(@sb)
|
1596
|
+
register_call(@sb, 100)
|
1597
|
+
end
|
1598
|
+
end
|
1599
|
+
it "should correctly compute cbet stats" do
|
1600
|
+
[:flop, :turn, :river].each do |street|
|
1601
|
+
[:sb, :bb, :button].each do |player|
|
1602
|
+
@stats.send("cbet_#{street}", player).should be_nil
|
1603
|
+
@stats.send("call_cbet_#{street}", player).should be_nil
|
1604
|
+
@stats.send("fold_to_cbet_#{street}", player).should be_nil
|
1605
|
+
end
|
1606
|
+
@stats.send("dbet_#{street}", "sb").should be_false
|
1607
|
+
@stats.send("dbet_#{street}", "bb").should be_true
|
1608
|
+
@stats.send("dbet_#{street}", "button").should be_nil
|
1609
|
+
@stats.send("call_dbet_#{street}", "sb").should be_nil
|
1610
|
+
@stats.send("call_dbet_#{street}", "bb").should be_nil
|
1611
|
+
@stats.send("call_dbet_#{street}", "button").should be_false
|
1612
|
+
@stats.send("fold_to_dbet_#{street}", "sb").should be_nil
|
1613
|
+
@stats.send("fold_to_dbet_#{street}", "bb").should be_nil
|
1614
|
+
@stats.send("fold_to_dbet_#{street}", "button").should be_false
|
1615
|
+
end
|
1616
|
+
end
|
1617
|
+
end
|
1618
|
+
|
1619
|
+
context "when big blind last bets each street and bets first in on the next" do
|
1620
|
+
before(:each) do
|
1621
|
+
[:flop, :turn, :river].each do |street|
|
1622
|
+
if street == :flop
|
1623
|
+
register_call(@button, 2)
|
1624
|
+
register_call(@sb, 1)
|
1625
|
+
register_raise_to(@bb, 100)
|
1626
|
+
register_call(@button, 98)
|
1627
|
+
register_call(@sb, 98)
|
1628
|
+
end
|
1629
|
+
register_street street
|
1630
|
+
register_check(@sb)
|
1631
|
+
register_bet(@bb, 100)
|
1632
|
+
register_call(@button, 100)
|
1633
|
+
register_fold(@sb)
|
1634
|
+
end
|
1635
|
+
end
|
1636
|
+
it "should correctly compute cbet stats" do
|
1637
|
+
[:flop, :turn, :river].each do |street|
|
1638
|
+
@stats.send("cbet_#{street}", "sb").should be_nil
|
1639
|
+
@stats.send("cbet_#{street}", "bb").should be_true
|
1640
|
+
@stats.send("cbet_#{street}", "button").should be_nil
|
1641
|
+
@stats.send("call_cbet_#{street}", "sb").should be_false
|
1642
|
+
@stats.send("call_cbet_#{street}", "bb").should be_nil
|
1643
|
+
@stats.send("call_cbet_#{street}", "button").should be_true
|
1644
|
+
@stats.send("fold_to_cbet_#{street}", "sb").should be_true
|
1645
|
+
@stats.send("fold_to_cbet_#{street}", "bb").should be_nil
|
1646
|
+
@stats.send("fold_to_cbet_#{street}", "button").should be_false
|
1647
|
+
@stats.send("dbet_#{street}", "sb").should be_false
|
1648
|
+
@stats.send("dbet_#{street}", "bb").should be_nil
|
1649
|
+
@stats.send("dbet_#{street}", "button").should be_nil
|
1650
|
+
[:sb, :bb, :button].each do |player|
|
1651
|
+
@stats.send("call_dbet_#{street}", "sb").should be_nil
|
1652
|
+
@stats.send("fold_to_dbet_#{street}", "bb").should be_nil
|
1653
|
+
end
|
1654
|
+
end
|
1655
|
+
end
|
1656
|
+
end
|
1657
|
+
|
1658
|
+
context "when button is last aggressor preflop and checks on flop" do
|
1659
|
+
before(:each) do
|
1660
|
+
register_raise_to(@button, 100)
|
1661
|
+
register_call(@sb, 99)
|
1662
|
+
register_call(@bb, 98)
|
1663
|
+
register_street :flop
|
1664
|
+
register_check(@sb)
|
1665
|
+
register_check(@bb)
|
1666
|
+
register_check(@button)
|
1667
|
+
end
|
1668
|
+
|
1669
|
+
it "correctly compute cbet stats" do
|
1670
|
+
@stats.cbet_flop("sb").should be_nil
|
1671
|
+
@stats.cbet_flop("bb").should be_nil
|
1672
|
+
@stats.cbet_flop("button").should be_false
|
1673
|
+
["sb", "bb", "button"].each do |player|
|
1674
|
+
@stats.send("call_cbet_flop", player).should be_nil
|
1675
|
+
@stats.send("fold_to_cbet_flop", player).should be_nil
|
1676
|
+
end
|
1677
|
+
@stats.dbet_flop("sb").should be_false
|
1678
|
+
@stats.dbet_flop("bb").should be_false
|
1679
|
+
@stats.dbet_flop("button").should be_nil
|
1680
|
+
[:sb, :bb, :button].each do |player|
|
1681
|
+
@stats.dbet_flop(player).should be_nil
|
1682
|
+
end
|
1683
|
+
end
|
1684
|
+
end
|
1685
|
+
|
1686
|
+
context "when button is last aggressor flop and checks on turn" do
|
1687
|
+
before(:each) do
|
1688
|
+
register_street :flop
|
1689
|
+
register_check(@sb)
|
1690
|
+
register_check(@bb)
|
1691
|
+
register_bet(@button, 100)
|
1692
|
+
register_call(@sb, 100)
|
1693
|
+
register_call(@bb, 100)
|
1694
|
+
register_street :turn
|
1695
|
+
register_check(@sb)
|
1696
|
+
register_check(@bb)
|
1697
|
+
register_check(@button)
|
1698
|
+
end
|
1699
|
+
|
1700
|
+
it "correctly compute cbet stats" do
|
1701
|
+
@stats.cbet_turn("sb").should be_nil
|
1702
|
+
@stats.cbet_turn("bb").should be_nil
|
1703
|
+
@stats.cbet_turn("button").should be_false
|
1704
|
+
["sb", "bb", "button"].each do |player|
|
1705
|
+
@stats.send("call_cbet_turn", player).should be_nil
|
1706
|
+
@stats.send("fold_to_cbet_turn", player).should be_nil
|
1707
|
+
end
|
1708
|
+
@stats.dbet_turn("sb").should be_false
|
1709
|
+
@stats.dbet_turn("bb").should be_false
|
1710
|
+
@stats.dbet_turn("button").should be_nil
|
1711
|
+
[:sb, :bb, :button].each do |player|
|
1712
|
+
@stats.dbet_turn(player).should be_nil
|
1713
|
+
end
|
1714
|
+
end
|
1715
|
+
end
|
1716
|
+
|
1717
|
+
context "when button is last aggressor turn and checks on river" do
|
1718
|
+
before(:each) do
|
1719
|
+
register_street :turn
|
1720
|
+
register_check(@sb)
|
1721
|
+
register_check(@bb)
|
1722
|
+
register_bet(@button, 100)
|
1723
|
+
register_call(@sb, 100)
|
1724
|
+
register_call(@bb, 100)
|
1725
|
+
register_street :river
|
1726
|
+
register_check(@sb)
|
1727
|
+
register_check(@bb)
|
1728
|
+
register_check(@button)
|
1729
|
+
end
|
1730
|
+
|
1731
|
+
it "correctly compute cbet stats" do
|
1732
|
+
@stats.cbet_river("sb").should be_nil
|
1733
|
+
@stats.cbet_river("bb").should be_nil
|
1734
|
+
@stats.cbet_river("button").should be_false
|
1735
|
+
["sb", "bb", "button"].each do |player|
|
1736
|
+
@stats.send("call_cbet_river", player).should be_nil
|
1737
|
+
@stats.send("fold_to_cbet_river", player).should be_nil
|
1738
|
+
end
|
1739
|
+
@stats.dbet_river("sb").should be_false
|
1740
|
+
@stats.dbet_river("bb").should be_false
|
1741
|
+
@stats.dbet_river("button").should be_nil
|
1742
|
+
[:sb, :bb, :button].each do |player|
|
1743
|
+
@stats.dbet_river(player).should be_nil
|
1744
|
+
end
|
1745
|
+
end
|
1746
|
+
end
|
1747
|
+
end
|
1748
|
+
end
|
1749
|
+
|
1750
|
+
context "when reporting statistics" do
|
1751
|
+
before(:each) do
|
1752
|
+
@stats = HandStatistics.new
|
1753
|
+
@stats.register_player @seat2 = next_sample_player(:seat => 2, :screen_name => "seat2")
|
1754
|
+
@stats.register_player @seat4 = next_sample_player(:seat => 4, :screen_name => "seat4")
|
1755
|
+
@stats.register_player @seat6 = next_sample_player(:seat => 6, :screen_name => "seat6")
|
1756
|
+
@stats.register_player @seat8 = next_sample_player(:seat => 8, :screen_name => "seat8")
|
1757
|
+
@stats.register_button 1
|
1758
|
+
@blind_attack_plugin = @stats.plugins.find{|each| each.is_a? BlindAttackStatistics}
|
1759
|
+
@cash_plugin = @stats.plugins.find{|each| each.is_a? CashStatistics}
|
1760
|
+
@continuation_bet_plugin = @stats.plugins.find{|each| each.is_a? ContinuationBetStatistics}
|
1761
|
+
@aggression_plugin = @stats.plugins.find{|each| each.is_a? AggressionStatistics}
|
1762
|
+
@preflop_raise_plugin = @stats.plugins.find{|each| each.is_a? PreflopRaiseStatistics}
|
1763
|
+
@street_plugin = @stats.plugins.find{|each| each.is_a? StreetStatistics}
|
1764
|
+
@street_bet_plugin = @stats.plugins.find{|each| each.is_a? StreetBetStatistics}
|
1765
|
+
@reports = {}
|
1766
|
+
end
|
1767
|
+
|
1768
|
+
it "should report blind attack statistics for each player" do
|
1769
|
+
@blind_attack_plugin.should_receive(:blind_attack_opportunity?).exactly(@stats.players.size)
|
1770
|
+
@blind_attack_plugin.should_receive(:blind_attack_opportunity_taken?).exactly(@stats.players.size)
|
1771
|
+
@blind_attack_plugin.should_receive(:blind_defense_opportunity?).exactly(@stats.players.size)
|
1772
|
+
@blind_attack_plugin.should_receive(:blind_defense_opportunity_taken?).exactly(@stats.players.size)
|
1773
|
+
@reports = @stats.reports
|
1774
|
+
@stats.players.each{|each| @reports[each].should include(
|
1775
|
+
:is_blind_attack_opportunity,
|
1776
|
+
:is_blind_attack_opportunity_taken,
|
1777
|
+
:is_blind_defense_opportunity,
|
1778
|
+
:is_blind_defense_opportunity_taken
|
1779
|
+
)}
|
1780
|
+
end
|
825
1781
|
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
1782
|
+
it "should report continuation bet statistics for each player" do
|
1783
|
+
@continuation_bet_plugin.should_receive(:cbet_opportunity?).exactly(@stats.players.size)
|
1784
|
+
@continuation_bet_plugin.should_receive(:cbet_opportunity_taken?).exactly(@stats.players.size)
|
1785
|
+
@reports = @stats.reports
|
1786
|
+
@stats.players.each{|each| @reports[each].should include(:is_cbet_opportunity)}
|
1787
|
+
@stats.players.each{|each| @reports[each].should include(:is_cbet_opportunity_taken)}
|
1788
|
+
end
|
833
1789
|
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
1790
|
+
it "should report cash statistics for each player" do
|
1791
|
+
report_items = [
|
1792
|
+
:seat, :position, :cards, :card_category_index,
|
1793
|
+
:posted, :paid, :won, :profit,
|
1794
|
+
:posted_in_bb, :paid_in_bb, :won_in_bb, :profit_in_bb,
|
1795
|
+
:starting_stack, :starting_stack_in_bb, :starting_stack_as_M, :starting_stack_as_M_class
|
1796
|
+
]
|
1797
|
+
report_items.each{|report_item| @cash_plugin.should_receive(report_item).exactly(@stats.players.size)}
|
1798
|
+
@reports = @stats.reports
|
1799
|
+
report_items.each{|report_item|@stats.players.each{|each| @reports[each].should include(report_item)}}
|
1800
|
+
end
|
840
1801
|
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
1802
|
+
it "should report aggression statistics for each player" do
|
1803
|
+
@aggression_plugin.should_receive(:preflop_passive).exactly(@stats.players.size)
|
1804
|
+
@aggression_plugin.should_receive(:preflop_aggressive).exactly(@stats.players.size)
|
1805
|
+
@aggression_plugin.should_receive(:postflop_passive).exactly(@stats.players.size)
|
1806
|
+
@aggression_plugin.should_receive(:postflop_aggressive).exactly(@stats.players.size)
|
1807
|
+
@reports = @stats.reports
|
1808
|
+
@stats.players.each{|each| @reports[each].should include(:preflop_passive)}
|
1809
|
+
@stats.players.each{|each| @reports[each].should include(:preflop_aggressive)}
|
1810
|
+
@stats.players.each{|each| @reports[each].should include(:postflop_passive)}
|
1811
|
+
@stats.players.each{|each| @reports[each].should include(:postflop_aggressive)}
|
1812
|
+
end
|
852
1813
|
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
1814
|
+
it "should report preflop raise statistics for each player" do
|
1815
|
+
@preflop_raise_plugin.should_receive(:pfr_opportunity?).exactly(@stats.players.size)
|
1816
|
+
@preflop_raise_plugin.should_receive(:pfr_opportunity_taken?).exactly(@stats.players.size)
|
1817
|
+
@reports = @stats.reports
|
1818
|
+
@stats.players.each{|each| @reports[each].should include(:is_pfr_opportunity)}
|
1819
|
+
@stats.players.each{|each| @reports[each].should include(:is_pfr_opportunity_taken)}
|
1820
|
+
end
|
1821
|
+
|
1822
|
+
it "should report street statistics for each player" do
|
1823
|
+
report_items = [
|
1824
|
+
:saw_flop,:saw_turn,:saw_river,:saw_showdown,
|
1825
|
+
:won_preflop, :won_flop, :won_turn, :won_river, :won_showdown
|
1826
|
+
]
|
1827
|
+
report_items.each{|report_item| @street_plugin.should_receive(report_item).exactly(@stats.players.size)}
|
1828
|
+
@reports = @stats.reports
|
1829
|
+
report_items.each{|report_item|@stats.players.each{|each| @reports[each].should include(report_item)}}
|
1830
|
+
end
|
1831
|
+
|
1832
|
+
it "should report street bet statistics for each player" do
|
1833
|
+
report_items = [
|
1834
|
+
:preflop_2bet, :preflop_3bet, :preflop_4bet,
|
1835
|
+
:flop_1bet, :flop_2bet, :flop_3bet, :flop_4bet,
|
1836
|
+
:turn_1bet, :turn_2bet, :turn_3bet, :turn_4bet,
|
1837
|
+
:river_1bet, :river_2bet, :river_3bet, :river_4bet,
|
1838
|
+
:call_flop_1bet, :call_flop_2bet, :call_flop_3bet, :call_flop_4bet,
|
1839
|
+
:call_turn_1bet, :call_turn_2bet, :call_turn_3bet, :call_turn_4bet,
|
1840
|
+
:call_river_1bet, :call_river_2bet, :call_river_3bet, :call_river_4bet,
|
1841
|
+
:fold_to_preflop_1bet, :fold_to_preflop_2bet, :fold_to_preflop_3bet, :fold_to_preflop_4bet,
|
1842
|
+
:fold_to_flop_1bet, :fold_to_flop_2bet, :fold_to_flop_3bet, :fold_to_flop_4bet,
|
1843
|
+
:fold_to_turn_1bet, :fold_to_turn_2bet, :fold_to_turn_3bet, :fold_to_turn_4bet,
|
1844
|
+
:fold_to_river_1bet, :fold_to_river_2bet, :fold_to_river_3bet, :fold_to_river_4bet,
|
1845
|
+
:last_aggr_preflop, :last_aggr_flop, :last_aggr_turn, :last_aggr_river,
|
1846
|
+
:cbet_flop, :cbet_turn, :cbet_river,
|
1847
|
+
:fold_to_cbet_flop, :fold_to_cbet_turn, :fold_to_cbet_river,
|
1848
|
+
:dbet_flop, :dbet_turn, :dbet_river,
|
1849
|
+
:fold_to_dbet_flop, :fold_to_dbet_turn, :fold_to_dbet_river
|
1850
|
+
]
|
1851
|
+
report_items.each{|report_item| @street_bet_plugin.should_receive(report_item).exactly(@stats.players.size)}
|
1852
|
+
@reports = @stats.reports
|
1853
|
+
report_items.each{|report_item|@stats.players.each{|each| @reports[each].should include(report_item)}}
|
1854
|
+
end
|
1855
|
+
end
|
860
1856
|
end
|