In [1]:
%pylab inline
from matplotlib import font_manager as fm
import matplotlib as mpl
import pandas as pd
import requests
from pokereval import PokerEval
pokereval=PokerEval()
from bs4 import  BeautifulSoup
from IPython.html.widgets import interact, fixed
from IPython.html import widgets
from IPython.display import HTML, YouTubeVideo, Image, Javascript, Math, IFrame
from IPython.utils.traitlets import Unicode
from IPython.core.magic import cell_magic
plt.rc('xtick', labelsize=30)
plt.rc('ytick', labelsize=30)
plt.rc('lines', linewidth=5)
plt.rc('figure', figsize=[14.0, 10.0])
plt.rc('font', family=["Microsoft JhengHei"])
plt.rcParams['text.usetex']=False
def pretty_card(c):
    return c[0]+'$\\'+{'h': 'heart', 'd':'diamond', 's':'spade', 'c':'club'}[c[1].lower()]+'suit$'
def pretty_cards(cards):
    return " ".join(map(pretty_card, cards))
def str2cards(s):
    if type(s) is str:
        return [s[i:i+2] for i in range(0, len(s),2)]
    else:
        return list(s)
def poker_eval(pockets, board, **kw):
    pockets = [str2cards(x) for x in pockets]
    board = str2cards(board)
    img_style = "float: left; width: 12%; margin-right: 1%; margin-bottom: 0em;margin-top: 0em"
    result = pokereval.poker_eval(game='holdem', fill_pockets=1, pockets=pockets, board=board, **kw)
    sizes = [x['ev'] for x in result['eval']]
    labels = [pretty_cards(x) for x in pockets]
    prop = fm.FontProperties()
    prop.set_size(30)
    explode = (0.1,)+(0,)*(len(pockets)-1)
    pie = plt.pie(sizes, labels=labels, shadow=True, autopct="%2.2f%%", startangle=90, explode=explode)
    plt.axis("equal")
    plt.setp(pie[2], fontproperties=prop)
    display(HTML("<div>"+"".join('<img src="cards/%s.png" style="%s" />'%(b, img_style) for b in board if b!="__")+"</div>"))
    return sizes

def preflop(*pockets, **kw):
    return poker_eval(pockets=list(pockets), board=["__"]*5, **kw)

def show_html(html, noclass=False):
    if noclass and 'class' in html.attrs:
        html=BeautifulSoup(str(html)).body.contents[0]
        del html.attrs['class']
    display(HTML(str(html)))

def get_html(url):
    r = requests.get(url)
    soup = BeautifulSoup(r.content)
    for s in soup.findAll('span', attrs={'class':'sortkey'}):
        s.extract()
    return soup

def show_bio(name):
    url = 'http://en.wikipedia.org/wiki/'
    table = get_html(url+name).find('table', attrs={'class':'vcard'})
    table.attrs['style']='width: 80%'
    for img in table.findAll('img'):
        img.parent.attrs['class']='zoom_img'
    show_html(table)
#from sympy import *
#init_printing()
Populating the interactive namespace from numpy and matplotlib
:0: FutureWarning: IPython widgets are experimental and may change in the future.
In [2]:
import subprocess 
from IPython.core.magic import (register_line_magic, register_cell_magic,
                                register_line_cell_magic)
def popen2(cmd):
    return subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE)
def lsc(src):
    return popen2(['lsc','-s','-b', '-c']).communicate(src.encode('utf8'))[0].decode('utf8')
@register_cell_magic
def livescript(line, cell):
    """Run the cell block of livescript code"""
    print(line)
    out = lsc(cell)
    print(out)
    display(Javascript(out))

數學漫談 Week4

黑傑克與下注

魏澤人

Blackjack

In [3]:
bjhtml = get_html('http://en.wikipedia.org/wiki/Blackjack')
show_html(bjhtml.findAll('table')[0])
Blackjack
BlackJack6.jpg
A blackjack
Alternative name(s) Twenty-One
Players 2+, usually 2–6
Skill(s) required Probability
Cards 52
Deck French
Play Clockwise
Random chance High
In [4]:
show_html(bjhtml.findAll('ul')[27])
In [5]:
show_html(bjhtml.findAll('table')[1])
Number of Decks House Advantage
Single deck 0.17%
Double deck 0.46%
Four decks 0.60%
Six decks 0.64%
Eight decks 0.65%
In [6]:
show_html(bjhtml.findAll('table')[2])
Player hand Dealer's face-up card
2 3 4 5 6 7 8 9 10 A
Hard totals (excluding pairs)
17–20 S S S S S S S S S S
16 S S S S S H H SU SU SU
15 S S S S S H H H SU H
13–14 S S S S S H H H H H
12 H H S S S H H H H H
11 Dh Dh Dh Dh Dh Dh Dh Dh Dh H
10 Dh Dh Dh Dh Dh Dh Dh Dh H H
9 H Dh Dh Dh Dh H H H H H
5–8 H H H H H H H H H H
Soft totals
2 3 4 5 6 7 8 9 10 A
A,8–A,9 S S S S S S S S S S
A,7 S Ds Ds Ds Ds S S H H H
A,6 H Dh Dh Dh Dh H H H H H
A,4–A,5 H H Dh Dh Dh H H H H H
A,2–A,3 H H H Dh Dh H H H H H
Pairs
2 3 4 5 6 7 8 9 10 A
A,A SP SP SP SP SP SP SP SP SP SP
10,10 S S S S S S S S S S
9,9 SP SP SP SP SP S SP SP S S
8,8 SP SP SP SP SP SP SP SP SP SP
7,7 SP SP SP SP SP SP H H H H
6,6 SP SP SP SP SP H H H H H
5,5 Dh Dh Dh Dh Dh Dh Dh Dh H H
4,4 H H H SP SP H H H H H
2,2–3,3 SP SP SP SP SP SP H H H H

