/ domm

I hack Perl for fun and profit

Follow me on twitter!
Atom Icom ... on Atom!
03.01.2021: Bulk downloading all episodes of a podcast
12.12.2020: Advent of Code Day 12 - sailing to a pause
11.12.2020: Advent of Code Day 11 - slow SeatGoL
10.12.2020: Advent of Code Day 10 - trillion jolts
09.12.2020: Advent of Code Day 9 - while learning
08.12.2020: Advent of Code Day 8 - running code
07.12.2020: Advent of Code Day 7 - baggy recursion
06.12.2020: Advent of Code Day 6 - simple counting
05.12.2020: Advent of Code Day 5 - hard fail

Today I failed quite hard. Instead of thinking what the task was really about (binary numbers), I just stupidly followed the instructions, and wasted 45min on a not-working string/arithmetic based monstrosity that did not even work because I had a lot of one-off errors.

Part 1

I took a short break and planned the weekend shopping, and then cooked up an also quite stupid array-based solution in 11:27min. But at least I got valid results for the test data, and also for the proper input.

After taking a run in the afternoon I (finally!) realized that I just need to convert the input to zeros and ones, and then convert this binary number to an int:

my $max=0;
while (<>) {
    tr/FBLR/0101/;
    my $id = eval '0b'.substr($_, 0, 7).' * 8 + 0b'.substr($_, 7, 3);
    $max = $id if $id > $max;
}
say $max;

I use tr, which is a Perl operator to *tr*ade chars in a string: the first char in the first part is replaced by the first char in the second part, and so on. This way I can easily convert the input into the more useful 0s and 1s.

Then I can just prefix the 001010 with 0b and eval the string (I know I should use pack() for this, but I wasn't in the mood to read the manpage..).

Golf

Now that we have a reasonable short solution, we can golf it a bit more to:

while(<>){tr/FBLR/0101/;s/(.{7})(.{3})/'0b'.$1.'*8+0b'.$2/ee;if($_>$a){$a=$_}}say$a;

Instead of using substr to extract the row and set spec, I use a regex replacement, and in the replacement and use the nice double-e flag /ee to evaluate the result twice. The first eval will prepare a string like 0b1001010*8+0b010, and the second eval will calculate this expression and return the seat ID.

Part 2

The one benefit of my stupid approach for part 1 was that it was very easy to just generate a "map" of the plane, remove all the occupied seats, and then just print out the remaining seats.

my %plane;
for my $r (0 .. 128) {
    for my $s (0..7) {
        $plane{$r.'_'.$s}='X';
    }
}
# ...
    delete $plane{$row.'_'.$seat};
# ...
    warn Data::Dumper::Dumper \%plane;

This allowed me to immediately spot my seat (73/3)! Sometimes it's easier to use the big computer behind my eyes for simple pattern recognition instead to come up with a coded solution (of course this does not scale very well..)

Stats & Links

Comments (via senph)

04.12.2020: Advent of Code Day 4 - validating regex
>>>>>>>>>>
<