Skip to content

Instantly share code, notes, and snippets.

@jscalo
Created March 13, 2022 18:31
Show Gist options
  • Save jscalo/3a9315f1169fe6f2b0dba086ffa89a4b to your computer and use it in GitHub Desktop.
Save jscalo/3a9315f1169fe6f2b0dba086ffa89a4b to your computer and use it in GitHub Desktop.
Simulation that shows how often a public toilet lid needs to be touched based on different "policies".
import Foundation
enum Gender {
case female, male
static func random() -> Gender {
return Int.random(in: 0...1) == 0 ? .female : .male
}
}
enum LidState {
case up, down
}
enum LidPolicy: String {
case leaveAfter
case returnToDown
func description() -> String {
switch self {
case .leaveAfter: return "Leave the lid as is when finished."
case .returnToDown: return "Men close the lid if necessary when finished."
}
}
}
struct Person {
let gender: Gender
let isPooping: Bool
static func random() -> Person {
return Person(gender: Gender.random(),
isPooping: Int.random(in: 0..<20) == 0) // about 1 in 20?
}
func desiredLidState() -> LidState {
if isPooping {
return .down
} else {
return gender == .female ? .down : .up
}
}
func beginBusiness(context: inout SimulationContext) {
if desiredLidState() == .up {
context.openLidIfNecessary()
} else if desiredLidState() == .down {
context.closeLidIfNecessary()
}
}
func endBusiess(context: inout SimulationContext) {
if gender == .female {
// Nothing to do here.
} else /* male */ {
if context.lidPolicy == .returnToDown {
context.closeLidIfNecessary()
}
}
}
}
struct SimulationContext {
let lidPolicy: LidPolicy
var lidState = LidState.down
var lidTouches = 0
let iterations: Int
mutating func openLidIfNecessary() {
if lidState == .down {
lidState = .up
lidTouches += 1
}
}
mutating func closeLidIfNecessary() {
if lidState == .up {
lidState = .down
lidTouches += 1
}
}
func printResult() {
print("Policy: \(lidPolicy.description())")
print("Iterations: \(iterations)")
print("Lid touches: \(lidTouches)")
let ratio = Double(lidTouches)/Double(iterations)
print("Lid touch %: \(ratio.percentageStr)%")
print("\n")
}
}
func simulateWithPolicy(_ lidPolicy: LidPolicy, iterations: Int) {
var context = SimulationContext(lidPolicy: lidPolicy, iterations: iterations)
for _ in 0..<iterations {
let nextPerson = Person.random()
nextPerson.beginBusiness(context: &context)
nextPerson.endBusiess(context: &context)
}
context.printResult()
}
extension Double {
var percentageStr: String {
let perc = self * 100.0
return String(format: "%0.1f", perc)
}
}
// Main
simulateWithPolicy(.leaveAfter, iterations: 1000000)
simulateWithPolicy(.returnToDown, iterations: 1000000)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment