pokerstats 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. data/.document +5 -0
  2. data/.gitignore +5 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +18 -0
  5. data/Rakefile +50 -0
  6. data/VERSION +1 -0
  7. data/bin/checkps +190 -0
  8. data/generators/pokerstats/USAGE +1 -0
  9. data/generators/pokerstats/pokerstats_generator.rb +7 -0
  10. data/generators/pokerstats/templates/create_pokerstats.rhtml +28 -0
  11. data/lib/pokerstats.rb +2 -0
  12. data/lib/pokerstats/.gitignore +0 -0
  13. data/lib/pokerstats/hand_constants.rb +27 -0
  14. data/lib/pokerstats/hand_history.rb +38 -0
  15. data/lib/pokerstats/hand_statistics.rb +225 -0
  16. data/lib/pokerstats/hand_statistics_api.rb +64 -0
  17. data/lib/pokerstats/player_statistics.rb +58 -0
  18. data/lib/pokerstats/plugins/aggression_statistics.rb +57 -0
  19. data/lib/pokerstats/plugins/blind_attack_statistics.rb +78 -0
  20. data/lib/pokerstats/plugins/cash_statistics.rb +95 -0
  21. data/lib/pokerstats/plugins/continuation_bet_statistics.rb +68 -0
  22. data/lib/pokerstats/plugins/preflop_raise_statistics.rb +50 -0
  23. data/lib/pokerstats/poker-edge.rb +57 -0
  24. data/lib/pokerstats/pokerstars_file.rb +100 -0
  25. data/lib/pokerstats/pokerstars_hand_history_parser.rb +141 -0
  26. data/pokerstats.gemspec +91 -0
  27. data/spec/file_empty.txt +0 -0
  28. data/spec/file_many_hands.txt +564 -0
  29. data/spec/file_one_hand.txt +52 -0
  30. data/spec/hand_statistics_spec.rb +846 -0
  31. data/spec/hand_statistics_spec_helper.rb +89 -0
  32. data/spec/player_statistics_spec.rb +230 -0
  33. data/spec/pokerstars_file_spec.rb +160 -0
  34. data/spec/pokerstars_hand_history_parser_spec.rb +197 -0
  35. data/spec/spec_helper.rb +9 -0
  36. data/spec/zpokerstars_hand_history_parser_integration.rb.txt +67 -0
  37. metadata +125 -0
