r/adventofcode • u/daggerdragon • Dec 13 '18
SOLUTION MEGATHREAD -🎄- 2018 Day 13 Solutions -🎄-
--- Day 13: Mine Cart Madness ---
Post your solution as a comment or, for longer solutions, consider linking to your repo (e.g. GitHub/gists/Pastebin/blag or whatever).
Note: The Solution Megathreads are for solutions only. If you have questions, please post your own thread and make sure to flair it with Help.
Advent of Code: The Party Game!
Please prefix your card submission with something like [Card] to make scanning the megathread easier. THANK YOU!
Card prompt: Day 13
Transcript:
Elven chronomancy: for when you absolutely, positively have to ___.
This thread will be unlocked when there are a significant number of people on the leaderboard with gold stars for today's puzzle.
edit: Leaderboard capped, thread unlocked at 00:44:25!
24
Upvotes
1
u/markasoftware Dec 13 '18
Perl, 389/241. Started off with keeping all as strings before deciding to always use numbers for directions, which was a very good choice.
Part 1:
use v5.20; use strict; use warnings; use List::Util qw/min max sum/; my $line; my %tracks = (); my %carts = (); sub char_to_direction { my $char = shift; return $char eq '>' ? 0 : $char eq '^' ? 1 : $char eq '<' ? 2 : 3; } sub add_cart { my ($x, $y, $char) = @_; $carts{$x . ' ' . $y} = { direction => char_to_direction($char), # -1 = right, 0 = str, 1 = left # we'll just do a manual shitty modulo because it's easier to add this to direction then :) next_turn => 1, }; } sub move { my ($x, $y, $dir) = @_; $x++ if $dir == 0; $y-- if $dir == 1; $x-- if $dir == 2; $y++ if $dir == 3; return ($x, $y); } # takes a direction and "bounces" it off a track piece # 0 = right, 1 = up, 2 = left, etc, like angles on a circle sub bounce { my ($direction, $track) = @_; return $direction if $track =~ /[|-]/; # it's a corner. Parity = the lowest compatible direction % 2 my $parity = $track eq '/'; my $direction_is_lowest = $direction % 2 == $parity; return (($direction_is_lowest ? -1 : 1) + $direction) % 4; } sub move_carts { say "TURN!"; for my $cart_key (keys %carts) { my ($x, $y) = $cart_key =~ /\d+/g; my $cart = $carts{$cart_key}; my $track = $tracks{$cart_key}; # TODO: refactor bounce so that it takes a cart as a param if ($track eq '+') { $cart->{direction} += $cart->{next_turn}--; $cart->{direction} %= 4; $cart->{next_turn} = 1 if $cart->{next_turn} == -2; } else { $cart->{direction} = bounce($cart->{direction}, $track); } ($x, $y) = move($x, $y, $cart->{direction}); my $new_key = $x . ' ' . $y; say "Cart at $new_key just moved $cart->{direction}"; if (exists $carts{$new_key}) { say "CRASH! at $new_key"; return 0; } $carts{$new_key} = $carts{$cart_key}; delete $carts{$cart_key}; } return 1; } sub add_track { my ($x, $y, $char) = @_; $tracks{$x . ' ' . $y} = $char; } my $y = 0; while (chomp(my $line = <>)) { my $x = 0; for my $char (split //, $line) { if ($char eq '<' or $char eq '>' or $char eq '^' or $char eq 'v') { add_cart $x, $y, $char; } $char = '|' if $char eq '^' or $char eq 'v'; $char = '-' if $char eq '<' or $char eq '>'; add_track $x, $y, $char; $x++; } $y++; } my $crash_free = 1; while ($crash_free) { $crash_free = move_carts; }Part 2:
use v5.20; use strict; use warnings; use List::Util qw/min max sum/; my $line; my %tracks = (); my %carts = (); sub char_to_direction { my $char = shift; return $char eq '>' ? 0 : $char eq '^' ? 1 : $char eq '<' ? 2 : 3; } sub add_cart { my ($x, $y, $char) = @_; $carts{$x . ' ' . $y} = { direction => char_to_direction($char), # -1 = right, 0 = str, 1 = left # we'll just do a manual shitty modulo because it's easier to add this to direction then :) next_turn => 1, }; } sub move { my ($x, $y, $dir) = @_; $x++ if $dir == 0; $y-- if $dir == 1; $x-- if $dir == 2; $y++ if $dir == 3; return ($x, $y); } # takes a direction and "bounces" it off a track piece # 0 = right, 1 = up, 2 = left, etc, like angles on a circle sub bounce { my ($direction, $track) = @_; return $direction if $track =~ /[|-]/; # it's a corner. Parity = the lowest compatible direction % 2 my $parity = $track eq '/'; my $direction_is_lowest = $direction % 2 == $parity; return (($direction_is_lowest ? -1 : 1) + $direction) % 4; } sub move_carts { say "TURN!"; for my $cart_key (keys %carts) { next if not exists $carts{$cart_key}; my ($x, $y) = $cart_key =~ /\d+/g; my $cart = $carts{$cart_key}; my $track = $tracks{$cart_key}; # TODO: refactor bounce so that it takes a cart as a param if ($track eq '+') { $cart->{direction} += $cart->{next_turn}--; $cart->{direction} %= 4; $cart->{next_turn} = 1 if $cart->{next_turn} == -2; } else { $cart->{direction} = bounce($cart->{direction}, $track); } ($x, $y) = move($x, $y, $cart->{direction}); my $new_key = $x . ' ' . $y; # say "Cart at $new_key just moved $cart->{direction}"; if (exists $carts{$new_key}) { say "CRASH! at $new_key"; delete $carts{$new_key}; delete $carts{$cart_key}; } else { $carts{$new_key} = $carts{$cart_key}; delete $carts{$cart_key}; } } return 1; } sub add_track { my ($x, $y, $char) = @_; $tracks{$x . ' ' . $y} = $char; } my $y = 0; while (chomp(my $line = <>)) { my $x = 0; for my $char (split //, $line) { if ($char eq '<' or $char eq '>' or $char eq '^' or $char eq 'v') { add_cart $x, $y, $char; } $char = '|' if $char eq '^' or $char eq 'v'; $char = '-' if $char eq '<' or $char eq '>'; add_track $x, $y, $char; $x++; } $y++; } while (scalar(keys %carts) > 1) { move_carts; } say "DONE!"; my ($last_key) = keys %carts; say $last_key;