BuddhiLW / Blackjack.jl

Julia plots, gifs and Monte Carlos simulations of probabilities concerning Blackjack

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Readme

Terminology

TerminologyMeaning
CNRCount with No Replacement
BJcorecore of the Blackjack application

Helper functions

High-order functions

Commonly we find the pattern P(event(e1,e2)) = P((f(e1) && g(e2)) || (f(e2) && g(e1))), in which f and g are boolean functions.

So, we write this pattern with high-order functions.

Example

function isCombination(f, g, e1, e2)
    if (f(e1) && g(e2)) || (f(e2) && g(e1))
        true
    else
        false
    end
end


# isBJ
function isBJ(e1, e2)
    isCombination(BJcore.isA, BJcore.isTens, e1, e2)
end

Probability of having a BlackJack

Analytically, considering no replacement

Let’s suppose we just started a hand, 6 decks of 52 cards.

The probability to have a ten and an ace is of:

$P(\mathrm{BJ}) = \dfrac{N(A;10s) ∪ N(10s;A)}{N(\mathrm{possible \, pairs})}$

In which, $N(A;10s)=(6.4)×(6.4.4)$. And, $N(\text{possible pairs})=(6.52)×(6.52-1)$. Because, There are 4 possible As in each one of the 6 decks and four possible 10s: 10, Q, J, K. So, the possibility of an Ace and a ten, N(A;10s).

P = 2*((6*4)*(6*4*4))/((6*52)*(6*52-1))

Therefore, the probability is ~0.0475.

Considering a random experiment, without replacement

include("src/noreplace-histogram.jl")

N = 10^5
cnt = 0
for i in 1:N
    event = CNR.CardEventNR(3, 6)
    if (isA(event[1]) && isTens(event[3]) || isA(event[3]) && isTens(event[1]))
        cnt += 1
    end
end

P_BJ = cnt / N # => 0.0480

Therefore, P(BJ)=~0.0480, at first hand, using Monte Carlo Method.

Helper functions

In which, the helper functions isA and isTens are defined as:

function isA(event)
    if event == "A"
        true
    else
        false
    end
end

function isTens(event)
    if event == "10" || event == "Q" || event == "J" || event == "K"
        true
    else
        false
    end
end

Card Event (random card pick, infinite deck)

function cardEvent()
    hit = rand(1:pcards)
    if deck[hit].first == "A"
        deck[hit].first
    else
        return string(deck[hit].second[1])
    end
end

Julia animation plotting

Infinite deck

  • Q&A (Stack Overflow)
using DataStructures
N = 10^3
frequency2 = [cardEvent() for _ in 1:N]
anim = @animate for i = 1:N
    if i < 10
        f = counter(frequency2[1:i])
        P = [j / sum(f) for j in values(f)]

        bar([keys(f)...], P, title=L"\mathbf{retiradas}")
    elseif mod(i, 10) == 0
        f = counter(frequency2[1:i])
        P = [j / sum(f) for j in values(f)]

        bar([keys(f)...], P, title=L"\mathbf{retiradas}")
    end
end

gif(anim, "mygif.gif", fps=1)

Finite deck, with no replacement

function cardEventNR(n=1, dks=6, r=false)
    c = repeat(cards, 4 * dks) # 4 cards per number of decks per card-type
    hits = sample(c, n, replace=r)
    return hits
end

frequency3 = cardEventNR(312, 6)

anim3 = @animate for i = 1:(13*6*4)
    f = counter(frequency3[1:i])
    P = [j / sum(f) for j in values(f)]
    title = "$i retiradas"
    bar([keys(f)...], P, title=title)
end

gif(anim3, "mygif-noreplace.gif", fps=10)

Decks WithOut cards

preferences must follow the structure Vector{Pair{String,Int64}}, e.i., [“A” => 3, “K”=>3].

Given the chosen n decks, we have $n.(4.13)=n.52$ cards. But, we are going to remove certain cards by a given quantity $m &lt;= 4.n$ (4.n is the total quantity of cards of a type).

We take m, divide by 4, and take the floor. Thus, we have of many complete decks are emptied by that card-type. Further, we take the modulus mod(m,4), so we have how many cards have to be depleted from a deck. Finally, we removed all cards of this type with the given quantity asked.

Notes on studying Julia

Metaprogramming

Use calculating probabilities

We have the following, when we calculate the probability of getting a blackjack at first play - for context,

function P_BJ(n=10^6)
    N = n
    cnt = 0
    for i in 1:N
        event = CNR.CardEventNR(3, 6)
        if ((BJcore.isA(event[1]) && BJcore.isTens(event[3])) || (BJcore.isA(event[3]) && BJcore.isTens(event[1])))
            cnt += 1
        end
    end
    P_BJ = cnt / N # => ~0.0475
    print("Probability of BJ, at first hand: $(P_BJ)")
end
end

We notice that, on the line,

if ((BJcore.isA(event[1]) && BJcore.isTens(event[3])) || (BJcore.isA(event[3]) && BJcore.isTens(event[1])))

There is a pattern that is common on calculating probabilities for any event that doesn’t depend on order. That is, f(a).g(b) + f(b).g(a).

macro isCombination(f,g,e1,e2)
    return :( ( f(e1) && g(e2) ) || ( f(e2) && g(e1) ) )
end
function make_expr2(op, opr1, opr2)
    opr1f, opr2f = map(x -> isa(x, Number) ? 2*x : x, (opr1, opr2))
    retexpr = Expr(:call, op, opr1f, opr2f)
    return retexpr
end

Julia documentation example

https://docs.julialang.org/en/v1/manual/metaprogramming/#Functions-on-Expressions

julia> function make_expr2(op, opr1, opr2)
           opr1f, opr2f = map(x -> isa(x, Number) ? 2*x : x, (opr1, opr2))
           retexpr = Expr(:call, op, opr1f, opr2f)
           return retexpr
       end
make_expr2 (generic function with 1 method)

julia> make_expr2(:+, 1, 2)
:(2 + 4)

julia> ex = make_expr2(:+, 1, Expr(:call, :*, 5, 8))
:(2 + 5 * 8)

julia> eval(ex)
42

Bash conversion with ffmpeg to mp4

ffmpeg -i mygif.gif -c:v libx264 -profile:v baseline -level 3.0 -pix_fmt yuv420p working.mp4

About

Julia plots, gifs and Monte Carlos simulations of probabilities concerning Blackjack


Languages

Language:Julia 100.0%