Last active
August 29, 2015 14:10
-
-
Save kristopherjohnson/f941f2dab644c481c4aa to your computer and use it in GitHub Desktop.
Random number sequence generators for Swift
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
import func Darwin.arc4random | |
import func Darwin.arc4random_uniform | |
/// Generator of random UInt32 values | |
public struct RandomUInt32Generator: GeneratorType, SequenceType { | |
/// Return next random value. | |
/// | |
/// Note: The returned Optional value will never be nil | |
public func next() -> UInt32? { | |
return arc4random() | |
} | |
/// Return next random value. | |
/// | |
/// This is a convenience method that unwraps the non-nil Optional returned by next(). | |
public func nextValue() -> UInt32 { | |
return next()! | |
} | |
/// Return this generator | |
public func generate() -> RandomUInt32Generator { | |
return self | |
} | |
} | |
/// Generator of random UInt32 values less than a specified upper bound | |
public struct UniformRandomUInt32Generator: GeneratorType, SequenceType { | |
private let upperBound: UInt32 | |
public init(upperBound: UInt32) { | |
self.upperBound = upperBound | |
} | |
/// Return next random value. | |
/// | |
/// Note: The returned Optional value will never be nil | |
public func next() -> UInt32? { | |
return arc4random_uniform(upperBound) | |
} | |
/// Return next random value. | |
/// | |
/// This is a convenience method that unwraps the non-nil Optional returned by next(). | |
public func nextValue() -> UInt32 { | |
return next()! | |
} | |
/// Return this generator | |
public func generate() -> UniformRandomUInt32Generator { | |
return self | |
} | |
} | |
/// Generator of random UInt32 values within a specified range | |
public struct BoundedRandomUInt32Generator: GeneratorType, SequenceType { | |
private let minValue: UInt32 | |
private let maxValue: UInt32 | |
/// Construct generator to generate values between minValue and maxValue, inclusive. | |
public init(minValue: UInt32, maxValue:UInt32) { | |
assert(minValue <= maxValue) | |
self.minValue = minValue | |
self.maxValue = maxValue | |
} | |
/// Construct using a Range<Int> | |
public init(range r: Range<Int>) { | |
assert(r.startIndex >= 0, "range must not include negative values") | |
self.init(minValue: UInt32(r.startIndex), maxValue: UInt32(r.endIndex - 1)) | |
} | |
/// Construct using a Range<UInt32> | |
public init(range r: Range<UInt32>) { | |
self.init(minValue: r.startIndex, maxValue: r.endIndex - 1) | |
} | |
/// Return next random value. | |
/// | |
/// Note: The returned Optional value will never be nil | |
public func next() -> UInt32? { | |
return arc4random_uniform(maxValue - minValue + 1) + minValue | |
} | |
/// Return next random value. | |
/// | |
/// This is a convenience method that unwraps the non-nil Optional returned by next(). | |
public func nextValue() -> UInt32 { | |
return next()! | |
} | |
/// Return this generator | |
public func generate() -> BoundedRandomUInt32Generator { | |
return self | |
} | |
} | |
/// Generator of random Double values uniformly distributed in the range 0.0 ..< 1.0 | |
public struct UniformRandomDoubleGenerator: GeneratorType, SequenceType { | |
/// Return next random value. | |
/// | |
/// Note: The returned Optional value will never be nil | |
public func next() -> Double? { | |
// There may be a better magic number to use here, but this should work | |
let intervalCount = UInt(1) << 31 | |
return Double(arc4random_uniform(UInt32(intervalCount))) / Double(intervalCount) | |
} | |
/// Return next random value. | |
/// | |
/// This is a convenience method that unwraps the non-nil Optional returned by next(). | |
public func nextValue() -> Double { | |
return next()! | |
} | |
/// Return this generator | |
public func generate() -> UniformRandomDoubleGenerator { | |
return self | |
} | |
} | |
// Example usage | |
// Generate numbers in the range 0..<100 until we get a 7 | |
let sequence = UniformRandomUInt32Generator(upperBound: 100) | |
for value in sequence { | |
println(value) | |
if value == 7 { | |
println("We got a 7!") | |
break | |
} | |
} | |
// Generate some random floating-point values in the range 0..<1 | |
let doubleGen = UniformRandomDoubleGenerator() | |
for n in 1...20 { | |
println("Random double #\(n): \(doubleGen.nextValue())") | |
} | |
// A six-sided die | |
struct D6 { | |
let gen = BoundedRandomUInt32Generator(range: 1...6) | |
func roll() -> Int { | |
// This typecast is safe because we know the values are convertible to Int | |
return Int(gen.nextValue()) | |
} | |
} | |
let d6 = D6() | |
for n in 1...20 { | |
println("Random d6 roll #\(n): \(d6.roll())") | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment