re: AoC Day 13: Mine Cart Madness VIEW POST

FULL DISCUSSION
 

Perl solution. Most of the decisions are represented by the hash tables at the beginning of the code:

#!/usr/bin/perl
use warnings;
use strict;
use feature qw{ say };

use List::Util qw{ first };

use enum qw( X Y FACING TURN );
use enum qw( LEFT STRAIGHT RIGHT );
use constant {
    MOVE => {
        '<' => [ -1,  0 ],
        '>' => [  1,  0 ],
        'v' => [  0,  1 ],
        '^' => [  0, -1 ],
    },
    BEND => {
        '^/'  => '>',
        '^\\' => '<',
        'v/'  => '<',
        'v\\' => '>',
        '</'  => 'v',
        '<\\' => '^',
        '>/'  => '^',
        '>\\' => 'v',
    },
    FACES => [ '^', '>', 'v', '<' ],
};

my (@map, @carts, %crash);
while (<>) {
    chomp;
    while (/([<>^v])/g) {
        push @carts, [ pos() - 1, $. - 1, $1, LEFT ];
        ++$crash{ $carts[-1][X] }{ $carts[-1][Y] };
    }
    s/[<>]/-/g;
    s/[v^]/|/g;
    push @map, [split //, $_, -1];
}

while (1) {
    for my $cart (
        sort { $a->[Y] <=> $b->[Y] || $a->[X] <=> $b->[X] } @carts
    ) {
        --$crash{ $cart->[X] }{ $cart->[Y] };
        my $move = MOVE->{ $cart->[FACING] };
        $cart->[$_] += $move->[$_] for X, Y;
        if ($crash{ $cart->[X] }{ $cart->[Y] }++) {
            say "$cart->[X],$cart->[Y]";
            exit
        }

        my $current = $map[ $cart->[Y] ][ $cart->[X] ];
        next if $current =~ /[-|]/;

        if ('+' eq $current) {
            my $face_index = first { $cart->[FACING] eq FACES->[$_] }
                             0 .. $#{(FACES)};
            $face_index += (-1, 0, 1)[ $cart->[TURN] ];
            $cart->[FACING] = FACES->[ $face_index % 4 ];
            ++$cart->[TURN];
            $cart->[TURN] %= 3;

        } else {
            $cart->[FACING] = BEND->{ $cart->[FACING] . $current };
        }
    }
}

In part 2, I just replaced the code that printed the collision with a new one that removes the two carts involved.

#!/usr/bin/perl
use warnings;
use strict;
use feature qw{ say };

use List::Util qw{ first };

use enum qw( X Y FACING TURN );
use enum qw( LEFT STRAIGHT RIGHT );
use constant {
    MOVE => {
        '<' => [ -1,  0 ],
        '>' => [  1,  0 ],
        'v' => [  0,  1 ],
        '^' => [  0, -1 ],
    },
    BEND => {
        '^/'  => '>',
        '^\\' => '<',
        'v/'  => '<',
        'v\\' => '>',
        '</'  => 'v',
        '<\\' => '^',
        '>/'  => '^',
        '>\\' => 'v',
    },
    FACES => [ '^', '>', 'v', '<' ],
};

my @map;
my @carts;
my %crash;
while (<>) {
    chomp;
    while (/([<>^v])/g) {
        push @carts, [ pos() - 1, $. - 1, $1, LEFT ];
        ++$crash{ $carts[-1][X] }{ $carts[-1][Y] };
    }
    s/[<>]/-/g;
    s/[v^]/|/g;
    push @map, [split //, $_, -1];
}

while (1) {
    for my $cart (
        sort { $a->[Y] <=> $b->[Y] || $a->[X] <=> $b->[X] } @carts
    ) {
        next unless $cart->[FACING];

        --$crash{ $cart->[X] }{ $cart->[Y] };
        my $move = MOVE->{ $cart->[FACING] };
        $cart->[$_] += $move->[$_] for X, Y;
        if ($crash{ $cart->[X] }{ $cart->[Y] }++) {
            $crash{ $cart->[X] }{ $cart->[Y] } -= 2;
            $cart->[FACING] = 0;
            my $other_cart = first {
                $_->[FACING] && $_->[X] == $cart->[X] && $_->[Y] == $cart->[Y]
            } @carts;
            $other_cart->[FACING] = 0;
            next
        }

        my $current = $map[ $cart->[Y] ][ $cart->[X] ];
        next if $current =~ /[-|]/;

        if ('+' eq $current) {
            my $face_index = first { $cart->[FACING] eq FACES->[$_] }
                             0 .. $#{(FACES)};
            $face_index += (-1, 0, 1)[ $cart->[TURN] ];
            $cart->[FACING] = FACES->[ $face_index % 4 ];
            ++$cart->[TURN];
            $cart->[TURN] %= 3;

        } else {
            $cart->[FACING] = BEND->{ $cart->[FACING] . $current };
        }
    }

    my @left = grep $carts[$_][FACING], 0 .. $#carts;
    next unless 1 == @left;

    say join ',', @{ $carts[ $left[0] ] }[X, Y];
    exit
}
code of conduct - report abuse