Clusters of Wires for Advent of Code 2023 - Day 25

Date

Day 25 of Advent of Code had us determine clusters of wires and the best way to partition them. For most people, the solution revolved around using graphviz. While most of the problem can be done via the command line, I chose to write a macOS app that used graphviz and PDFKit to allow the “human intelligence” to determine the proper cutting points.

For the command line portion of the code, it can be broken down in to generating a graph diagram, clustering the diagram, and then rendering the diagram.

Scores on an iPhone
Scores on an iPhone

Command Line Generation

The graph diagram looks similar to:

graph G {
  vmq -- { rcq qvj bpj }
  fgc -- { gph }
  cgg -- { jnf fmh pbf tmm qml }
  ghp -- { pvl }
  fbh -- { zcx }
  xmk -- { vvb fgk prt dkd qcc hqj }
  jkl -- { zvz }
  zsx -- { msc jpr qmq }
  cdf -- { qlc mtk bnq }
  knq -- { qpb }
  ...
}

The command lines to generate the PDF are:

cluster -C2 -o clustered.dot input.dot
dot -Tpdf -Ksfdp clustered.dot -o Day25.pdf

Sandboxing Gotchas

I used a standard Xcode template for SwiftUI to create the interface. To execute the command line tools, you use a Process object to execute the command and wait. There is a hidden issue with the example code you see around the internet. By default, an application is sandboxed, so while it can execute some system commands, like ls, without issue, it cannot execute arbitrary binaries on your system. There are workarounds, like using sh -c or env to execute the code, but either these do not properly support command line arguments, or they are also sandbox aware and can’t properly execute your commands.

The easiest solution, which works for Advent of Code as it isn’t really a “production” app, is to just disable sandboxing in the Entitlements file. The other solution would be to statically compile graphviz and its dependencies. This is more work than I wanted to do in a small time, so I went with the former solution.

The other part that gets missed from using Process is that you should wait for the program to finish executing. This can be handled in the terminationHandler of the run method, and it can be easily wrapped for async / await as well.

private func generateGraph(from inputURL: URL) async throws -> URL {
    let processURL = URL(fileURLWithPath: "/opt/homebrew/Cellar/graphviz/9.0.0/bin/dot")
    let outputURL = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
        .appending(path: "Day25.pdf")
    
    let arguments = [
        "-Tpdf",
        "-Ksfdp",
        inputURL.path(percentEncoded: false),
        "-o",
        outputURL.path(percentEncoded: false)
    ]
    
    try await withCheckedThrowingContinuation { continuation in
        do {
            try Process.run(processURL, arguments: arguments) { process in
                continuation.resume()
            }
        } catch {
            continuation.resume(throwing: error)
        }
    }
    
    return outputURL
}

Dropping Blocks for Advent of Code 2023 - Day 22

Date

Day 22 of Advent of Code had us drop blocks from an initial position to a compact stack. The blocks are simulated to use 1 meter cubes, so I used equations for a falling body to simulate the actual pull of gravity to make the falling realistic. This looked great for the sample, which completed quickly. For the actual solution, the problem is so big that the video is 1 hour, 20 minutes long and eventually cannot show the bricks falling as they are outside of the viewport.

Advent of Code 2023 - Day22

Closing Pipes for Advent of Code 2023 - Day 10

Date

Day 10 of Advent of Code had us trace the layout of a pipe and then determine which spaces remaining that were completely enclosed by the pipe. Once the pipe was traced and closed, an application of the even-odd rule was used to determine the enclosed spaces.

I chose a simple solution of always just casting my ray to the left. This ended up simplifying my code, as there are cases where the ray only went over parallel lines, never intersecting a truly vertical line. In this case, I only needed to consider pipes that went downward for the even-odd counting.

Advent of Code 2023 - Day 10

Score Card 3.0.1 Released

Date

Score Card 3.0.1 has been released! This minor release fixes an issue of scores losing focus when shifting to face up positions.


Restructure 2.1.1 & 2.1.2 Released

Date

It turns out I never used the close method in Restructure in any of my production code. This led to crashes cleaning up statements, as well as fully deleting the database. There was even a lone issue on GitHub pointing me to the problem, but I never fixed it for over 3 years.