My answers to the Advent of Code 2021
When this started, I thought I'd use it as a chance to learn OCaml or Rust. But the first and most important task every day was to read some lines from a file, and in OCaml, this turned out to be a brainteaser on its own, for me. Simply put, I didn't have time this year.
The kind of input reading that these puzzles want is pretty simple for C++. To read a bunch of integers from standard input, for example:
copy(istream_iterator<int>(cin), istream_iterator<int>(), back_inserter(numbers));
So off I went! Later puzzles seemed remarkably well-suited to C++
library classes like bitset<N>
, or standard algorithms like
partition
, for example, so I've continued in C++.
It'll be fun to have these as a reference for programming exercises when I go back to learn OCaml or Rust, I hope.
Every problem is compiled with C++11 out of the box, using only what's in the standard library.
Even though every day has the same Makefile
, I keep a copy in each day's
subdirectory so that each one is self-contained. The contents of each
day are:
Makefile
sample.txt
: the example input in the problem descriptioninput.txt
: the official problem inputpart_1.cc
: my solution to part 1 of the problempart_2.cc
: my solution to part 2 of the problem
The problems are all solved like this:
./part1 < input.txt
./part2 < input.txt
There's one problem, the lantern-fish one, where the example text talks about differing numbers of days, 18 vs. 80. This is the one case so far where the executable takes an optional command-line argument.
Virtually all style guides have variable declarations on their own
line, except for a in a for
loop. But there are certain C++ idioms
where I think it makes sense to do the same. Reading lines from input
is one of them:
string line; while (getline(cin, line)) {
The idea here is that line
is not meaningfully initialized until the
first call to getline
, so why not put them on the same line, even
though it's two separate statements? I know that pedantic IDEs will
send me to the corner for that, but this isn't production code.
Same goes for variables initialized from a stream using >>
:
int one, two; ss >> one >> two;
C++ doesn't have a "module" concept, nor does it have inner functions. This means that any variables which are shared at a scope larger than local have to be in a class or have to be global. And of course, within a library, global variables are kind of dangerous and significant, so they're often indicated using uppercase. But in these self-contained puzzles, I didn't bother with different casing for them, since the only reason I went global was because I didn't have inner functions.
In many cases, I was able to use lambdas to do the job of inner functions.