Skip to content

Instantly share code, notes, and snippets.

@loganwright
Last active June 24, 2021 23:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save loganwright/8c0f9a1203f5c6743b4e9b2452784233 to your computer and use it in GitHub Desktop.
Save loganwright/8c0f9a1203f5c6743b4e9b2452784233 to your computer and use it in GitHub Desktop.
binary-cards-probability
// setup
enum Value: String, CaseIterable, Equatable {
case ace,
two,
three,
four,
five,
six,
seven,
eight,
nine,
ten,
jack,
queen,
king
}
enum Suit: String, CaseIterable, Equatable {
case spades,
hearts,
diamonds,
clubs
}
struct Card: Equatable {
let value: Value
let suit: Suit
}
let deck = Suit.allCases.flatMap { suit in
Value.allCases.map { value in
Card(value: value, suit: suit)
}
}
precondition(deck.count == 52)
/// subdivisions
typealias Question = (Card) -> Bool
struct SubdividedDeck {
let label: String
let left: [Card]
let right: [Card]
init(_ label: String, _ question: Question) {
self.label = label
let (left, right) = deck.makeGroups(sortWith: question)
self.left = left
self.right = right
}
}
extension Array where Element == Card {
func pickRandom() -> Card {
assert(!self.isEmpty)
return randomElement()!
}
func makeGroups(sortWith: Question) -> ([Card], [Card]) {
var a = [Card]()
var b = [Card]()
forEach { card in
if sortWith(card) {
a.append(card)
} else {
b.append(card)
}
}
return (a, b)
}
}
/// round
enum Result: Equatable {
case win, loss
}
extension Array where Element == Result {
var winPercentage: Double {
let wins = filter { $0 == .win } .count
let total = self.count
return Double(wins) / Double(total)
}
}
/// options
let isRed = SubdividedDeck("isRed") { card in
switch card.suit {
case .diamonds, .hearts:
return true
default:
return false
}
}
let isFace = SubdividedDeck("isFace") { card in
switch card.value {
case .jack, .queen, .king:
return true
default:
return false
}
}
let isAceOfSpades = SubdividedDeck("isAce") { card in
card.suit == .spades && card.value == .ace
}
///
extension SubdividedDeck {
func play() -> Result {
let prize = deck.pickRandom()
let choicePool = choicePool(containing: prize)
let guess = choicePool.pickRandom()
return guess == prize ? .win : .loss
}
func choicePool(containing prize: Card) -> [Card] {
left.contains(prize) ? left : right
}
}
/// prepare
let tests = [
isRed,
isFace,
isAceOfSpades,
]
var results: [String: [Result]] = [:]
tests.forEach { results[$0.label] = [] }
/// simulate
let numberOfCycles = 10_000_000
for _ in 1...numberOfCycles {
tests.forEach { test in
let result = test.play()
results[test.label]!.append(result)
}
}
/// results
tests.forEach { test in
let probability = results[test.label]!.winPercentage
print("\(test.label): \(probability)")
}
print("")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment