poker_odds 0.1.3 → 0.1.4

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0f051198b6ad06d450eed6de84d7144e29f8799613a4b3afa9e51efcb361a79e
4
- data.tar.gz: 66e2a399060eba110e929582245c50ae6e654bb8c7efa8484e02a22cb71e5fe1
3
+ metadata.gz: f204234da42a8bd00fd9d1407dc188a9ea79856591b1bedb2e9c7d2d9c22cb34
4
+ data.tar.gz: b0884f1224a3e5655b92b3d602551c42fd42a89d9d0779d4331da8585c03f767
5
5
  SHA512:
6
- metadata.gz: 625b416f0687fcd883a399aeab7e6130453eb935450174ffef7aeb284b7a1e9742f7bdde89a58b717d635b8404176d60f04f619740dff4f028822ffaf641acf3
7
- data.tar.gz: 107664dcfa0b07d0da2c608bf56e740b5f59ab12c3ad75ebf5c25580f0780fe28c72ba2b8a14f0ae13d2475e31b44a8b26d8d08ab1e91abcf1b2d250721b6a16
6
+ metadata.gz: 2d980e663b61d2a91c6f7a68e5d8ab58873f927260f208162040dcee38043988ca3581a68b4253f78f32fa046ac0426ba59234357e4cdef5f6577cd203445b0f
7
+ data.tar.gz: 11738e7f2a97870f45c7db7aa9c33b12409780d971d513aef0ec7f6cfc85d1541a762f0ecfc8fdc8e4bc3e4649356753386733f57bb7c958546dcafd676b2cc6
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/poker_odds`. To experiment with that code, run `bin/console` for an interactive prompt.
4
4
 
5
- TODO: Delete this and the text above, and describe your gem
5
+ ポーカーのエクイティが分かる
6
6
 
7
7
  ## Installation
8
8
 
@@ -23,22 +23,14 @@ Or install it yourself as:
23
23
  ## Usage
24
24
 
25
25
  ```
26
- round = PokerOdds::Round.new(flop: 'Ah 9h Jd', turn: '3d')
27
- round.add_hand("9d 9c")
28
- round.add_hand("Kd Kc")
26
+ round = PokerOdds::Hand.new(flop: 'Ah 9h Jd', turn: '3d')
27
+ round.player='9d 9c, Kd Kc'
29
28
 
30
29
  round.equities
31
30
  # =>
