Archive for June, 2015

Going random in the age of GameplayKit

Screen Shot 2015-06-30 at 8.08.57 AM

One of the great things about GameplayKit is how it helps you simulate rolled die and random distributions. The example in the above screenshot uses a Gaussian distribution as it rolls a number between 0 and 100. The results of 100000 “rolls” are shown in the playground.

Here’s an example that demonstrates how to generate random values.

public func RollEm(samples : Int) -> [Int] {
    // Build a source
    let source = GKARC4RandomSource()

    // Drop the first n > 768 values
    source.dropValuesWithCount(1024)

    // Build a distribution
    let distribution = 
        GKGaussianDistribution(randomSource: source, 
            lowestValue: 0, highestValue: 100)

    // Access random values
    var counts = Array(count: 101, 
        repeatedValue: 0)
    for _ in 1...samples{
        counts[distribution.nextInt()]++}
    return counts
}

Creating Sources

You start by creating a source. GameplayKit offers three choices: ARC4, linear congruential, or Mersenne twister. These are GKRandomSource subclasses that provide concrete randomization implementations. Each source uses a distinct approach to generate random numbers.

The linear source is fastest but least “random” because low bits repeat more than high bits. Apple recommends you choose this when performance matters. The Mersenne Twister source is slowest but creates the best results, avoiding repeating patterns. The ARC4 source (similar to arc4random) offers the middle ground of performance vs results.

The class documentation notes that ARC4 may create sequences with initial repeating values that reveal the source’s seed. “To obfuscate gameplay mechanics based on this generator, call this method with a count parameter of 768 or greater.” Drop values by calling dropValuesWithCount().

Apple also recommends avoiding GameplayKit randomization for cryptography.

Distributions

You pipe sources, which generate random bits, through distributions, which transform their output into actual random numbers. A distribution is limited by a range with known frequency characteristics. The Gaussian distribution used in the above example creates a normal (“bell”) curve, with a known mean and deviation derived from that range.

The shuffled distribution avoids repeated short sequences by “shuffling” outputs with uniform distributions. Apple writes,

A GKShuffledDistribution object produces random numbers that across many samplings are uniformly distributed, but where short sequences of similar values are unlikely. This behavior is sometimes called “fair” randomization, because true randomness in games can result in extended “lucky streaks” or “unlucky streaks” for players.

Finally, there’s the basic random distribution, which just creates a uniform distribution without bias.

Custom Distributions

I couldn’t find any notes about subclassing GKRandomDistribution in the headers but there are tons of probability distribution types and you’d think for simulation, you might want to expand beyond linear, shuffled, and Gaussian. I messed around a bit with building cumulative distribution functions for probability distributions. I found myself building classes using the GKRandom protocol instead of subclassing. Subclassing just seems pointless at this time.

Generating Numbers

Gameplay Kit replaces your dice pouch. You can simulate a d6 or d20 die using preset constructors or you can build a distributionForDieWithSideCount customize to the number of sides needed for your game. Just pull the nextInt from your die as each time you roll.

Distributions also allow you to grab random floating point values (nextUniform), coin tosses (nextBool). The returned values are affected by how you set up your distribution, so if use a skewed distribution, expect skewed results.

Shuffling

One final thing that GKRandomSource does that’s really nice to work with is arrayByShufflingObjectsInArray:. I’ve posted about using this before, so I’ll skip the details here. Handy and doesn’t require a distribution. Just grab the shared random source, which uses the built-in arc4 random generator.

Life with 6-Plus

As we head into Summer, I’ve had a good long haul with my 6-Plus. I think I’ve had enough hands-on time with it to summarize how I like it. In a word? Meh. This is not one of Apple’s more outstanding products.

It’s not big enough to be used as a tablet so I end up hauling my iPad with my everywhere. It’s too big to be used comfortably as a phone so I keep longing for a smaller handset. In fact, I’d have done much better at this point getting a phone from any provider with voice dialing and an iPad or iPad mini with cellular data.

That’s not to say that there isn’t much to love on the 6 plus. It’s just that you have to look to find it. It’s like hauling around a well-intentioned bumbling moose with you. No matter how nice the moose, it’s still a moose.

