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:
Makefilesample.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.txtThere'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.