The adventures of poker, packets, pipes and Python Roger Barnes
May 19, 2015
The adventures of poker, packets, pipes and
PythonRoger Barnes
I like playing online poker
But I could be better at it
I needed a poker buddy
That's a terrible hand!
All in!
Live Hold'em Poker Pro
Packet capture options
from your (rooted) Android device - wifi or 3G● apps - eg Shark for Root● tcpdump - via shell
Packet capture options
from your router or another device on the network (if promiscuous mode) - wifi only ● tcpdump/libpcap● wireshark/tshark● pcapy● ngrep
Hackable routers
There are many devices and firmwares to choose from (see dd-wrt and tomato-usb)
I have Netgear WNR3500L with Tomato-USB● ssh built in● Additional packages installed using Optware
○ http://tomatousb.org/doc:optware○ Includes python, tshark, ngrep, wget, some build
tools, ...
Initial capture using tshark
tshark -i eth1 -w capture.pcap -f "host 192.168.1.106 and (port 9400 or port 9500)"
Analyse using wireshark - bingo!
IPython Notebookhttp://ipython.org/ipython-doc/dev/interactive/htmlnotebook.html
Parsing game state
More IPython notebook work to figure out sequence of events, card values, player actions etc
Mapping card valuesdef cardmapper(val):
vals = '23456789TJQKA'
suits = 'cdhs'
result = divmod(val, 13)
return vals[result[1]] + suits[result[0]]
print cardmapper(44) # 7s
print cardmapper(21) # Td
print cardmapper(17) # 6d
print cardmapper(51) # As
print cardmapper(7) # 9c
print cardmapper(0) # 2c
Getting live capture data
● tshark?● pcapy?● ngrep?
Too hardMaybeProbably
Getting live capture data into Python
● Install pcapy on router?● zmq on router?● SSH and pipe?
Too hardToo hardMaybe
Running hand analysis
● Run directly on router? Too hard
Solution - ssh, ngrep and pipes
ssh $router "ngrep ..." | python -u poker-buddy.py
Piping data into Python is easyYou can read stdin...import syswhile True: l = sys.stdin.readline():
Alternatively use the Unix-like fileinput module...import fileinputfor line in fileinput.input():
... fileinput reads from a list of files, or else stdin
Pipes
Pipes
Watch out for buffering!
python -u
Now for some poker smarts
Loads of resources on the web● Poker games generally
○ starting hand rankings○ odds calculations etc
Now for some poker smarts
Easy lookup tables in python...# Unprocessed space separated string dump
stats_rankings = \
"""AA 2.3200 550,632
KK 1.6700 551,878
... lots more lines
32s -0.1600 369,182"""
# Now convert to structured data
stats_rankings = dict([
(line.split()[0], (rank + 1, float(line.split()[1])))
for rank, line
in enumerate(stats_rankings.split("\n"))
])
Now for some poker smarts
Python specific● pypoker-eval
○ Wrapper for poker-eval toolkit○ Run hand simulations
● machine learning systems○ endless possibilities
● Lots of other resources at:http://pokerai.org/pf3/viewforum.php?f=32
Codedef read_raw_from_stdin():
line = ''
while 1:
l = sys.stdin.readline()
line += l.strip()
if '''we have a complete line''':
parse_update(line)
line = ''
if __name__ == "__main__":
read_raw_from_stdin()
Codedef parse_update(update_str):
player_cards = get_cards(update_str)
if player_cards:
my_cards = [v for v in player_cards if v[0] != '__']
if my_cards:
rank_starting_hand(my_cards[0])
else:
player_cards = old_player_cards # global state excluded
community_cards = get_cards(update_str, player=False)
if community_cards:
print("Community cards %s" % community_cards)
rank_hand(player_cards, community_cards)
Codee = PokerEval()
def rank_hand(pocket_cards, community_cards, iterations=100000):
unknown_cards = ['__'] * (5 - len(community_cards))
result = e.poker_eval(game = "holdem",
pockets = pocket_cards,
iterations = iterations,
board = community_cards + unknown_cards)
for i, data in enumerate(result['eval']):
print(pocket_cards[i], "%2d%%" % (float(data['ev']) / 10), data['winhi'], data['losehi'], data['tiehi'])
Game in progress - poker-buddy.py
Player cards [['__', '__'], ['__', '__'], ['Ac', 'Kc'], ['__', '__'], ['__', '__']]Group 1(5, 0.77)
Game in progress - poker-buddy.py
Community cards ['Th', '5s', '9h']['__', '__'] 21% 20486 77811 1703['__', '__'] 21% 20267 78013 1720['Ac', 'Kc'] 15% 14880 84332 788['__', '__'] 21% 20386 77819 1795['__', '__'] 21% 20207 78074 1719
Game in progress - poker-buddy.py
Community cards ['Th', '5s', '9h', 'Jc', '6s']['__', '__'] 24% 24185 74694 1121['__', '__'] 24% 24332 74502 1166['Ac', 'Kc'] 1% 1019 98870 111['__', '__'] 24% 24005 74893 1102['__', '__'] 24% 24148 74698 1154
Summary
● Python can be used for packet capture○ pycapy
● Python for data processing ○ Pipes, unbuffered input (-u option), stdin, fileinput
module● Python on embedded devices
○ Optware on routers & other embedded devices● IPython Notebook great for analysis...
...and documenting what you found● There's a library for almost everything
○ eg pypoker-eval
Thanks! Questions?
Code (warts and all):https://github.com/mindsocket/poker-buddy