Advent of Code 2020 (Days 1-9)
I need a good distraction to finish the year
[2020-12-01]#development #adventofcode #julia #lisp #racket
Next: Advent of Code 2020 Day 10
Advent of Code 2020 is here! This year I’m revisiting Julia, a cross between Python, Fortran, with a hint of Lisp. My solutions are on SourceHut, and in this and follow-up posts I’ll keep a running log of my approach and thoughts (edit: I go into much more detail for later, harder problems).
Day 1
My immediate idea was to take advantage of Julia’s first-class matrix/vector operations. This made quick work of both parts, although as a colleague pointed out to me it could have yielded false positives, since I included each number plus itself (i.e. I really should have filtered out the diagonals).
Extra credit
- Racket: Having a function to produce
combinations
in the standard library made it pretty easy. - Common Lisp: Writing a function to enumerate two-item combinations for part 1 was easy; three-item combinations for part 2 was trickier, and I ended up just doing all three-element permutations instead.
Day 2
Julia has some nice features I was able to use here, including pipelines (|>
),
which can also be done per-element (.|>
, what Julia calls “broadcasting”). For
example, the following nested function calls:
println(sum(map(x->fn(parseline(x)...), eachline("input/day02.txt"))))
can be rewritten as:
eachline("input/day02.txt") .|> parseline .|> fn |> sum |> println
In addition to being easier to read, it helps for rapid interactive development and debugging.
Extra Credit
- Racket
Day 3
Julia’s strong array support came in helpful here.
Extra Credit
- Common Lisp:
loop
really shined here, especially the way parallel counters work. Looping over the tree map was very easy and clear:
(defun trees (m xs ys)
(loop for j below (array-dimension m 0) by ys
for i by xs
count (aref m j (mod i (array-dimension m 1)))))
Notice how no upper limit needs to be set for the column counter i
, letting
the row counter j
solely terminate the loop.
Day 4
Julia has a solid regex library. Also notable, it allows “chained” comparison operators, e.g.
valid_byr(p) = 1920 <= parse(Int,p["byr"]) <= 2002
Extra Credit
- Common Lisp: I experimented with
struct
, it went ok. Parsing fields seemed a bit awkward, probably room for improvement there.
Day 5
As they say, there are 10 types of people in the world: those who speak binary, and those who don’t.
Day 6
Julia fully embraces unicode. Sometimes it’s clearer using mathematical symbols,
but in general probably not. I like using them anyways, (like how I use λ
instead of lambda
in racket). It’s nice that the REPL and emacs mode support
LaTϵχ commands followed by <tab>
to quickly insert them (e.g. \cup
-> ∪ for
union and \cap
-> ∩ for intersection).
Day 7
A naive parser and some regex solved this. Bonus: I had my program output a
dot
file for graphing in Graphviz, but the output
from dot
was gigantic and unreadable. I thought maybe circo
would make a
nice graph, but I gave up on it after about a half hour.
Day 8
Is this the next intcode‽ Maybe not… I invested a
bit into learning Julia’s struct
and multi-dispath methods just in case.
Day 9
Ugh, I hate when you make an assumption during part one that makes you rewrite a
bunch of code for part two. In this case I thought I was clever (“oh, we only
need the last n entries? I’ll write a ring buffer!”), but then of course we
needed all the entries in part two. Admittedly the code wasn’t really that more
complicated just indexing into a Vector
, and I got rid of all the
probaly-buggy Ring
code I’d written. Learned a bit more about methods and
multi-dispatch. Did I mention how much I love the Test.@test
and @debug
macros? Well they’re nice.
Day 10
My Day 10 writeup got a bit long, so I broke it into its own post. I’m going to try to do more detailed write-ups like that going forward.
Next: Advent of Code 2020 Day 10