Skip to content

Instantly share code, notes, and snippets.

@kristopherjohnson
Last active August 29, 2015 14:10
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 kristopherjohnson/f941f2dab644c481c4aa to your computer and use it in GitHub Desktop.
Save kristopherjohnson/f941f2dab644c481c4aa to your computer and use it in GitHub Desktop.
Random number sequence generators for Swift
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