AoC 2022/5 - Insane crane

TL;DR

On with Advent of Code puzzle 5 from 2022: “Just shove a bezoar down their throats”!

This is one of those challenges where there is an epiphany. Well, I know that this is supposed to happen in about one month in the christian calendar and we’re literally in advent, but still it’s a revelation.

In this case, it told me that I’m too old for this wit.

The puzzle input is something liket this:

    [D]    
[N] [C]    
[Z] [M] [P]
 1   2   3 

move 1 from 2 to 1
move 3 from 1 to 3
move 2 from 2 to 1
move 1 from 1 to 2

The first part (before the empty line) is a graphical depiction of an arrangement of stuff in columns (represented by numbers at the base), which could just as well be represented like this instead:

1 N Z
2 M C D
3 P

Then there is a sequence of moves, which could just as well be represented like this instead:

1 2 1
3 1 3
2 2 1
1 1 2

Having the engineer mindset, of course I set for parsing the whole thing. There’s some subtlety in the inputs, too, in that the second part is extremely easy to parse (with Raku, or Perl, or most of other modern languages I guess), so it feels like it’s only half of the work to be done.

It’s even subtler, IMHO, in that my full input (and anyone’s else, I guess) has 9 stacks, so each of them has a 1-digit identifier. Which makes both the first and the second half parseable by simply reading from the same exact positions in each part of the input.

After solving it, of course there’s the lateral thinking of so many bright people that goes along these lines:

Should I spend several minutes coding a general parsing routine for my input, or should I just hardcode it in my code in 30 seconds and only parse the second part?

I guess you know the answer.

So there’s been two epiphanies, actually, the second being that I don’t do this for the points (I never got any, by the way) I do this for the fun and the joy of getting better at Raku.

Yes, yes… The Fox and the Grapes.

OK, the flip side of it is that I do have a working parsing routine, that I can share here:

sub get-inputs ($filename) {
   my @lines = $filename.IO.lines;
   my $inputs = {};

   my @stacks = [''],;
   while @lines {
      my $line = @lines.shift;
      last if $line ~~ /^ \s* $/;
      next if $line !~~ / \[ /;
      my $i = 1;
      while $line.chars >= 3 {
         my $char = $line.substr(1, 1);
         @stacks[$i].unshift($char) if $char ne ' ';
         $line.substr-rw(0, 4) = '';
         ++$i;
      }
   }
   $inputs<stacks> = @stacks;

   $inputs<moves> = @lines.map({ [.comb(/\d+/)] }).Array;

   return $inputs;
}

We’re getting all @lines from the file at once here, because I don’t know how to get some lines here, then get some lines there. Well, I should, but I don’t.

Reading at fixed positions is not really my go-to solution, so I’m chopping stuff from the input lines and getting the relevant character on the way. Well, it’s sort of reading at fixed positions, actually.

I’m not sure I like the substr/substr-rw pair in Raku; maybe I just have to understand them, but it seems that the single substr from Perl was a bit easier to use for doing their jobs at the same time.

Reading the moves finally goes the dirty way. No input checking, just get all sequence of numbers from each line.

The solution to the first part is just playing with stacks, i.e. push here what you pop there:

sub part1 ($inputs) {
   my $data = $inputs<stacks>.deepmap(*.clone);
   for $inputs<moves>.Slip -> $move {
      my ($amount, $from, $to) = @$move;
      $data[$to].push: $data[$from].pop for ^$amount;
   }
   $data»[*-1].join('');
}

The second part is an interesting occasion to do some exercise with slicing:

sub part2 ($inputs) {
   my $data = $inputs<stacks>.deepmap(*.clone);
   for $inputs<moves>.Slip -> $move {
      my ($amount, $from, $to) = @$move;
      $data[$to].push: $data[$from][*-$amount .. *-1].Slip;
      $data[$from][*-$amount .. *-1]:delete;
   }
   $data»[*-1].join('');
}

The good thing is that, this time, all the Slips I put did not harm. I’m still not too sure all of them are needed, but the code works with them and they were not an afterthought.

Full solution.

Stay safe!


Comments? Octodon, Twitter, GitHub, Reddit, or drop me a line!