-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathStrength_HMM.py
227 lines (193 loc) · 8.56 KB
/
Strength_HMM.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
#-------------------------------------------------------------------------------
# Name: Strength_HMM.py
# Purpose: Uses HMM to estimate the strength of opponent's hole cards.
#-------------------------------------------------------------------------------
import numpy as np
import random
import copy
# Hidden states of opponent's hole cards.
states = ('Low', 'Medium','High')
# Observations of opponent's betting actions
observations = ('call,L', 'call,M', 'call,H','Raise,L','Raise,M','Raise,H')
# Prior probabilities of each state
start_probability = {'Low': 1.0/3, 'Medium':1.0/3,'High':1.0/3 }
# The transition probabilities of card strength states change.
transition_probability = {
'Low' : {'Low': 0.5, 'Medium':1.0/3,'High':1.0/6},
'Medium' : {'Low': 1.0/3, 'Medium': 1.0/3,'High':1.0/3},
'High':{'Low': 1.0/6, 'Medium':1.0/3,'High':0.5}
}
# Emission probabilities base count.
emission_probability_base = {
'Low' : {'call,L':50, 'call,M':12, 'call,H':8,'Raise,L':15,'Raise,M':10,'Raise,H':5},
'Medium' : {'call,L':15, 'call,M':20, 'call,H':15,'Raise,L':15,'Raise,M':20,'Raise,H':25},
'High':{'call,L':5, 'call,M':10, 'call,H':15,'Raise,L':15,'Raise,M':30,'Raise,H':25}
}
emission_probability = {
'Low' : {'call,L':0.50, 'call,M':0.12, 'call,H':0.08,'Raise,L':0.15,'Raise,M':0.10,'Raise,H':0.05},
'Medium' : {'call,L':0.15, 'call,M':0.20, 'call,H':0.15,'Raise,L':0.15,'Raise,M':0.20,'Raise,H':0.25},
'High':{'call,L':0.05, 'call,M':0.10, 'call,H':0.15,'Raise,L':0.15,'Raise,M':0.30,'Raise,H':0.25}
}
# Viterbi to determine the most possible state of opponent's hole cards.
def viterbi(obs, states, start_p, trans_p, emit_p):
'''
obs: observation sequence
states = ('Low', 'Medium','High')
start_p = start_probability
trans_p = transition_probability
emit_p = emission_probability, but it will advance along with the game going.
return the most possible state sequence and the according probabilities.
'''
V = [{}]
path = {}
# Initialize base cases (t == 0)
for y in states:
V[0][y] = start_p[y] * emit_p[y][obs[0]]
path[y] = [y]
# Run Viterbi for t > 0
t=0
for t in range(1, len(obs)):
V.append({})
newpath = {}
for y in states:
(prob, state) = max((V[t-1][y0] * trans_p[y0][y] * emit_p[y][obs[t]], y0) for y0 in states)
V[t][y] = prob
newpath[y] = path[state] + [y]
# Don't need to remember the old paths
path = newpath
#print_dptable(V)
(prob, state) = max((V[t][y], y) for y in states)
return (prob, path[state])
# Updtate the emission_probability through updating emission_probability_base
def update_emission_prob(Hist_Record,ebase=copy.deepcopy(emission_probability_base),e_prob=emission_probability):
'''
Hist_Record: player's bet history
ebase: copy from emission_probability_base and update from it.
'''
# No need to update if only one history
if len(Hist_Record)==1:
return emission_probability
# Update emission_probability_base based on the player's bet history. Count each case.
for i in range(len(Hist_Record)-1):
if Hist_Record[i]==[]:
continue
for j in range(len(Hist_Record[i])):
if Hist_Record[i][j]==[]:
continue
for each_record in Hist_Record[i][j]:
if each_record[0]=='K':
if each_record[1]<1.0/3:
ebase['Low']['call,L']+=1
elif each_record[1]<2.0/3:
ebase['Medium']['call,L']+=1
else:
ebase['High']['call,L']+=1
elif each_record[0]=='C':
if each_record[1]<1.0/3:
if each_record[2]<1.0/3:
ebase['Low']['call,L']+=1
elif each_record[2]<2.0/3:
ebase['Low']['call,M']+=1
else:
ebase['Low']['call,H']+=1
elif each_record[1]<2.0/3:
if each_record[2]<1.0/3:
ebase['Medium']['call,L']+=1
elif each_record[2]<2.0/3:
ebase['Medium']['call,M']+=1
else:
ebase['Medium']['call,H']+=1
else:
if each_record[2]<1.0/3:
ebase['High']['call,L']+=1
elif each_record[2]<2.0/3:
ebase['High']['call,M']+=1
else:
ebase['High']['call,H']+=1
elif each_record[0]=='R':
if each_record[1]<1.0/3:
if each_record[2]<1.0/3:
ebase['Low']['Raise,L']+=1
elif each_record[2]<2.0/3:
ebase['Low']['Raise,M']+=1
else:
ebase['Low']['Raise,H']+=1
elif each_record[1]<2.0/3:
if each_record[2]<1.0/3:
ebase['Medium']['Raise,L']+=1
elif each_record[2]<2.0/3:
ebase['Medium']['Raise,M']+=1
else:
ebase['Medium']['Raise,H']+=1
else:
if each_record[2]<1.0/3:
ebase['High']['Raise,L']+=1
elif each_record[2]<2.0/3:
ebase['High']['Raise,M']+=1
else:
ebase['High']['Raise,H']+=1
low_total=sum(ebase['Low'].values())
medium_total=sum(ebase['Medium'].values())
high_total=sum(ebase['High'].values())
# compute the new emission probability from the new emission probability base count
emission_probability_new = {
'Low' : {'call,L': float(ebase['Low']['call,L'])/low_total,
'call,M':float(ebase['Low']['call,M'])/low_total,
'call,H':float(ebase['Low']['call,H'])/low_total,
'Raise,L':float(ebase['Low']['Raise,L'])/low_total,
'Raise,M':float(ebase['Low']['Raise,M'])/low_total,
'Raise,H':float(ebase['Low']['Raise,H'])/low_total},
'Medium' : {'call,L': float(ebase['Medium']['call,L'])/medium_total,
'call,M':float(ebase['Medium']['call,M'])/medium_total,
'call,H':float(ebase['Medium']['call,H'])/medium_total,
'Raise,L':float(ebase['Medium']['Raise,L'])/medium_total,
'Raise,M':float(ebase['Medium']['Raise,M'])/medium_total,
'Raise,H':float(ebase['Medium']['Raise,H'])/medium_total},
'High' : {'call,L': float(ebase['Medium']['call,L'])/high_total,
'call,M':float(ebase['High']['call,M'])/high_total,
'call,H':float(ebase['High']['call,H'])/high_total,
'Raise,L':float(ebase['High']['Raise,L'])/high_total,
'Raise,M':float(ebase['High']['Raise,M'])/high_total,
'Raise,H':float(ebase['High']['Raise,H'])/high_total}}
return emission_probability_new
# Extract current observation from history record
def current_obs(Hist_Record):
'''
Hist_Record: player's bet history
return the current observation
'''
cur_obs=[]
current_record=Hist_Record[-1]
for j in range(len(current_record)):
if current_record[j]==[]:
return cur_obs
item=current_record[j][-1]
if item[0]=='K':
cur_obs.append('call,L')
elif item[0]=='C':
if item[2]<1.0/3:
cur_obs.append('call,L')
elif item[2]<2.0/3:
cur_obs.append('call,M')
else:
cur_obs.append('call,H')
elif item[0]=='R':
if item[2]<1.0/3:
cur_obs.append('Raise,L')
elif item[2]<2.0/3:
cur_obs.append('Raise,M')
else:
cur_obs.append('Raise,H')
return cur_obs
# Use HMM to detemine the state of opponent's hole card.
def HMM_state(Hist_Record):
'''
Hist_Record: player's bet history
return the most possible current state
'''
cur_obs=current_obs(Hist_Record)
if cur_obs==[]:
return 'No_State'
emission_prob_new=update_emission_prob(Hist_Record,ebase=copy.deepcopy(emission_probability_base),e_prob=emission_probability)
results=viterbi(cur_obs, states, start_probability, transition_probability, emit_p=emission_prob_new)
return results[1][-1]