Dev: Adding unit tests to command line projects

Wanted to add unit tests to a command line project. Realized that this isn’t an option in the creation dialog like it is with normal apps. So putting this here for the googles.

1. Add a testing bundle. Editor > Add Target, Cocoa (Touch) Testing Bundle, Next, etc.

2. Edit the scheme. Product > Scheme > Edit Scheme. Select Test, click +. Under “Choose targets to test as part of this scheme”, select your test target.

3. Try. Check that you set it up right with Product > Test (Command-U).

Tips:

  • When using Swift, don’t forget that to use @testable in your import to expose all the classes, whether or not marked public.
  • When converting your target name for import, use underscores to replace spaces: “Hola Svift” becomes “Hola_Svift”.

Swift and sleep depravation

In terms of Swift and sleep depravation1, neither one is good for the other. I asked here:  “But why does the first one work?” in reference to:

print([1, 2, 3, 4, 5, 6].map(String.init))
print([1, 2, 3, 4, 5, 6].map{String($0)})

Now I’m going to answer in a way that I should probably have managed on the first go-round. Thanks to everyone who pinged me.  First, String.init is a function. For example, this

func plus1(a : Int) -> Int {return a + 1}

creates a function called plus1. If you type plus1 into a playground, it shows the Int-> Int signature.

Screen Shot 2015-06-28 at 7.18.09 PM

You can assign plus1 to something else and that’s a function too.

let plusOne = plus1
print([1, 2, 3, 4, 5, 6].map(plus1))
print([1, 2, 3, 4, 5, 6].map(plusOne))

The map function takes one argument, a function / closure / lambda expression / thing that does things, and returns an array with result of mapping that transformation over each element of self.

This example uses a closure. It is an argument to the map function.

print([1, 2, 3, 4, 5, 6].map({$0 + 1}))

Because the closure is the last argument, you theoretically don’t have to use parentheses.

print([1, 2, 3, 4, 5, 6].map{$0 + 1})

As I’m starting to learn, it’s a better idea to keep those parens. Map uses values returned by its closure parameter. Naked-trailing-closure is better suited for situations where the closure executes as a procedure rather than a function, for example GCD dispatch.

So the example I started out with:

print([1, 2, 3, 4, 5, 6].map{String($0)})

would be better implemented as

debugPrint([1, 2, 3, 4, 5, 6].map({String($0)}))

Finally, there is a related construct, which has nothing to do with this, which I was incoherently mumbling about last week, which goes like this:

MyClass.myMethod(instance)

This is a curried function on a class, that enables you to pass MyClass.myMethod as a closure, and can be used for storing target-action patterns. Thanks, Thompas Pelaia, who adds, “A big advantage over the Objective-C target-action using selectors is that you get compile time checking in Swift. For example, you can use it with protocols and/or generics.”

Me? I’m going to try to get some sleep this week. Hopefully no more tornados.

p.s. A big thanks to Chris Lattner

1 joke. see also. The actual lack of sleep is real.

Xcode shenanigans: Indentage Servitude

This happen to you? The indentation thing, not the code thing.

Screen Shot 2015-06-28 at 12.24.22 PM

Xcode won’t indent code that doesn’t match the current target. It even does this in standalone code editors outside proper workspaces. The best you can do is this.

  • Change the iOS in the #if to OSX.
  • Use Editor > Structure > Re-indent on the Cocoa part.
  • Then change the condition back to iOS.

Speaking of build configurations, you cannot use #if around bits of statements either. You must annotate full Swift expressions, statements, and control flow statements.

Screen Shot 2015-06-28 at 12.37.39 PM

Things aren’t so bad if you can differentiate entire statements:

Screen Shot 2015-06-28 at 12.54.05 PM

But if your arguments involve different signatures, Auto Layout for example, configurations lead to long, tortured nearly parallel implementations.

Finally. Yes, the color thing was a bad example. It is better solved by using typealias.

Screen Shot 2015-06-28 at 12.46.43 PM

Fun with Apple Unicode: Here’s to the crazy ones

Crazy

