Last active
April 15, 2017 16:46
-
-
Save janhuenermann/2876d08448ebcdd454a40a7934c4d47e to your computer and use it in GitHub Desktop.
A little program that calculates poker probabilities.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// main.swift | |
// poker-head | |
// | |
// Created by Jan on 14.04.17. | |
// Copyright © 2017 Jan Hünermann. All rights reserved. | |
// | |
import Foundation | |
// out – A card that improves our hand | |
var players = 5 | |
let cardsPerPlayer = 2 | |
let pokerDeck = 52 | |
let pokerFlop = 3 // number of cards shown after flop | |
let pokerTurn = 4 // number of cards shown after turn | |
// Only works for n ∈ [0; 20[ | |
func binomial(_ n: Int, _ k: Int) -> UInt64 { | |
if (k == 0 || k == n) { | |
return 1 | |
} | |
var coeff: UInt64 = 1 | |
for x in (n-k+1)...(n) { | |
coeff *= UInt64(x) | |
} | |
for x in 1...k { | |
coeff /= UInt64(x) | |
} | |
return coeff | |
} | |
// What is the probability that there are exactly OS outs in the stack? | |
// Calculates this via a tree | |
func probabilityForPrecisely(numberOfOutsInStack OS: Int, numberOfTotalOuts O: Int, shownCards S: Int, distributedCards: Int = 0, inHand X1: Int = 0, inStack X2: Int = -1) -> Double { | |
var X2 = X2 | |
if (X2 == -1) { | |
X2 = O | |
} | |
// End of tree; this branch should be zero unless it's number of outs in stack is equal to the number we are looking for | |
if distributedCards == (players - 1) * cardsPerPlayer { | |
if X2 == OS { | |
return 1.0 | |
} | |
else { | |
return 0.0 | |
} | |
} | |
// There are no outs in the stack anymore | |
if (X2 == 0) { | |
return OS != 0 ? 0.0 : 1.0 | |
} | |
let unknownCards = pokerDeck - distributedCards - S - cardsPerPlayer | |
// Ok, player draws one of our outs | |
let playerDrawsOut = Double(X2) / Double(unknownCards) | |
* probabilityForPrecisely(numberOfOutsInStack: OS, numberOfTotalOuts: O, shownCards: S, distributedCards: distributedCards + 1, inHand: X1 + 1, inStack: X2 - 1) | |
// Ok, player does not draw one of our outs | |
let playerDrawsNoOut = (1.0 - Double(X2) / Double(unknownCards)) | |
* probabilityForPrecisely(numberOfOutsInStack: OS, numberOfTotalOuts: O, shownCards: S, distributedCards: distributedCards + 1, inHand: X1, inStack: X2) | |
// Sum | |
return playerDrawsOut + playerDrawsNoOut | |
} | |
// The probability that given S shown cards and O outs, the next card will be one | |
// of your desires (it will be an out) | |
func singleProbability(outs O: Int, numberOfShownCards S: Int = 3) -> Double { | |
if (O == 0) { | |
return 0.0 | |
} | |
// Size of stack | |
let stack = pokerDeck - players * cardsPerPlayer - S | |
// Output | |
var cumulative = 0.0 | |
for x in 0...O { | |
// P(there are exactly x outs in stack) | |
let binom = probabilityForPrecisely(numberOfOutsInStack: x, numberOfTotalOuts: O, shownCards: S) | |
// P(there are exactly x outs in stack) * (x outs / stack size) | |
cumulative += binom * (Double(x) / Double(stack)) | |
} | |
return cumulative | |
} | |
// Sum probability that one of your outs will come after flop | |
func turnAndRiverProb(outs O: Int) -> Double { | |
let a1 = singleProbability(outs: O, numberOfShownCards: pokerFlop) | |
let b1 = singleProbability(outs: O, numberOfShownCards: pokerTurn) | |
let b2 = singleProbability(outs: O - 1, numberOfShownCards: pokerTurn) | |
// P(out on turn) + P(out on river) + P(out on turn AND out on river) | |
return a1 * (1-b2) + (1-a1) * b1 + a1 * b2 | |
} | |
func riverProb(outs O: Int) -> Double { | |
return singleProbability(outs: O, numberOfShownCards: pokerTurn) | |
} | |
print("Welcome to POKER HEAD") | |
print("I will calculate probabilities") | |
print("******") | |
print("How many players do you want me to calculate for?") | |
players = Int(readLine()!)! | |
print("Ok, \(players) players. Go ahead and ask me for probabilities.") | |
print("Valid commands :") | |
print("after-flop <outs>") | |
print("on-river <outs>") | |
while (true) { | |
let input = readLine()!.components(separatedBy: " ") | |
if (input.count != 2) { | |
print("Incorrect input") | |
continue | |
} | |
let cmd = input[0].lowercased() | |
let outs = Int(input[1])! | |
switch cmd { | |
case "on-river": print(riverProb(outs: outs) * 100, "%") | |
case "after-flop": print(turnAndRiverProb(outs: outs) * 100, "%") | |
default: print("Incorrect input") | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment