Repetition in Swift

A couple of years ago, partially just for fun and partially for a school assignment, I wrote a Sudoku puzzle solver in Java. The core of the program was a handful of state-checking functions. Each of these looked at the current state of the board and did a few tests to see if any new numbers could be placed.

If any one function solved and placed a number, all the checks needed to be run again using the new board state. The functions were called repeatedly until the board state no longer changed between executions. Since some checks were faster and more basic than others, I had an elaborate system of recursive calls and boolean didAnythingChange checks. The program worked pretty well, but got stuck if there wasn't enough information to produce a solution. If the board started out with only one number marked, for example, the program would fail, as it didn't do any brute-force searching for solutions.

I've recently been playing around with creating an iOS app to implement my personal strategy for a favorite board game. As it is somewhat a puzzle-based game, the solution process is similar. The app needs to run some checks on the game state until the checks turn up no new information. This game is a bit simpler than Sudoku, so I'm not worried about prioritizing certain checks over others.

Remembering the mess of recursive calls I wrote for the Sudoku solver, I thought to myself, there has to be a better way...

Enter the repeater:

func repeat(function: () -> (), untilNoChangeTo sentinel: () -> String) {
    var initial, final: String
    
    do {
        initial = sentinel()
        function()
        final = sentinel()
    } while initial != final
}

In this example, the game board state is condensed into a String that serves as a poor man's hash of the game state. When used as below, the repeat function takes care of monitoring the game state and repeating as necessary.

class Game {
    func checkForSolution() { ... }
    func gameState() -> String { ... }
}

repeat(game.checkForSolution, untilNoChangeTo: game.gameState)

For my new app, repeat calls a parent function that, in turn, repeats the individual solution-checking functions. This is probably a bit overenthusiastic, but as the game state for this particular game isn't too complex, I'll give it a pass for now.

I like this repeat function, but it's a shame that it's tied to String. There must be a better way...

Enter generics.

func repeatGenerically<T: Equatable>(function: () -> (), untilNoChangeTo sentinel: () -> T) {
    var initial, final: T
    
    do {
        initial = sentinel()
        function()
        final = sentinel()
    } while initial != final
}

Only a few changes are needed to make the function much more reusable. Dropping in the generic type <T> takes care of almost everything. The last modification is specifiying that T must be Equatable, since we need to compare two values of type T after the do-while.

This was a fun discovery, one of the many made possible by Apple's use of Swift to nudge programmers into the 21st century. Here's a Gist if you want to give either of the above repeat functions a spin.