Advent of Code 2023

As a little anti-nausea med, I have this in my utilities.swift file for AoC:

func memoize<In: Hashable, Out>(_ f: @escaping (In) -> Out) -> (In) -> Out {
  var memo: [In: Out] = [:]
  return {
    if let result = memo[$0] {
      return result
    } else {
      let result = f($0)
      memo[$0] = result
      return result
    }
  }
}

which I used on day 12 as

let possibilities = memoize(_possibilities)

func _possibilities(_ record: Record) -> Int {
  // snip...

  // try if starting with a . or ?
  let ifDotCount = record.tryEatDot().map(possibilities) ?? 0

  // etc...
}

Of course, this is still a global memo dictionary variable. But it guarantees it's only used for memoizing that one function, and since _possibilities is pure it's fairly principled.

It's not thread safe though, so if you try using this in Swift 6 you'd get an error – so you'd need to mark possibilities as either @MainActor or nonisolated(unsafe) (for AoC leaderboard purposes only, of course).

p.s. congrats on placing on Day 12, @mayoff

5 Likes