@@ -0,0 +1,64 @@
1
+ module Pokerstats
2
+ module HandStatisticsAPI
3
+ def initialize handstatistics
4
+ @hand_statistics = handstatistics
5
+ end
6
+
7
+ def self.exposed_methods
8
+ self.public_instance_methods - StatisticsHolder.public_instance_methods
9
+ end
10
+
11
+ def report screen_name
12
+ automatic_report screen_name
13
+ end
14
+
15
+ def register_player screen_name, street
16
+ end
17
+
18
+ def street_transition street
19
+ end
20
+
21
+ def street_transition_for_player street, player
22
+ end
23
+
24
+ def apply_action action, street
25
+ end
26
+
27
+ def automatic_report screen_name
28
+ result = {}
29
+ self.class.report_specification.each do |each|
30
+ result[each[0]] = send(each[2], screen_name)
31
+ end
32
+ result
33
+ end
34
+
35
+ private
36
+
37
+ module ClassMethods
38
+ def report_specification
39
+ [
40
+ # [key, sql_type, function]
41
+ ]
42
+ end
43
+
44
+ def rails_migration_segment_for_player_data
45
+ prefix = "\n" + " " * 10
46
+ result = "#{prefix}# FROM #{self.to_s}"
47
+ report_specification.each do |each|
48
+ result += "#{prefix}t.#{each[1]}\t#{each[0].inspect}"
49
+ end
50
+ result += "\n"
51
+ end
52
+
53
+ def rails_generator_command_line_for_player_data
54
+ report_specification.inject("") do |string, each|
55
+ string + "#{each[0]}:#{each[1]} "
56
+ end
57
+ end
58
+ end
59
+
60
+ def self.included(klass)
61
+ klass.extend ClassMethods
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,58 @@
1
+ module Pokerstats
2
+ class PlayerStatistics
3
+
4
+ def initialize
5
+ @aggregate_statistics = {}
6
+ end
7
+
8
+ def reports
9
+ @aggregate_statistics
10
+ end
11
+
12
+ def aggregate_numeric_statistic each_player, reports, aggregate_stat, hand_stat
13
+ @aggregate_statistics[each_player][aggregate_stat] ||= 0
14
+ @aggregate_statistics[each_player][aggregate_stat] += reports[each_player][hand_stat]
15
+ end
16
+
17
+ def aggregate_boolean_statistic each_player, reports, aggregate_stat, hand_stat
18
+ @aggregate_statistics[each_player][aggregate_stat] ||= 0
19
+ @aggregate_statistics[each_player][aggregate_stat] += 1 if reports[each_player][hand_stat]
20
+ end
21
+
22
+ def aggregate_statistic each_player, reports, aggregate_stat, hand_stat
23
+ @aggregate_statistics[each_player][aggregate_stat] ||= 0
24
+ if /^is_/ =~ hand_stat.to_s
25
+ @aggregate_statistics[each_player][aggregate_stat] += 1 if reports[each_player][hand_stat]
26
+ else
27
+ @aggregate_statistics[each_player][aggregate_stat] += reports[each_player][hand_stat]
28
+ end
29
+ end
30
+
31
+ def record hand_statistics
32
+ reports = hand_statistics.reports
33
+ reports.keys.each do |each_player|
34
+ @aggregate_statistics[each_player] ||= {}
35
+
36
+ @aggregate_statistics[each_player][:t_hands] ||= 0
37
+ @aggregate_statistics[each_player][:t_hands] += 1
38
+ @aggregate_statistics[each_player][:t_vpip] ||= 0
39
+ @aggregate_statistics[each_player][:t_vpip] += 1 unless reports[each_player][:paid].zero?
40
+ aggregate_numeric_statistic each_player, reports, :t_posted, :posted
41
+ aggregate_numeric_statistic each_player, reports, :t_paid, :paid
42
+ aggregate_numeric_statistic each_player, reports, :t_won, :won
43
+ aggregate_numeric_statistic each_player, reports, :t_preflop_passive, :preflop_passive
44
+ aggregate_numeric_statistic each_player, reports, :t_preflop_aggressive, :preflop_aggressive
45
+ aggregate_numeric_statistic each_player, reports, :t_postflop_passive, :postflop_passive
46
+ aggregate_numeric_statistic each_player, reports, :t_postflop_aggressive, :postflop_aggressive
47
+ aggregate_boolean_statistic each_player, reports, :t_blind_attack_opportunity, :is_blind_attack_opportunity
48
+ aggregate_boolean_statistic each_player, reports, :t_blind_attack_opportunity_taken, :is_blind_attack_opportunity_taken
49
+ aggregate_boolean_statistic each_player, reports, :t_blind_defense_opportunity, :is_blind_defense_opportunity
50
+ aggregate_boolean_statistic each_player, reports, :t_blind_defense_opportunity_taken, :is_blind_defense_opportunity_taken
51
+ aggregate_boolean_statistic each_player, reports, :t_pfr_opportunity, :is_pfr_opportunity
52
+ aggregate_boolean_statistic each_player, reports, :t_pfr_opportunity_taken, :is_pfr_opportunity_taken
53
+ aggregate_boolean_statistic each_player, reports, :t_cbet_opportunity, :is_cbet_opportunity
54
+ aggregate_boolean_statistic each_player, reports, :t_cbet_opportunity_taken, :is_cbet_opportunity_taken
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,57 @@
1
+ module Pokerstats
2
+ class AggressionStatistics < HandStatistics::Plugin
3
+
4
+ def self.report_specification
5
+ [
6
+ # [key, sql_type, function]
7
+ [:preflop_passive, 'integer', :preflop_passive],
8
+ [:postflop_passive, 'integer', :postflop_passive],
9
+ [:preflop_aggressive, 'integer', :preflop_aggressive],
10
+ [:postflop_aggressive, 'integer', :postflop_aggressive]
11
+ ]
12
+ end
13
+
14
+ def initialize handstatistics
15
+ super handstatistics
16
+ @preflop_passive = {}
17
+ @preflop_aggressive = {}
18
+ @postflop_passive = {}
19
+ @postflop_aggressive = {}
20
+ end
21
+
22
+ def preflop_passive(screen_name)
23
+ @preflop_passive[screen_name]
24
+ end
25
+
26
+ def postflop_passive(screen_name)
27
+ @postflop_passive[screen_name]
28
+ end
29
+
30
+ def preflop_aggressive(screen_name)
31
+ @preflop_aggressive[screen_name]
32
+ end
33
+
34
+ def postflop_aggressive(screen_name)
35
+ @postflop_aggressive[screen_name]
36
+ end
37
+
38
+ def register_player screen_name, street
39
+ @preflop_passive[screen_name] = 0
40
+ @preflop_aggressive[screen_name] = 0
41
+ @postflop_passive[screen_name] = 0
42
+ @postflop_aggressive[screen_name] = 0
43
+ end
44
+
45
+ def apply_action action, street
46
+ aggression = action[:aggression]
47
+ player = action[:screen_name]
48
+ if [:prelude, :preflop].member?(street)
49
+ @preflop_aggressive[player] +=1 if aggression == :aggressive
50
+ @preflop_passive[player] += 1 if aggression == :passive
51
+ else
52
+ @postflop_aggressive[player] +=1 if aggression == :aggressive
53
+ @postflop_passive[player] +=1 if aggression == :passive
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,78 @@
1
+ module Pokerstats
2
+ class BlindAttackStatistics < HandStatistics::Plugin
3
+ def initialize handstatistics
4
+ super(handstatistics)
5
+ @blind_attack_state = :no_action_taken
6
+ @blind_attack_opportunity = {}
7
+ @blind_attack_opportunity_taken ={}
8
+ @blind_defense_opportunity = {}
9
+ @blind_defense_opportunity_taken = {}
10
+ end
11
+
12
+ def blind_attack_opportunity?(screen_name)
13
+ @blind_attack_opportunity[screen_name]
14
+ end
15
+
16
+ def blind_attack_opportunity_taken?(screen_name)
17
+ @blind_attack_opportunity_taken[screen_name]
18
+ end
19
+
20
+ def blind_defense_opportunity?(screen_name)
21
+ @blind_defense_opportunity[screen_name]
22
+ end
23
+
24
+ def blind_defense_opportunity_taken?(screen_name)
25
+ @blind_defense_opportunity_taken[screen_name]
26
+ end
27
+
28
+ def self.report_specification
29
+ [
30
+ # [key, sql_type, function]
31
+ [:is_blind_attack_opportunity, 'integer', :blind_attack_opportunity?],
32
+ [:is_blind_attack_opportunity_taken, 'integer', :blind_attack_opportunity_taken?],
33
+ [:is_blind_defense_opportunity, 'integer', :blind_defense_opportunity?],
34
+ [:is_blind_defense_opportunity_taken, 'integer', :blind_defense_opportunity_taken?]
35
+ ]
36
+ end
37
+
38
+ # def report(screen_name)
39
+ # {
40
+ # :is_blind_attack_opportunity => blind_attack_opportunity?(screen_name),
41
+ # :is_blind_attack_opportunity_taken => blind_attack_opportunity_taken?(screen_name),
42
+ # :is_blind_defense_opportunity => blind_defense_opportunity?(screen_name),
43
+ # :is_blind_defense_opportunity_taken => blind_defense_opportunity_taken?(screen_name)
44
+ # }
45
+ # end
46
+
47
+ def apply_action action, street
48
+ player = action[:screen_name]
49
+ aggression = action[:aggression]
50
+
51
+ return if aggression == :neutral || street != :preflop
52
+
53
+ @blind_defense_opportunity[player] ||= @hand_statistics.blind?(player) && @blind_attack_state == :attacker_raised_first_in
54
+ @blind_defense_opportunity_taken[player] ||= @blind_defense_opportunity[player] && aggression != :fold
55
+ case @blind_attack_state
56
+ when :no_action_taken
57
+ @blind_attack_opportunity[player] ||= @hand_statistics.attacker?(player)
58
+ @blind_attack_opportunity_taken[player] ||= @hand_statistics.attacker?(player) && aggression == :aggressive
59
+ @blind_attack_state = case aggression
60
+ when :aggressive
61
+ @hand_statistics.attacker?(player) ? :attacker_raised_first_in : :responsive_action_taken
62
+ when :passive
63
+ :responsive_action_taken
64
+ else
65
+ :no_action_taken
66
+ end
67
+ when :attacker_raised_first_in
68
+ @blind_attack_opportunity[player] ||= false
69
+ @blind_attack_opportunity_taken[player] ||= false
70
+ @blind_attack_state = :responsive_action_taken unless [:check, :fold].member?(aggression)
71
+ when :responsive_action_taken
72
+ @blind_attack_opportunity[player] ||= false
73
+ @blind_attack_opportunity_taken[player] ||= false
74
+ else raise "invalid state: #{@blind_attack_state}"
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,95 @@
1
+ module Pokerstats
2
+ class CashStatistics < HandStatistics::Plugin
3
+ def initialize handstatistics
4
+ super handstatistics
5
+ @posted = {}
6
+ @paid = {}
7
+ @paid_this_round = {}
8
+ @won = {}
9
+ @cards = {}
10
+ @stats = {:posted => @posted, :paid => @paid, :won => @won, :cards => @cards}
11
+ end
12
+
13
+ def posted(player)
14
+ @posted[player]
15
+ end
16
+
17
+ def paid(player)
18
+ @paid[player]
19
+ end
20
+
21
+ def paid_this_round(player)
22
+ @paid_this_round[player]
23
+ end
24
+
25
+ def won(player)
26
+ @won[player]
27
+ end
28
+
29
+ def cards(player)
30
+ @cards[player]
31
+ end
32
+
33
+ def self.report_specification
34
+ [
35
+ # [key, sql_type, function]
36
+ [:posted, 'decimal', :posted],
37
+ [:paid, 'decimal', :paid],
38
+ [:won, 'decimal', :won],
39
+ [:cards, 'string', :cards]
40
+ ]
41
+ end
42
+
43
+ # def report(screen_name)
44
+ # {
45
+ # :posted => posted(screen_name),
46
+ # :paid => paid(screen_name),
47
+ # :won => won(screen_name),
48
+ # :cards => cards(screen_name)
49
+ # }
50
+ # end
51
+
52
+ def stats(player=nil)
53
+ return @stats unless player
54
+ # @stats.inject({}){|last, pair| last.merge(pair[0] => pair[1][player])}
55
+ end
56
+
57
+ def register_player(screen_name, street)
58
+ @posted[screen_name] = 0
59
+ @paid[screen_name] = 0
60
+ @won[screen_name] = 0
61
+ end
62
+
63
+ def street_transition_for_player street, player
64
+ @paid_this_round[player] = 0 unless street == :preflop
65
+ end
66
+
67
+ def apply_action action, street
68
+ player = action[:screen_name]
69
+ description = action[:description]
70
+ result = action[:result]
71
+ amount = action[:amount]
72
+ data = action[:data]
73
+ case result
74
+ when :post
75
+ @posted[player] += amount
76
+ @paid_this_round[player] += amount unless description == "antes"
77
+ when :pay
78
+ @paid[player] ||= 0
79
+ @paid[player] += amount
80
+ @paid_this_round[player] += amount
81
+ when :pay_to
82
+ net_amount_paid = amount - @paid_this_round[player]
83
+ action[:net_amount_paid] = net_amount_paid
84
+ @paid[player] += net_amount_paid
85
+ @paid_this_round[player] += net_amount_paid
86
+ when :win
87
+ @won[player] += amount
88
+ when :neutral
89
+ when :cards
90
+ @cards[player] = data
91
+ else raise "invalid action result: #{result.inspect}"
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,68 @@
1
+ module Pokerstats
2
+ class ContinuationBetStatistics < HandStatistics::Plugin
3
+ def initialize handstatistics
4
+ super(handstatistics)
5
+ @last_preflop_raiser = nil
6
+ @number_preflop_raises = 0
7
+ @first_aggressor = {}
8
+ @first_aggression_opportunity = {}
9
+ @first_aggression_opportunity_taken = {}
10
+ end
11
+
12
+ def cbet_opportunity?(screen_name, street = :flop)
13
+ # puts "cbet_opportunity?(#{screen_name}, #{street})"
14
+ # puts @first_aggression_opportunity.inspect
15
+ @number_preflop_raises==1 && @last_preflop_raiser==screen_name && @first_aggression_opportunity[street] && @first_aggression_opportunity[street][screen_name]
16
+ end
17
+
18
+ def cbet_opportunity_taken?(screen_name, street = :flop)
19
+ cbet_opportunity?(screen_name) && @first_aggression_opportunity_taken[street][screen_name]
20
+ end
21
+
22
+ def self.report_specification
23
+ [
24
+ # [key, sql_type, function]
25
+ [:is_cbet_opportunity, 'integer', :cbet_opportunity?],
26
+ [:is_cbet_opportunity_taken, 'integer', :cbet_opportunity_taken?]
27
+ ]
28
+ end
29
+
30
+ #
31
+ # def report(screen_name)
32
+ # {
33
+ # :is_cbet_opportunity => cbet_opportunity?(screen_name),
34
+ # :is_cbet_opportunity_taken => cbet_opportunity_taken?(screen_name)
35
+ # }
36
+ # end
37
+
38
+ def street_transition street
39
+ @first_aggressor[street] = nil
40
+ @first_aggression_opportunity[street] = {}
41
+ @first_aggression_opportunity_taken[street] = {}
42
+ super(street)
43
+ end
44
+
45
+ def street_transition_for_player street, player
46
+ @first_aggression_opportunity[street][player] = nil
47
+ @first_aggression_opportunity_taken[street][player] = false
48
+ end
49
+
50
+ def apply_action action, street
51
+ player = action[:screen_name]
52
+ aggression = action[:aggression]
53
+ result = action[:result]
54
+ if street == :preflop and result == :pay_to
55
+ @number_preflop_raises += 1
56
+ @last_preflop_raiser = player
57
+ end
58
+ if aggression != :neutral && @first_aggressor[street].nil? && @first_aggression_opportunity[street][player].nil?
59
+ @first_aggression_opportunity[street][player] = true
60
+ if aggression == :aggressive
61
+ @first_aggressor[street] = player
62
+ @first_aggression_opportunity_taken[street][player] = true
63
+ @hand_statistics.players.each {|player| @first_aggression_opportunity[street][player] ||= false}
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,50 @@
1
+ module Pokerstats
2
+ class PreflopRaiseStatistics < HandStatistics::Plugin
3
+
4
+ def initialize handstatistics
5
+ super handstatistics
6
+ @pfr_opportunity = {}
7
+ @pfr_opportunity_taken = {}
8
+ @pfr_size_in_bb = {}
9
+ end
10
+
11
+ def pfr_opportunity?(screen_name)
12
+ @pfr_opportunity[screen_name]
13
+ end
14
+
15
+ def pfr_opportunity_taken?(screen_name)
16
+ @pfr_opportunity[screen_name] && @pfr_opportunity_taken[screen_name]
17
+ end
18
+
19
+ def self.report_specification
20
+ [
21
+ # [key, sql_type, function]
22
+ [:is_pfr_opportunity, 'integer', :pfr_opportunity?],
23
+ [:is_pfr_opportunity_taken, 'integer', :pfr_opportunity_taken?]
24
+ ]
25
+ end
26
+
27
+ # def report screen_name
28
+ # {
29
+ # :is_pfr_opportunity => pfr_opportunity?(screen_name),
30
+ # :is_pfr_opportunity_taken => pfr_opportunity_taken?(screen_name)
31
+ # }
32
+ # end
33
+
34
+ def apply_action action, street
35
+ # puts "pfr: apply_action #{street}, #{action.inspect}"
36
+ result = action[:result]
37
+ player = action[:screen_name]
38
+ if street == :preflop and [:pay, :pay_to, :neutral].member?(result) and @pfr_opportunity[player].nil?
39
+ case result
40
+ when :pay, :neutral
41
+ @pfr_opportunity[player] = true
42
+ @pfr_opportunity_taken[player] = false
43
+ when :pay_to
44
+ @hand_statistics.players.each {|each_player| @pfr_opportunity[each_player] ||= (each_player == player)}
45
+ @pfr_opportunity_taken[player] = true
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end