下注策略

停損 停利

In [6]:
from random import randint, choice
for k in range(10):
    i=10
    result=[i]
    while 0<i<100:
        i = i+choice([-1,1])
        result.append(i)
    plot(result);

不破產的機率

In [15]:
from sympy import *
init_printing()
n=S('n')
limit((1-1/n)**n, n, oo)
Out[15]:
$$e^{-1}$$
In [16]:
0.999**2000
Out[16]:
$$0.13519992539749945$$

加倍下注

In [26]:
stack = 1000
history = []
for i in range(1000):
    bet = 1
    while 1:
        history.append(stack)
        #print("bet", bet)
        c = choice([-1,1])
        if c == 1:
            stack+=bet
            #print("win stack=%d"%stack) 
            break
        stack-=bet
        if stack==0:
            print("破產")
            break
        #print("lose, stack=%d"%stack)
        bet = min(bet*2, stack)
    history.append(stack)
    if stack==0:
        break
plot(history);
破產

  • Martingale 1, 2, 4, 8, 16, ….
  • 贏要衝 輸要縮
  • 99.99% win $1.
  • Gambler’s ruin: A有 99 元,B有 1元,那麼 99% A贏,1% B贏。
  • Optional Sampling Theorem (Doob 1953).
  • 在賭客或者賭場資金有限的前提下
  • 賭場有利的遊戲,賭客不可能靠「纜」擊敗賭場。

Kelly Criterion 1956

$f^{*} = \frac{bp - q}{b} = \frac{p(b + 1) - 1}{b},$

In [27]:
from sympy import *
init_printing()
x,b,p = symbols('x b p')
y = p*log(1+b*x) + (1-p)*log(1-x)
solve(diff(y,x), x)
Out[27]:
$$\left [ \frac{1}{b} \left(b p + p - 1\right)\right ]$$

心理

  • Gambler’s Fallacy
  • Availability Error
  • Clustering Illusion (see pattern)
  • Ramsey Theory: "complete disorder is impossible"
In [28]:
Image('http://upload.wikimedia.org/wikipedia/commons/thumb/9/98/RamseyTheory_K5_no_mono_K3.svg/210px-RamseyTheory_K5_no_mono_K3.svg.png')
Out[28]:
  • Gambler’s Conceit: David Ewing
  • Illusion of Control
In [29]:
m2html=soup = BeautifulSoup(open("math2.html").read())
show_html(m2html.findAll("section")[24])
AB
In [30]:
phtml=get_html('http://en.wikipedia.org/wiki/Penney%27s_game')
show_html(phtml.findAll('table')[0])
1st player's choice 2nd player's choice Odds in favour of 2nd player
HHH THH 7 to 1
HHT THH 3 to 1
HTH HHT 2 to 1
HTT HHT 2 to 1
THH TTH 2 to 1
THT TTH 2 to 1
TTH HTT 3 to 1
TTT HTT 7 to 1

輪盤破解

  • Joseph Hobson Jagger , 1837 統計破解
  • Eudaemons 1978
  • J. Doyne Farmer and Norman Packard
  • "The Eudaemonic Pie“
  • The trio 2004
  • a Hungarian woman and two Serbian men
  • Laser, Cell Phone
  • 英國, 無罪

麻將賓果

In [31]:
Image('https://c2.staticflickr.com/6/5141/5594037415_a1891512ff_z.jpg')
Out[31]:
In [32]:
Image('http://images.plurk.com/fccc0ab75908d721f8bf26cb749a6405.jpg')
Out[32]:
In [37]:
(14*binomial(30, 9)/binomial(36,15)).evalf()
Out[37]:
$$0.0359740670461733$$
In [38]:
(14*binomial(30,14)/binomial(36,20)).evalf()
Out[38]:
$$0.278592375366569$$
In [ ]:
 
In [41]:
from itertools import combinations
from random import shuffle
positions = [(a,b) for a in range(6) for b in range(6)]
聽牌, 胡牌 = 0,0
N = 100
for i in range(N):
    shuffle(positions)
    count=[0]*14
    for a,b in positions[:15]:
        count[a]+=1
        count[b+6]+=1
        if a==b:
            count[12]+=1
        if a+b==5:
            count[13]+=1
    if any(x==5 for x in count):
        聽牌 +=1
    if any(x==6 for x in count):
        胡牌 +=1
print(聽牌/N,胡牌/N)
1.0 1.0
In [ ]:
((14*6*binomial(30,10)-30*36*binomial(24,5)-(36+13+12)*25*binomial(25,6))/binomial(36,15)).evalf()
In [43]:
((14*6*binomial(30,10))/binomial(36,15)*5/21).evalf()
Out[43]:
$$0.10792220113852$$
In [ ]:
from IPython.external import mathjax; mathjax.install_mathjax()
In [ ]: