-
Notifications
You must be signed in to change notification settings - Fork 0
/
bot_player.py
132 lines (109 loc) · 3.82 KB
/
bot_player.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
import double_or_nothing_util as dnUtil
import sys
import math
class BotPlayer:
def __init__(self):
self.resetBot()
def resetBot(self):
"""Set up the bot for the beginning state of the game"""
self.state = [None, None, None, False]
self.score = 0
counts = {}
for value in dnUtil.valuesList:
counts[value] = self.calcDefaultCount(value)
self.state[2] = counts
def calcDefaultCount(self, value):
"""Returns the default number of cards higher/lower than the
input value.
"""
idx = dnUtil.valuesList.index(value)
higher = (len(dnUtil.valuesList) - idx - 1) * 4
lower = idx * 4
tie = 4
return (higher, lower, tie)
def updateBotCounts(self, nextCard):
"""Update the card count given the next card has been drawn"""
nextVal = dnUtil.getValue(nextCard)
state = self.getState()
counts = self.getCounts(state)
newCount = counts.copy()
for value in dnUtil.valuesList:
if counts[value][2] == 0:
continue
update = self.updateCount(value, nextVal, counts[value])
newCount[value] = update
self.setCounts(newCount)
def updateCount(self, cardVal, nextVal, counts):
"""Update the number of cards higher/lower than the value given
the next card has been drawn."""
higher, lower, tie = counts
comp = dnUtil.compareValue(cardVal, nextVal)
if comp == 0:
tie -= 1
elif comp < 0:
higher -= 1
else:
lower -= 1
return (higher, lower, tie)
def expectancyPcnt(self, p):
"""Simplified trade expectancy formula."""
return (2 * p) - 1
def getAction(self, game, state):
"""Choose an action given the current state."""
if self.getUnknownCard(state) is None:
baseVal = self.getBase(state)
counts = self.getCounts(state)[baseVal]
if counts[0] > counts[1]:
return dnUtil.Action.Higher
elif counts[0] < counts[1]:
return dnUtil.Action.Lower
else:
if dnUtil.random.random() > 50:
return dnUtil.Action.Higher
else:
return dnUtil.Action.Lower
elif self.getLoseBool(state):
return dnUtil.Action.Exit
else:
nextVal = self.getUnknownCard(state)
nextCounts = self.getCounts(state)[nextVal]
deckSize = sum(nextCounts)
high, low, tie = nextCounts
if high > low:
winrate = high / deckSize
elif high < low:
winrate = low / deckSize
else:
winrate = 0.5
risk = game.getRisk()
if self.expectancyPcnt(winrate) > self.expectancyPcnt(risk / 100):
return dnUtil.Action.Continue, winrate * 100
else:
return dnUtil.Action.Exit, winrate * 100
def getState(self):
return self.state
def setState(self, state):
self.state = state
def getScore(self):
return self.score
def setScore(self, score):
self.score = score
def getBase(self, state):
return state[0]
def setBase(self, card):
self.state[0] = dnUtil.getValue(card)
def getUnknownCard(self, state):
return state[1]
def setUnknownCard(self, card):
if card is not None:
self.state[1] = dnUtil.getValue(card)
else:
self.state[1] = None
def getCounts(self, state):
return state[2]
def setCounts(self, counts):
self.state[2] = counts
def setLoseBool(self, lose):
self.state[3] = lose
def getLoseBool(self, state):
return state[3]