There are no fewer than seven different “Here’s to the crazy ones” references in the Apple Emoji set. (If I missed any, please let me know!)

Update: A thank you goes out to commenter Unicode.

📝
MEMO
Unicode: U+1F4DD (U+D83D U+DCDD), UTF-8: F0 9F 93 9D

📜
SCROLL
Unicode: U+1F4DC (U+D83D U+DCDC), UTF-8: F0 9F 93 9C

📖
OPEN BOOK
Unicode: U+1F4D6 (U+D83D U+DCD6), UTF-8: F0 9F 93 96

📑
BOOKMARK TABS
Unicode: U+1F4D1 (U+D83D U+DCD1), UTF-8: F0 9F 93 91

📋
CLIPBOARD
Unicode: U+1F4CB (U+D83D U+DCCB), UTF-8: F0 9F 93 8B

📃
PAGE WITH CURL
Unicode: U+1F4C3 (U+D83D U+DCC3), UTF-8: F0 9F 93 83

📄
PAGE FACING UP
Unicode: U+1F4C4 (U+D83D U+DCC4), UTF-8: F0 9F 93 84

Swift: Crash. Burn. Die.

How to fail in Swift.

Fatal Error

Unconditionally print a `message` and stop execution.

fatalError("Goodbye!")
fatalError()

Assert

Traditional C-style assert with an optional message. Use these to test assumptions and locate design errors during development.

assert(false)
assert(false, "Oops")
assertionFailure()
assertionFailure("Oops")
  • Program execution ends on false assertions in playgrounds and -Onone.
  • Assertions are not evaluated in -O (default Release).
  • For -Ounchecked, the optimizer tries to assume the assertion would evaluate to true. If not, it is a “serious programming error”.

Precondition

Unlike assertions, preconditions are checked and will stop an app in release mode. Use these sparingly. With great failure comes great responsibility.

precondition(false)
precondition(false, "Oops")
preconditionFailure()
preconditionFailure("Ooops")
  • A fail stops to a debuggable state in Debug (-Onone) and playgrounds.
  • Ends execution in release (-O).
  • Same deal as assert for -Ounchecked.

Abort and Exit

Most commonly used for command line apps, abort() produces abnormal process termination.

@noreturn func abort()

Use exit() for traditional exit code support, which can then be tested in shell scripts.

@noreturn func exit(_: Int32)

Throwing

It’s entirely possible to throw or catch a recoverable error and continue execution. If that’s not a viable solution, find the best way to prepare for a clean termination and then perform a program exit.

enum Failure : ErrorType {
    case Fail
}

do {
    throw Failure.Fail
} catch {
    // clean up shop
    NSLog("App failure") // prints to system console
    fatalError("\(error)")
}

Swift: Protocol requirements

Swift 2.0 enables you to add public extensions of generic types. In Beta 2, extensions can be constrained by adding  protocol requirements on the type parameters of the generic type.

Last night, Gal3rielol asked if he could use extensions to add methods to arrays with restricted types, such as [Int] or [MyType].

You cannot add specific typing, like

extension Array where Element == Int

because this type requirement transforms the generic Array into a non-generic version.

Nor, can you perform an extension on Array<Int>:

error: constrained extension must be declared on the 
unspecialized generic type 'Array' with constraints 
specified by a 'where' clause

You can find or create a protocol that limits your extension to more or less just the type you want to work with:

extension Array where T : StringLiteralConvertible 
extension Array where T : IntegerArithmeticType

Or create a custom protocol and use it restrict the items your extension works with:

protocol OnlyStrings {}
extension String: OnlyStrings{}
extension Array where T : OnlyStrings

This approach is limited. While you know the extension only applies to strings, the compiler is still working with type T. This example by Mike Ash demonstrates the issue:

extension Array where T : OnlyStrings {
    func appendAll() -> String {
        var accumulator = ""
        for item in self { accumulator += item }
        return accumulator
    }
}

This errors with “error: binary operator ‘+=’ cannot be applied to operands of type ‘String’ and ‘T’” Work around this by casting item to String(item). You should also add a StringLiteralConvertible restriction. It’s inelegant at best.