RogerBW's Blog

Advent of Code 2020 07 January 2021

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.

See also:
Advent of Code 2019

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.

Search
Archive
Tags 1920s 1930s 1940s 1950s 1960s 1970s 1980s 1990s 2000s 2010s 2300ad 3d printing action advent of code aeronautics aikakirja anecdote animation anime army astronomy audio audio tech base commerce battletech bayern beer boardgaming book of the week bookmonth chain of command children chris chronicle church of no redeeming virtues cold war comedy computing contemporary cornish smuggler cosmic encounter coup covid-19 crime crystal cthulhu eternal cycling dead of winter doctor who documentary drama driving drone ecchi economics en garde espionage essen 2015 essen 2016 essen 2017 essen 2018 essen 2019 essen 2022 essen 2023 essen 2024 existential risk falklands war fandom fanfic fantasy feminism film firefly first world war flash point flight simulation food garmin drive gazebo genesys geocaching geodata gin gkp gurps gurps 101 gus harpoon historical history horror hugo 2014 hugo 2015 hugo 2016 hugo 2017 hugo 2018 hugo 2019 hugo 2020 hugo 2021 hugo 2022 hugo 2023 hugo 2024 hugo-nebula reread in brief avoid instrumented life javascript julian simpson julie enfield kickstarter kotlin learn to play leaving earth linux liquor lovecraftiana lua mecha men with beards mpd museum music mystery naval noir non-fiction one for the brow opera parody paul temple perl perl weekly challenge photography podcast politics postscript powers prediction privacy project woolsack pyracantha python quantum rail raku ranting raspberry pi reading reading boardgames social real life restaurant reviews romance rpg a day rpgs ruby rust scala science fiction scythe second world war security shipwreck simutrans smartphone south atlantic war squaddies stationery steampunk stuarts suburbia superheroes suspense television the resistance the weekly challenge thirsty meeples thriller tin soldier torg toys trailers travel type 26 type 31 type 45 vietnam war war wargaming weather wives and sweethearts writing about writing x-wing young adult
Special All book reviews, All film reviews
Produced by aikakirja v0.1