-
Notifications
You must be signed in to change notification settings - Fork 0
/
pokerbot.py
335 lines (296 loc) · 17.2 KB
/
pokerbot.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
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
#!/usr/bin/env python
# -*- coding=utf-8 -*-
from LalBot.lalbot import LalBot
from PokerRoom.pokerroom import PokerRoom
from pprint import pprint
import time
import datetime
import threading
from whitelist import WHITELIST
WEEKDAYS = ['Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday']
class PokerBot(LalBot):
versionstr = 'v1.6.0'
welcome_message = u'Internet Relay Poker {}. Type "poker: help" for more information.'.format(versionstr)
player_whitelist = WHITELIST
_currency = u'Ł'#u'$'
_action_timeout = 1800
def setup(self):
self.hand_running = False
self.allow_hand = True
self.room = PokerRoom()
self.join_wait = []
self.leave_wait = []
new_commands = {'demo':self.demo_cardnames,
'join':self.add_player,
'leave':self.remove_player,
'rules':self.print_rules,
'cards':self.tell_cards,
'stacks':self.tell_stacks,
'stack db':self.tell_stack_db,
'pots':self.tell_sidepots,
'action':self.remind_action,
'challenge (.+)':self.challenge,
'board':self.tell_boardcards,
'rebuy':self.rebuy,
'show my hand':self.show_hand,
#'dbg_newhand':self.run_hand,
'bar me':self.bar_player,
'(fold|fold and show|check|call|bet|raise by|raise to|jam|shove|all in)(?: (\d+))?\s{0,}$':self.advance_action,
}
self.commandlist.update(new_commands)
self.action_timer = time.time() + self._action_timeout
@property
def helpfile(self):
try:
n = self.connection.get_nickname()
except AttributeError as err:
n = 'poker'
helpfile = [u'''PokerBot {}'''.format(self.versionstr),
u'''Type "{}: join" to join the table.'''.format(n),
u'''Type "{}: leave" to leave the table.'''.format(n),
u'''Type "{}: bar me" to ban yourself from the table (permamently!) if you have work to do.'''.format(n),
u'''Type "{}: rules" to show rules.'''.format(n),
u'''Type "{}: cards" for a reminder of your cards.'''.format(n),
u'''Type "{}: board" for a reminder of the board cards.'''.format(n),
u'''Type "{}: pots" to show who has a stake in which pot, and how much.'''.format(n),
u'''Type "{}: stacks" to see the players and stacks.'''.format(n),
u'''Type "{}: stack db" to see the whole stack database.'''.format(n),
u'''Type "{}: action" to prod the person whose turn it is.'''.format(n),
u'''Type "{}: challenge" to challenge a player to a game!'''.format(n),
u'''If you are out of chips, type "{}: rebuy" to get a new stack.'''.format(n.format(n)),
u'''Type "{}: fold/check/call/shove/jam/all in" to take the appropriate action.'''.format(n),
u'''Type "{}: bet [x]/raise by [x]/raise to [x]" to make the appropriate bet.'''.format(n),
u'''Type "{}: show my hand" to show other people your hand.'''.format(n),
u'''Typing "{}: fold and show" will show your hand before folding.'''.format(n),
u'''Good luck!''',
]
return helpfile
@property
def rulesfile(self):
rulesfile = [u'''Texas Hold 'Em Poker is played at this table.''',
u'''Blinds on {} are {}{} and {}{} with no Ante.'''.format(WEEKDAYS[datetime.date.weekday(datetime.date.today())],
self._currency,self.room.SMALL_BLIND,self._currency,self.room.SMALL_BLIND*2),
u'''Buyins are {}10000.'''.format(self._currency),
u'''Rebuying is allowed once per day.'''.format(self._currency),
u'''Visit http://en.wikipedia.org/wiki/Texas_hold_'em#Rules for an in-depth look at the rules.''',
u'''Visit http://en.wikipedia.org/wiki/List_of_poker_hands for a list of the possible hands you can make.''',
u'''Straight Flush > Quads > Full House > Flush > Straight > Trips > Two Pair > One Pair > High Card.''',
]
return rulesfile
def add_player(self,source='',resp_dst='',*pargs):
if source in self.player_whitelist:
if self.room.hand_running:
self.join_wait.append(source)
self.queue_message(u'Player {} joined the table; will play next hand.'.format(source))
else:
if self.room.add_player(source):
self.queue_message(u'Player {} joined the table.'.format(source))
else:
self.queue_message(u'You are already at the table, {}.'.format(source),False,resp_dst)
else:
self.queue_message(u'Sorry, {}, but you are barred from this table.'.format(source),False,resp_dst)
def remove_player(self,source='',resp_dst='',*pargs):
if self.room.hand_running:
self.leave_wait.append(source)
self.queue_message(u'Player {} left the table; will be out next hand.'.format(source))
else:
if self.room.remove_player(source):
self.queue_message(u'Player {} left the table.'.format(source))
else:
self.queue_message(u'Thanks, {}.'.format(source),False,resp_dst)
def bar_player(self,source='',resp_dst='',*pargs):
if source in self.player_whitelist:
self.player_whitelist.remove(source)
self.queue_message('Good work, {}.'.format(source),False,resp_dst)
self.remove_player(source)
def change_out_table(self,source='',resp_dst='',*pargs):
if self.room.hand_running:
return
else:
for player in self.join_wait:
self.add_player(player)
self.join_wait = []
for player in self.leave_wait:
self.remove_player(player)
self.leave_wait = []
self.check_busts()
def check_busts(self,source='',resp_dst='',*pargs):
if not self.room.hand_running:
for player in self.room.players:
if player['chips'] <= 0:
self.queue_message(u'{} is busted!'.format(player['name']))
self.room.players = [p for p in self.room.players[:] if p['chips'] > 0]
def rebuy(self,source,resp_dst='',*pargs):
if self.room.rebuy_chips(source):
self.add_player(source)
else:
self.queue_message(u'You cannot rebuy right now, {}.'.format(source),False,resp_dst)
def print_rules(self,source='',resp_dst='',*pargs):
if source == resp_dst:
self.queue_message('Listing Rules in private message...',False,self.main_channel_name)
for message in self.rulesfile:
self.queue_message(message,True,resp_dst)
def challenge(self,source,resp_dst='',*pargs):
self.queue_message(u'{} has challenged you, {}!'.format(source,pargs[0]))
def show_hand(self,source,resp_dst='',*pargs):
if source in self.room.cards:
cards = self.room.cards[source]
self.queue_message(u'{} shows: {}{}'.format(source,self.room.CARDNAMES[cards[0]],self.room.CARDNAMES[cards[1]]), important=True, channel=self.main_channel_name)
def demo_cardnames(self,source='',resp_dst='',*pargs):
if source == 'lutomlin':
self.queue_message(''.join(n for n in self.room.CARDNAMES[0:8]))
def tell_cards(self,source='',resp_dst='',*pargs):
cards = self.room.cards.get(source,None)
if cards:
self.queue_message(u'Your cards are: {}{}'.format(self.room.CARDNAMES[cards[0]],self.room.CARDNAMES[cards[1]]), important=True, channel=source)
else:
self.queue_message(u'You have no cards!',False,resp_dst)
def tell_all_cards(self,source='',resp_dst='',*pargs):
for player in self.room.players:
cards = self.room.cards.get(player['name'],None)
if cards:
self.queue_message(u'Your cards are: {}{}'.format(self.room.CARDNAMES[cards[0]],self.room.CARDNAMES[cards[1]]), important=True, channel=player['name'])
else:
self.queue_message(u'You have no cards!', important=False, channel=player['name'])
def tell_stacks(self,source='',resp_dst='',*pargs):
pl = [u'{} (Stack: {}{})'.format(p['name'],self._currency,p['chips']) for p in self.room.players]
self.queue_message(u'Players sitting at table (in order): {}'.format(' '.join(pl)),False,resp_dst)
def tell_stack_db(self,source='',resp_dst='',*pargs):
pl = [u'{} (Stack: {}{})'.format(p,self._currency,s['chips']) for p,s in self.room.db_data.iteritems()]
self.queue_message(u'Player stacks: {}'.format(' '.join(pl)),False,resp_dst)
def tell_sidepots(self,source='',resp_dst='',*pargs):
pots = self.room.pots
if self.room.current_pot:
self.queue_message(u'Main pot (before this street) contains {}{}.'.format(self._currency,self.room.current_pot))
else:
self.queue_message(u'Main pot (before this street) is empty!')
pass
if not pots:
#self.queue_message('No side pots to play for.')
pass
for pot in pots:
self.queue_message(u'A sidepot of {}{} contested by {}'.format(self._currency,pot['prize'],', '.join([p['name'] for p in pot['playerlist']])),True)
def remind_action(self,source='',resp_dst='',newboard=False,*pargs):
if self.room.hand_running:
if newboard:
self.queue_message(u'Action is on {}. Main pot is {}{}. Bet is at {}{}. Timer: {}s.'.format(self.room.get_action_player()['name'],
self._currency,self.room.current_pot,
self._currency,self.room.current_bet,
self.get_action_s()))
else:
self.queue_message(u'Action is on {}. Bet is at {}{}. Timer: {}s'.format(self.room.get_action_player()['name'],
self._currency,self.room.current_bet,
self.get_action_s()))
else:
self.queue_message(u'No hand in progress.',False,resp_dst)
def tell_boardcards(self,source='',resp_dst='',*pargs):
self.queue_message(u'Board: {}'.format(''.join([self.room.CARDNAMES[a] for a in self.room.boardcards])),important=True,channel=source)
def tell_all_boardcards(self,source='',resp_dst='',*pargs):
self.tell_boardcards(source=self.main_channel_name)#self.queue_message(u'Board: {}'.format(' '.join([self.room.CARDNAMES[a] for a in self.room.boardcards])),important=True)
for player in self.room.players:
self.tell_boardcards(source=player['name'])#self.queue_message(u'Board: {}'.format(' '.join([self.room.CARDNAMES[a] for a in self.room.boardcards])),important=True,channel=player['name'])
def advance_action(self,source='',resp_dst='',*pargs):
boardnum = len(self.room.boardcards)
#try:
if pargs[0] == 'fold and show':
self.show_hand(source=source)
success = self.room.advance_action(source, *pargs)
#except Exception as err:
# success = str(err)
if success is True:
self.reset_action_timer()
if pargs[0] == 'fold':
self.queue_message(u'{} folds.'.format(source))
if pargs[0] == 'fold and show':
self.queue_message(u'{} folds.'.format(source))
if pargs[0] == 'check':
self.queue_message(u'{} checks.'.format(source))
if pargs[0] == 'call':
self.queue_message(u'{} calls.'.format(source))
if pargs[0] == 'bet':
self.queue_message(u'{} bets {}{}.'.format(source,self._currency,pargs[1]))
if pargs[0] == 'raise by':
self.queue_message(u'{} raises another {}{}.'.format(source,self._currency,pargs[1]))
if pargs[0] == 'raise to':
self.queue_message(u'{} raises to {}{}.'.format(source,self._currency,pargs[1]))
if pargs[0] in ['jam','all in','shove']:
self.queue_message(u'{} moves all in!'.format(source))
if self.room.hand_running:
if boardnum != len(self.room.boardcards):
self.tell_all_boardcards()
self.remind_action(newboard=True)
else:
self.remind_action(newboard=False)
else:
self.queue_message(u'Hand complete!')
if self.room.return_cards():
self.tell_boardcards(source=self.main_channel_name)
for player,cards in self.room.return_cards().iteritems():
self.queue_message(u'{} shows {}'.format(player,''.join(self.room.CARDNAMES[card] for card in cards)))
for pot in self.room.return_pot_winners():
self.queue_message(u'Pot of {}{} won by {}'.format(self._currency,pot[0],', '.join(pot[1])))
else:
### Sweet, sweet haxarounds
if success == u"Can't raise with no previous bet!":
self.advance_action(source,resp_dst,'bet',pargs[1])
elif success in (u'No bet to call.',u'Bet is already matched!'):
self.advance_action(source,resp_dst,'check')
else:
self.queue_message(u'Not a valid action! {}'.format(success.format(self._currency)),False,resp_dst) ###SMRT!
def run_hand(self,source='',resp_dst='',*pargs):
self.room.hand_running = True
self.room.next_hand()
self.room.deal_cards()
print u'start of new hand'
pprint(self.room.players)
self.tell_stacks()
dl, sb, bb = self.room.post_blinds()
self.queue_message(u'{} is dealer, {} is small blind for {}{}, {} is big blind for {}{}'.format(dl,
sb,self._currency,self.room.SMALL_BLIND,
bb,self._currency,self.room.SMALL_BLIND*2))
self.tell_all_cards()
self.reset_action_timer()
self.remind_action()
def loop_thread(self):
while True:
if len(self.room.players) > 1 and not self.room.hand_running and self.allow_hand:
self.change_out_table()
if len(self.room.players) > 1:
self.queue_message(u'Next hand in 10...')
time.sleep(10)
self.check_busts()
if len(self.room.players) > 1:
self.run_hand()
else:
self.queue_message(u'Hand aborted - too few players.')
else:
self.queue_message(u'Table suspended - too few players.')
elif self.room.hand_running and self.get_action_s() < 0 and self.room.get_action_player():
self.queue_message(u'Player {} has not acted in {}s - folding their hand and kicking them from table...'.format(self.room.get_action_player()['name'],
self._action_timeout))
self.remove_player(self.room.get_action_player()['name'])
self.advance_action(self.room.get_action_player()['name'],'','fold')
self.reset_action_timer() ### Can get into loop if advance_action() is wrong for some reason
else:
#self.room.nudge() ### This probably isn't how you're meant to do it ### Not used :)
time.sleep(1)
def prevent_hand(self):
self.queue_message(u'Closing table at the end of this hand for a reboot...')
self.allow_hand = False
def reset_action_timer(self):
self.action_timer = time.time() + self._action_timeout
def get_action_s(self):
return int(self.action_timer - time.time())
def main():
import sys
if len(sys.argv) <= 1:
print "Usage: 'python -i lalbot.py <channel> [<nickname> [<server> [<port>]]]'"
print "bot=self, c=self.connection"
sys.exit(1)
bot = PokerBot(*sys.argv[1:])
thread = threading.Thread(target=bot.start)
thread.daemon = True
thread.start()
return bot
if __name__ == "__main__":
bot = main()