I did Advent of Code again, and had a
good time. Spoilers.
In 2018 I started in Rust and floundered. In 2019 I did it all in
Perl. For 2020 I started in Rust but moved on to Perl when the
problems started to get a bit more challenging (particularly since
there was a lot of text parsing involved and I know that idiom well in
Perl).
Rust does seem more verbose. Where 2a in Perl was
my $valid=0;
while (<>) {
chomp;
if (/^([0-9]+)-([0-9]+) ([a-z]): ([a-z]+)$/) {
my ($min,$max,$char,$pw)=($1,$2,$3,$4);
my %ph;
map {$ph{$_}++} split '',$pw;
if ($ph{$char} >= $min && $ph{$char} <= $max) {
$valid++;
}
} else {
die "invalid input $_\n";
}
}
print "$valid\n";
Rust takes about twice as many lines, and three times as many
characters, with:
use std::env;
use std::fs;
use std::collections::HashMap;
use regex::Regex;
fn main() {
let args: Vec<String> = env::args().collect();
let re=Regex::new(r"^([0-9]+)-([0-9]+) ([a-z]): ([a-z]+)$").unwrap();
let mut valid=0;
for i in 1..args.len() {
let contents=fs::read_to_string(args[i].clone())
.expect("file read err");
for line in contents.lines() {
for mat in re.captures_iter(line) {
let mut pw: HashMap<String, i32> = HashMap::new();
for chr in mat[4].chars() {
let cc=chr.to_string();
let mut n=1;
if pw.contains_key(&cc) {
n=pw[&cc]+1;
}
pw.insert(cc,n);
}
let ci=mat[3].to_string();
if pw.contains_key(&ci) {
if pw[&ci] >= mat[1].parse::<i32>().unwrap() &&
pw[&ci] <= mat[2].parse::<i32>().unwrap() {
valid += 1;
}
}
}
}
}
println!("{}",valid);
}
There's probably a more Rust-idiomatic way to do it, but…
It took until day 10 to get what I think of as a "classic" AoC
problem, one which would lead to a combinatorial explosion if tackled
naively.
Day 13 was the first one where it proved necessary to learn about
something I hadn't met before. Of course, once I had, there was
already library code that would immediately solve the problem.
Day 15 part 2 felt like bait for people going for the first-to-solve
scoreboards. (I don't, because the problems come out at about 5am UK
time and I'm usually not awake then.) If my part 1 solution ran in
0.015s (which it did) the same code should solve the 15,000× larger
part 2 in ~200s (rather less, because the timing for part 1 includes
startup time). Which is quite possibly faster than I can write
something cleverer, so it's at least worth starting it while I’m
looking at the pattern of results and thinking about other ways to
solve the problem.
Day 16 was probably my favourite; it reminded me a bit of
Sudoku-solving code I've written, though fortunately with only one
solving algorithm needed (if there's only one field that can match a
specific key, remove the other keys from that field; repeat until
solved).
Day 17 was inevitable, I suppose, but misquoting Johnson I am tired of
Life. Still, it turned out that going to three dimensions needed only
a very small tweak to the code.
Day 18 was surprisingly light: oh, an expression parser, using a
different precedence order so that you can't just use library code.
Fair enough.
Day 19: I am writing in Perl, so all shall be regular expressions!
(But I did special-case part 2 rather than writing a general
solution, because you can't backref a match count even in Perl.)
Day 20 was suddenly lacking in fun. It looks as though people took two
approaches to part 1: either work out the entire tiling problem, or
take the short-cut of working out that a corner tile must have exactly
two unique border values. The latter is what I did, and it solved part
1 very quickly; but that meant that part 2 involved writing all that
tile assembly code and then looking for the pattern, and I suffered
a failure of enthusiasm.
On the other hand, for day 21 I thought I'd spotted a short cut for
part 1 but it didn't work, so I ended up building what turned out to
be the part 2 solution and deriving the part 1 answer from that. (Same
general sort of idea as 20, so I'm a little surprised these were put
next to each other.)
Day 22: surprisingly lightweight so late in the day.
Day 23: no, it's not a thing like last year's questions where you have
to analyse the pattern and calculate only the tiny bits you need: it's
just a question of building an efficient data structure and working it
out in full.
Day 24: ooh, it's hexagonal grid Life. See comments on day 17. The
trick I use for hex grid coordinate calculations is to double the
easier axis scale, so that you never have to worry about offsets for
the alternating rows.
Day 25: fun, but… not exactly climactic. Perhaps I'm unreasonable to
be disappointed with that conclusion, but I am.
Overall, I think I didn't enjoy it as much as 2019's puzzles, but that
may simply be because there wasn't a continuing thematic element –
although the Intcode puzzles last year only made up nine out of the
25, they provided a feeling of progress and development which was
lacking this time. But I still enjoyed these, in particular the
Meretzky-inspired style of humour (author of the best of the classic
Infocom games), and I expect to do next year's set too.
Comments on this post are now closed. If you have particular grounds for adding a late comment, comment on a more recent post quoting the URL of this one.