poker_odds 0.1.1 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +6 -14
- data/lib/poker_odds/hand.rb +165 -0
- data/lib/poker_odds/version.rb +1 -1
- data/lib/poker_odds.rb +4 -5
- data/poker_odds.gemspec +3 -2
- metadata +9 -11
- data/lib/poker_odds/card.rb +0 -39
- data/lib/poker_odds/cards.rb +0 -232
- data/lib/poker_odds/round.rb +0 -108
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f204234da42a8bd00fd9d1407dc188a9ea79856591b1bedb2e9c7d2d9c22cb34
|
4
|
+
data.tar.gz: b0884f1224a3e5655b92b3d602551c42fd42a89d9d0779d4331da8585c03f767
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
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::
|
27
|
-
round.
|
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
|
-
|
33
|
-
|
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
|
data/lib/poker_odds/version.rb
CHANGED
data/lib/poker_odds.rb
CHANGED
@@ -1,9 +1,8 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
1
|
+
require 'virtus'
|
2
|
+
require 'poker_trump'
|
3
|
+
|
3
4
|
require_relative "poker_odds/version"
|
4
|
-
require_relative 'poker_odds/
|
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
|
-
|
44
|
-
spec.add_dependency '
|
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.
|
4
|
+
version: 0.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- kyohah
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-07-
|
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:
|
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:
|
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/
|
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
|
@@ -123,7 +121,7 @@ licenses:
|
|
123
121
|
metadata:
|
124
122
|
homepage_uri: https://github.com/kyohah/poker_odds
|
125
123
|
source_code_uri: https://github.com/kyohah/poker_odds
|
126
|
-
post_install_message:
|
124
|
+
post_install_message:
|
127
125
|
rdoc_options: []
|
128
126
|
require_paths:
|
129
127
|
- lib
|
@@ -138,8 +136,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
138
136
|
- !ruby/object:Gem::Version
|
139
137
|
version: '0'
|
140
138
|
requirements: []
|
141
|
-
rubygems_version: 3.
|
142
|
-
signing_key:
|
139
|
+
rubygems_version: 3.2.32
|
140
|
+
signing_key:
|
143
141
|
specification_version: 4
|
144
142
|
summary: Write a short summary, because RubyGems requires one.
|
145
143
|
test_files: []
|
data/lib/poker_odds/card.rb
DELETED
@@ -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
|
data/lib/poker_odds/cards.rb
DELETED
@@ -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
|
data/lib/poker_odds/round.rb
DELETED
@@ -1,108 +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 = {}
|
87
|
-
h[:hand] = hand
|
88
|
-
h[:win_rate] = win_rate
|
89
|
-
h[:lose_rate] = z.count { |a,b| b[:lose_hands]&.include?(hand) } / s
|
90
|
-
h[:tie_rate] = z.count { |a,b| b[:tie_hands]&.include?(hand) } / s
|
91
|
-
h[:outs] = win_hands.keys if win_rate > 0.5
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
def deck
|
96
|
-
cards = Cards.new_deck
|
97
|
-
cards.delete_cards!(expose_cards) if expose_cards
|
98
|
-
hands.each do |hand|
|
99
|
-
cards.delete_cards!(hand)
|
100
|
-
end
|
101
|
-
cards.delete_cards!(flop_cards) if flop_cards.present?
|
102
|
-
cards.delete_card!(turn_card) if turn_card.present?
|
103
|
-
cards.delete_card!(river_card) if river_card.present?
|
104
|
-
|
105
|
-
cards
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|