Day 4 of Advent of Code had us do a word search for “XMAS”. My solution was to just look for the letter “X” and
then spin around that point looking for the string. I though the spinning would look interesting, so I put together a
simple 2D visualization.
Word Search
Lessons Learned
Rendering a grid of text is slow. I added a new offscreenImage function to my visualization library that
lets you generate a CGImage using the same drawing tools you use for the main visualization.
Since rendering the found words would also be slow, I ended up recreating the text grid any time new highlights were
found, allowing the main rendering loop to only render cursors and search vectors.
A bug was found where if a statement was reused and one of the bindings went from a non-nil value to a nil value, the
binding would not update. For example:
tryrestructure.execute(query:"CREATE TABLE foo (name TEXT NULL)")letstatement=tryrestructure.prepare(query:"INSERT INTO foo (name) VALUES (:name)")letencoder=StatementEncoder()structFoo{name:String?}statement.reset()tryenconder.encode(Foo(name:"Bar"),to:statement)statement.step()statement.reset()tryenconder.encode(Foo(name:nil),to:statement)statement.step()
In this case, both records would have a name of “Bar”.
This bug comes from the use of KeyedEncodingContainerProtocol. I assumed that implementing encodeNil would be enough
for handling nil values, but the code needs to also implement the encodeIfPresent methods.
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.
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.