32
- [{:hand=>[{:rank=>"K", :suit=>:d}, {:rank=>"K", :suit=>:c}],
33
- :win_rate=>0.045454545454545456,
34
- :lose_rate=>0.9545454545454546,
35
- :tie_rate=>0.0,
36
- :outs=>[{:suit=>:s, :rank=>"K"}, {:suit=>:h, :rank=>"K"}]},
37
- {:hand=>[{:rank=>"9", :suit=>:d}, {:rank=>"9", :suit=>:c}],
38
- :win_rate=>0.9545454545454546,
39
- :lose_rate=>0.045454545454545456,
40
- :tie_rate=>0.0,
41
- :outs=>[]}]
31
+ {[#<PokerTrump::Card:0x00007fedc3889ab0 @rank="9", @suit=:d>, #<PokerTrump::Card:0x00007fedc38898f8 @rank="9", @suit=:c>]=>{:win_rate=>0.9545454545454546, :lose_rate=>0.045454545454545456, :tie_rate=>0.0},
32
+ [#<PokerTrump::Card:0x00007fedc3889650 @rank="K", @suit=:d>, #<PokerTrump::Card:0x00007fedc38894e8 @rank="K", @suit=:c>]=>
33
+ {:win_rate=>0.045454545454545456, :lose_rate=>0.9545454545454546, :tie_rate=>0.0, :outs=>[#<PokerTrump::Card:0x00007feda08a3208 @rank="K", @suit=:s>, #<PokerTrump::Card:0x00007feda08a2bc8 @rank="K", @suit=:h>]}}
42
34
 
43
35
  ```
44
36
 
@@ -0,0 +1,165 @@
1
+ module PokerOdds
2
+ class Hand
3
+ include Virtus.model
4
+
5
+ attribute :player_hands, Array, default: []
6
+ attribute :flop_cards, PokerTrump::Cards
7
+ attribute :turn_card, PokerTrump::Card
8
+ attribute :river_card, PokerTrump::Card
9
+
10
+ attribute :expose_cards, PokerTrump::Cards
11
+
12
+ def player=(str)
13
+ self.player_hands = str.split(',').map do |s|
14
+ PokerTrump::Cards.from_string(s.lstrip)
15
+ end
16
+ self
17
+ end
18
+
19
+ def flop=(str)
20
+ self.flop_cards = PokerTrump::Cards.from_string(str)
21
+ self
22
+ end
23
+
24
+ def turn=(str)
25
+ self.turn_card = PokerTrump::Card.from_string(str)
26
+ self
27
+ end
28
+
29
+ def river=(s)
30
+ self.river_cards = PokerTrump::Card.from_string(str)
31
+ self
32
+ end
33
+
34
+ def equities
35
+ z = deck.each_with_object({}) do |card, a|
36
+ scores = player_hands.each_with_object({}) do |player_hand, h|
37
+ cards = player_hand
38
+ cards = cards.add_cards(flop_cards)
39
+ cards = cards.add_card(turn_card)
40
+ cards = cards.add_card(card)
41
+
42
+ h[cards.score] ||= []
43
+ h[cards.score] << player_hand
44
+ end
45
+
46
+ a[card] = {}
47
+ if scores.keys.size == 1
48
+ a[card][:tie_hands] = player_hands
49
+ else
50
+ mk = scores.keys.max
51
+ a[card][:win_hands] = scores[mk]
52
+ a[card][:lose_hands] = scores.each_with_object([]) do |(k,v), a|
53
+ next if k == mk
54
+
55
+ a.concat(v)
56
+ end
57
+ end
58
+ end
59
+
60
+ s = z.size.to_f
61
+
62
+ player_hands.each_with_object({}) do |player_hand, h|
63
+ win_hands = z.select { |a,b| b[:win_hands]&.include?(player_hand) }
64
+ win_rate = win_hands.size / s
65
+ h[player_hand] = {}
66
+ h[player_hand][:win_rate] = win_rate
67
+ h[player_hand][:lose_rate] = z.count { |a,b| b[:lose_hands]&.include?(player_hand) } / s
68
+ h[player_hand][:tie_rate] = z.count { |a,b| b[:tie_hands]&.include?(player_hand) } / s
69
+ h[player_hand][:outs] = win_hands.keys if win_rate < 0.5
70
+ end
71
+ end
72
+
73
+ def flop_equities
74
+ z = deck.combination(2).each_with_object({}) do |cs, a|
75
+ scores = player_hands.each_with_object({}) do |player_hand, h|
76
+ cards = player_hand
77
+ cards = cards.add_cards(flop_cards)
78
+
79
+ cs.each { |c| cards = cards.add_card(c) }
80
+
81
+ h[cards.score] ||= []
82
+ h[cards.score] << player_hand
83
+ end
84
+
85
+ a[cs] = {}
86
+ if scores.keys.size == 1
87
+ a[cs][:tie_hands] = player_hands
88
+ else
89
+ mk = scores.keys.max
90
+ a[cs][:win_hands] = scores[mk]
91
+ a[cs][:lose_hands] = scores.each_with_object([]) do |(k,v), a|
92
+ next if k == mk
93
+
94
+ a.concat(v)
95
+ end
96
+ end
97
+ end
98
+
99
+ s = z.size.to_f
100
+
101
+ player_hands.each_with_object({}) do |player_hand, h|
102
+ win_hands = z.select { |a,b| b[:win_hands]&.include?(player_hand) }
103
+ win_rate = win_hands.size / s
104
+ h[player_hand] = {}
105
+ h[player_hand][:win_rate] = win_rate
106
+ h[player_hand][:lose_rate] = z.count { |a,b| b[:lose_hands]&.include?(player_hand) } / s
107
+ h[player_hand][:tie_rate] = z.count { |a,b| b[:tie_hands]&.include?(player_hand) } / s
108
+ h[player_hand][:outs] = win_hands.keys if win_rate < 0.5
109
+ end
110
+ end
111
+
112
+ def preflop_equities
113
+ ran = deck.combination(5).to_a
114
+ z = 10000.times.with_object({}) do |i, a|
115
+ cs = ran.sample
116
+ scores = player_hands.each_with_object({}) do |player_hand, h|
117
+ cards = player_hand
118
+
119
+ cs.each { |c| cards = cards.add_card(c) }
120
+
121
+ h[cards.score] ||= []
122
+ h[cards.score] << player_hand
123
+ end
124
+
125
+ a[cs] = {}
126
+ if scores.keys.size == 1
127
+ a[cs][:tie_hands] = player_hands
128
+ else
129
+ mk = scores.keys.max
130
+ a[cs][:win_hands] = scores[mk]
131
+ a[cs][:lose_hands] = scores.each_with_object([]) do |(k,v), a|
132
+ next if k == mk
133
+
134
+ a.concat(v)
135
+ end
136
+ end
137
+ end
138
+
139
+ s = z.size.to_f
140
+
141
+ player_hands.each_with_object({}) do |player_hand, h|
142
+ win_hands = z.select { |a,b| b[:win_hands]&.include?(player_hand) }
143
+ win_rate = win_hands.size / s
144
+ h[player_hand] = {}
145
+ h[player_hand][:win_rate] = win_rate
146
+ h[player_hand][:lose_rate] = z.count { |a,b| b[:lose_hands]&.include?(player_hand) } / s
147
+ h[player_hand][:tie_rate] = z.count { |a,b| b[:tie_hands]&.include?(player_hand) } / s
148
+ h[player_hand][:outs] = win_hands.keys if win_rate < 0.5
149
+ end
150
+ end
151
+
152
+ def deck
153
+ cards = PokerTrump::Cards.new_deck
154
+ cards.delete_cards!(expose_cards) unless expose_cards.size == 0
155
+ player_hands.each do |player_hand|
156
+ cards.delete_cards!(player_hand)
157
+ end
158
+ cards.delete_cards!(flop_cards) unless flop_cards.size == 0
159
+ cards.delete_card!(turn_card) if !!turn_card
160
+ cards.delete_card!(river_card) if !!river_card
161
+
162
+ cards
163
+ end
164
+ end
165
+ end
@@ -1,3 +1,3 @@
1
1
  module PokerOdds
2
- VERSION = "0.1.3"
2
+ VERSION = "0.1.4"
3
3
  end
data/lib/poker_odds.rb CHANGED
@@ -1,9 +1,8 @@
1
- require 'hashie'
2
- require 'active_support/all'
1
+ require 'virtus'
2
+ require 'poker_trump'
3
+
3
4
  require_relative "poker_odds/version"
4
- require_relative 'poker_odds/card'
5
- require_relative 'poker_odds/cards'
6
- require_relative 'poker_odds/round'
5
+ require_relative 'poker_odds/hand'
7
6
 
8
7
  module PokerOdds
9
8
  class Error < StandardError; end
data/poker_odds.gemspec CHANGED
@@ -40,6 +40,7 @@ Gem::Specification.new do |spec|
40
40
  spec.add_development_dependency "rake"
41
41
  spec.add_development_dependency "rspec"
42
42
  spec.add_development_dependency "pry"
43
- spec.add_dependency "hashie"
44
- spec.add_dependency 'activesupport'
43
+
44
+ spec.add_dependency 'virtus'
45
+ spec.add_dependency 'poker_trump'
45
46
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: poker_odds
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - kyohah
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-07-07 00:00:00.000000000 Z
11
+ date: 2022-07-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -67,7 +67,7 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: hashie
70
+ name: virtus
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - ">="
@@ -81,7 +81,7 @@ dependencies:
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
- name: activesupport
84
+ name: poker_trump
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - ">="
@@ -112,9 +112,7 @@ files:
112
112
  - bin/console
113
113
  - bin/setup
114
114
  - lib/poker_odds.rb
115
- - lib/poker_odds/card.rb
116
- - lib/poker_odds/cards.rb
117
- - lib/poker_odds/round.rb
115
+ - lib/poker_odds/hand.rb
118
116
  - lib/poker_odds/version.rb
119
117
  - poker_odds.gemspec
120
118
  homepage: https://github.com/kyohah/poker_odds
@@ -1,39 +0,0 @@
1
- module PokerOdds
2
- class Card < Hash
3
- include Hashie::Extensions::Coercion
4
- include Hashie::Extensions::MergeInitializer
5
- include Hashie::Extensions::MethodAccess
6
-
7
- RANKS = %w[A 2 3 4 5 6 7 8 9 T J Q K].freeze
8
- SUITS = %i[s h d c].freeze
9
-
10
- RANK_VALUE = {
11
- '2' => 2,
12
- '3' => 3,
13
- '4' => 4,
14
- '5' => 5,
15
- '6' => 6,
16
- '7' => 7,
17
- '8' => 8,
18
- '9' => 9,
19
- 'T' => 10,
20
- 'J' => 11,
21
- 'Q' => 12,
22
- 'K' => 13,
23
- 'A' => 14
24
- }
25
-
26
- coerce_key :rank, String
27
- coerce_key :suit, Symbol
28
-
29
- class << self
30
- def string_parse(string)
31
- Card.new(rank: string[0], suit: string[1])
32
- end
33
- end
34
-
35
- def rank_value
36
- RANK_VALUE[rank]
37
- end
38
- end
39
- end
@@ -1,232 +0,0 @@
1
- module PokerOdds
2
- class Cards < Array
3
- include Comparable
4
- DeleteError = Class.new(StandardError)
5
-
6
- STRAIGHT_PATTERNS = (6..14).to_a.reverse.map { |i| (0..4).map {|j| i - j } }.push([5,4,3,2,14]).map { |a| /#{a[0]}.+#{a[1]}.+#{a[2]}.+#{a[3]}.+#{a[4]}/ }.freeze
7
-
8
- class << self
9
- def new_deck
10
- new(Card::RANKS.flat_map do |rank|
11
- Card::SUITS.map do |suit|
12
- Card.new(suit: suit, rank: rank)
13
- end
14
- end)
15
- end
16
-
17
- def string_parse(string)
18
- a = string.split.map do |s|
19
- Card.new(rank: s[0], suit: s[1])
20
- end
21
-
22
- new(a)
23
- end
24
-
25
- def json_parse(json)
26
- h = JSON.parse(json)
27
-
28
- b = h.map { |a| Card.new(rank: a['rank'].to_sym, suit: a['suit'].to_sym) }
29
-
30
- Hands.new(b)
31
- end
32
- end
33
-
34
- def delete_card!(card)
35
- i = index(card)
36
- raise DeleteError if i.nil?
37
-
38
- delete_at(i)
39
- self
40
- end
41
-
42
- def delete_card(card)
43
- i = index(card)
44
- raise DeleteError if i.nil?
45
-
46
- clone_cards = clone
47
- clone_cards.delete_at(i)
48
-
49
- clone_cards
50
- end
51
-
52
- def delete_cards!(cards)
53
- cards.each { |t| delete_card!(t) }
54
- self
55
- end
56
-
57
- def delete_cards(cards)
58
- clone_cards = clone
59
- cards.each { |t| clone_cards.delete_card!(t) }
60
- clone_cards
61
- end
62
-
63
- def add_card(card)
64
- clone_cards = clone
65
- clone_cards.push(card)
66
- end
67
-
68
- def add_card!(card)
69
- push(card)
70
- end
71
-
72
- def add_cards(cards)
73
- clone_cards = clone
74
-
75
- cards.each { |card| clone_cards.add_card!(card) }
76
- clone_cards
77
- end
78
-
79
- def add_cards!(cards)
80
- cards.each { |card| add_card!(card) }
81
- self
82
- end
83
-
84
- def sort_by_suit
85
- @sort_by_suit ||= self.class.new(sort_by { |card| [card.suit, card.rank_value] }.reverse)
86
- end
87
-
88
- def sort_by_rank
89
- @sort_by_rank ||= self.class.new(sort_by { |card| [card.rank_value, card.suit] }.reverse)
90
- rescue => e
91
- binding.pry
92
- end
93
-
94
- def to_s
95
- map { |c| "#{c.rank}#{c.suit}" }.join(' ')
96
- end
97
-
98
- def to_s_rank_value
99
- map(&:rank_value).join(' ')
100
- end
101
-
102
- def group_by_suit
103
- @group_by_suit ||= group_by(&:suit).each_with_object({}) { |(k, v), h| h[k] = self.class.new(v).sort_by_rank }
104
- end
105
-
106
- def royal_flush_rate
107
- [10, 0,0,0,0,0] if /A(.) K\1 Q\1 J\1 T\1/.match?(sort_by_suit.to_s)
108
- end
109
-
110
- def straight_flush_rate
111
- group_by_suit.each do |k, v|
112
- next if v.size < 5
113
-
114
- a = v.straight_rate
115
- if a
116
- return [9, a[1], a[2], a[3], a[4], a[5]]
117
- end
118
- end
119
- nil
120
- end
121
-
122
- def four_of_a_kind_rate
123
- a = sort_by_rank.to_s.match(/(.). \1. \1. \1./)
124
-
125
- if a
126
- b = (a.pre_match + a.post_match).match(/(\S)/).to_s
127
-
128
- [8, PokerOdds::Card::RANK_VALUE[a[1]], PokerOdds::Card::RANK_VALUE[b.to_s], 0, 0,0]
129
- end
130
- end
131
-
132
- def full_house_rate
133
- case sort_by_rank.to_s
134
- when /(.). \1. \1. (.*)(.). \3./
135
- [7, PokerOdds::Card::RANK_VALUE[$1], PokerOdds::Card::RANK_VALUE[$3], 0, 0,0]
136
- when /((.). \2.) (.*)((.). \5. \5.)/
137
- [7, PokerOdds::Card::RANK_VALUE[$5], PokerOdds::Card::RANK_VALUE[$2], 0, 0,0]
138
- else
139
- nil
140
- end
141
- end
142
-
143
- def flush_rate
144
- group_by_suit.each do |k, v|
145
- next if v.size < 5
146
-
147
- return [6, v[0].rank_value, v[1].rank_value, v[2].rank_value, v[3].rank_value, v[4].rank_value]
148
- end
149
-
150
- nil
151
- end
152
-
153
- def straight_rate
154
- a = sort_by_rank.to_s.match(/(?<_A>A.+K.+Q.+J.+T)|(?<_K>K.+Q.+J.+T.+9)|(?<_Q>Q.+J.+T.+9.+8)|(?<_J>J.+T.+9.+8.+7)|(?<_T>T.+9.+8.+7.+6)|(?<_9>9.+8.+7.+6.+5)|(?<_8>8.+7.+6.+5.+4)|(?<_7>7.+6.+5.+4.+3)|(?<_6>6.+5.+4.+3.+2)|(?<_5>A.+5.+4.+3.+2)/)
155
- if a
156
- case k
157
- when :_A
158
- [5, *PokerOdds::Card::RANK_VALUE.values_at('A', 'K', 'Q','J', 'T')]
159
- when :_K
160
- [5, *PokerOdds::Card::RANK_VALUE.values_at('K', 'Q', 'J','T', '9')]
161
- when :_Q
162
- [5, *PokerOdds::Card::RANK_VALUE.values_at('Q', 'J', 'T','9', '8')]
163
- when :_J
164
- [5, *PokerOdds::Card::RANK_VALUE.values_at('J', 'T', '9','8', '7')]
165
- when :_T
166
- [5, *PokerOdds::Card::RANK_VALUE.values_at('T', '9', '8','7', '6')]
167
- when :_9
168
- [5, *PokerOdds::Card::RANK_VALUE.values_at('9', '8', '7','6', '5')]
169
- when :_8
170
- [5, *PokerOdds::Card::RANK_VALUE.values_at('8', '7', '6','5', '4')]
171
- when :_7
172
- [5, *PokerOdds::Card::RANK_VALUE.values_at('7', '6', '5','4', '3')]
173
- when :_6
174
- [5, *PokerOdds::Card::RANK_VALUE.values_at('6', '5', '4','3', '2')]
175
- when :_5
176
- [5, *PokerOdds::Card::RANK_VALUE.values_at('5', '4', '3','2', 'A')]
177
- end
178
- else
179
- nil
180
- end
181
- end
182
-
183
- def three_of_a_kind_rate
184
- md = sort_by_rank.to_s.match(/(.). \1. \1./)
185
-
186
- if md
187
- arranged_hand = (md.pre_match + md.post_match).strip.squeeze(" ")
188
-
189
- [4, PokerOdds::Card::RANK_VALUE[md[1]], PokerOdds::Card::RANK_VALUE[arranged_hand[0]], PokerOdds::Card::RANK_VALUE[arranged_hand[3]], 0, 0]
190
- else
191
- nil
192
- end
193
- end
194
-
195
- def two_pair_rate
196
- md = sort_by_rank.to_s.match(/(.). \1.(.*?) (.). \3./)
197
-
198
- if md
199
- arranged_hand = (md.pre_match + ' ' + md[2] + ' ' + md.post_match).strip.squeeze(" ")
200
- [3, PokerOdds::Card::RANK_VALUE[md[1]], PokerOdds::Card::RANK_VALUE[md[3]], PokerOdds::Card::RANK_VALUE[arranged_hand[0]], 0, 0]
201
- else
202
- nil
203
- end
204
- end
205
-
206
- def one_pair_rate
207
- md = sort_by_rank.to_s.match(/(.). \1./)
208
-
209
- if md
210
- arranged_hand = (md.pre_match + ' ' + md.post_match).strip.squeeze(" ")
211
-
212
- [2, PokerOdds::Card::RANK_VALUE[md[1]], PokerOdds::Card::RANK_VALUE[arranged_hand[0]], PokerOdds::Card::RANK_VALUE[arranged_hand[3]], PokerOdds::Card::RANK_VALUE[arranged_hand[6]], 0]
213
- else
214
- nil
215
- end
216
- end
217
-
218
- def high_card_rate
219
- arranged_hand = sort_by_rank.to_s
220
-
221
- [1, PokerOdds::Card::RANK_VALUE[arranged_hand[0]], PokerOdds::Card::RANK_VALUE[arranged_hand[3]], PokerOdds::Card::RANK_VALUE[arranged_hand[6]], PokerOdds::Card::RANK_VALUE[arranged_hand[9]], PokerOdds::Card::RANK_VALUE[arranged_hand[12]]]
222
- end
223
-
224
- def score
225
- @score ||= royal_flush_rate || straight_flush_rate || four_of_a_kind_rate || full_house_rate || flush_rate || straight_flush_rate || three_of_a_kind_rate || two_pair_rate || one_pair_rate || high_card_rate
226
- end
227
-
228
- def <=>(other_cards)
229
- score <=> other_cards.score
230
- end
231
- end
232
- end
@@ -1,107 +0,0 @@
1
- module PokerOdds
2
- class Round < Hash
3
- include Hashie::Extensions::Coercion
4
- include Hashie::Extensions::MergeInitializer
5
- include Hashie::Extensions::MethodAccess
6
-
7
- coerce_key :hands, Array
8
- coerce_key :flop_cards, PokerOdds::Cards
9
- coerce_key :turn_card, PokerOdds::Card
10
- coerce_key :river_card, PokerOdds::Card
11
-
12
- coerce_key :expose_cards, PokerOdds::Cards
13
-
14
- # class << self
15
- # def flop =(h)
16
-
17
- # end
18
- # end
19
-
20
- def initialize(**arg)
21
- self.flop=arg[:flop] if arg[:flop]
22
- self.turn=arg[:turn] if arg[:turn]
23
- self.river=arg[:river] if arg[:river]
24
-
25
- self[:hands] ||= []
26
- self[:expose_cards] ||= PokerOdds::Cards.new
27
- self[:flop_cards] ||= PokerOdds::Cards.new
28
- self[:turn_card] ||= PokerOdds::Card.new
29
- self[:river_card] ||= PokerOdds::Card.new
30
- end
31
-
32
- def add_hand(s)
33
- self[:hands] << PokerOdds::Cards.string_parse(s)
34
- self
35
- end
36
-
37
- def flop=(s)
38
- self[:flop_cards] = PokerOdds::Cards.string_parse(s)
39
- self
40
- end
41
-
42
- def turn=(s)
43
- self[:turn_card] = PokerOdds::Card.string_parse(s)
44
- self
45
- end
46
-
47
- def river=(s)
48
- self[:river_cards] = PokerOdds::Card.string_parse(s)
49
- self
50
- end
51
-
52
- def equities
53
- z = deck.each_with_object({}) do |card, a|
54
- scores = hands.each_with_object({}) do |hand, h|
55
- cards = hand
56
- cards = cards.add_cards(flop_cards)
57
- cards = cards.add_card(turn_card)
58
- cards = cards.add_card(card)
59
-
60
- if h[cards.score].present?
61
- h[cards.score] << hand
62
- else
63
- h[cards.score] = [hand]
64
- end
65
- end
66
-
67
- a[card] = {}
68
- if scores.keys.size == 1
69
- a[card][:tie_hands] = hands
70
- else
71
- mk = scores.keys.max
72
- a[card][:win_hands] = scores[mk]
73
- a[card][:lose_hands] = scores.each_with_object([]) do |(k,v), a|
74
- next if k == mk
75
-
76
- a.concat(v)
77
- end
78
- end
79
- end
80
-
81
- s = z.size.to_f
82
-
83
- hands.each_with_object({}) do |hand, h|
84
- win_hands = z.select { |a,b| b[:win_hands]&.include?(hand) }
85
- win_rate = win_hands.size / s
86
- h[hand] = {}
87
- h[hand][:win_rate] = win_rate
88
- h[hand][:lose_rate] = z.count { |a,b| b[:lose_hands]&.include?(hand) } / s
89
- h[hand][:tie_rate] = z.count { |a,b| b[:tie_hands]&.include?(hand) } / s
90
- h[hand][:outs] = win_hands.keys if win_rate < 0.5
91
- end
92
- end
93
-
94
- def deck
95
- cards = Cards.new_deck
96
- cards.delete_cards!(expose_cards) if expose_cards
97
- hands.each do |hand|
98
- cards.delete_cards!(hand)
99
- end
100
- cards.delete_cards!(flop_cards) if flop_cards.present?
101
- cards.delete_card!(turn_card) if turn_card.present?
102
- cards.delete_card!(river_card) if river_card.present?
103
-
104
- cards
105
- end
106
- end
107
- end