2023-12-08 15:31:44 +00:00
|
|
|
use 5.38.0;
|
|
|
|
|
|
|
|
package Part2;
|
|
|
|
|
|
|
|
use Part1;
|
|
|
|
|
2023-12-09 20:31:25 +00:00
|
|
|
use List::AllUtils qw/all first_index none min max product /;
|
|
|
|
use List::UtilsBy qw/ min_by max_by /;
|
|
|
|
use Math::Utils qw/ lcm /;
|
2023-12-09 16:47:37 +00:00
|
|
|
|
|
|
|
sub get_cycle( $current, $directions, $nodes ) {
|
|
|
|
|
|
|
|
my @tracks;
|
|
|
|
my $next_index = 0;
|
|
|
|
|
|
|
|
while() {
|
|
|
|
my $t = join '-', $current,$next_index;
|
|
|
|
my $i = first_index { $_ eq $t } @tracks;
|
|
|
|
if( $i > -1 ) {
|
|
|
|
my $c = 0;
|
|
|
|
# p @tracks;
|
|
|
|
# warn $i, " ",$t;
|
|
|
|
return $i, map {
|
|
|
|
$c++;
|
|
|
|
if(/Z-/) {
|
|
|
|
my $x = $c; $c = 0; $x;
|
|
|
|
}else {
|
|
|
|
()
|
|
|
|
}
|
|
|
|
} splice @tracks, $i;
|
|
|
|
}
|
|
|
|
push @tracks, $t;
|
|
|
|
$current = $nodes->{$current}[ $directions->[ $next_index ] ];
|
|
|
|
$next_index = ( $next_index+1)% @$directions;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
2023-12-08 15:31:44 +00:00
|
|
|
|
2023-12-09 20:05:07 +00:00
|
|
|
sub find_z($current,$next_index,$directions,$nodes) {
|
|
|
|
|
|
|
|
my $visited = 0;
|
|
|
|
|
|
|
|
while ( ) {
|
|
|
|
$visited++;
|
|
|
|
|
|
|
|
$current =
|
|
|
|
$nodes->{$current}[ $directions->[ $next_index++ % @$directions ] ];
|
|
|
|
|
|
|
|
last if $current =~ /Z$/
|
|
|
|
}
|
|
|
|
|
|
|
|
return $visited, $current, $next_index;
|
|
|
|
}
|
|
|
|
sub speedrun($current,$next_index,$directions,$nodes,$n) {
|
|
|
|
|
|
|
|
$current =
|
|
|
|
$nodes->{$current}[ $directions->[ $next_index++ % @$directions ] ]
|
|
|
|
for 1..$n;
|
|
|
|
|
|
|
|
return $current;
|
|
|
|
}
|
|
|
|
|
2023-12-09 20:31:25 +00:00
|
|
|
sub equation_for($current,$directions,$nodes) {
|
|
|
|
|
|
|
|
my $visited = 0;
|
|
|
|
my $next_index=0;
|
|
|
|
|
|
|
|
while ( ) {
|
|
|
|
$visited++;
|
|
|
|
|
|
|
|
$current =
|
|
|
|
$nodes->{$current}[ $directions->[ $next_index++ % @$directions ] ];
|
|
|
|
|
|
|
|
last if $current =~ /Z$/
|
|
|
|
}
|
|
|
|
|
|
|
|
my $first = $visited;
|
|
|
|
$visited = 0;
|
|
|
|
|
|
|
|
while ( ) {
|
|
|
|
$visited++;
|
|
|
|
|
|
|
|
$current =
|
|
|
|
$nodes->{$current}[ $directions->[ $next_index++ % @$directions ] ];
|
|
|
|
|
|
|
|
last if $current =~ /Z$/
|
|
|
|
}
|
|
|
|
|
|
|
|
my $entry = { b => $first, m => $visited };
|
|
|
|
return $entry;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-12-08 15:31:44 +00:00
|
|
|
sub solution_2 ($input) {
|
2023-12-08 15:52:54 +00:00
|
|
|
my $p = Part1::parse_input($input);
|
|
|
|
my @directions = $p->{directions}->@*;
|
|
|
|
my %nodes = $p->{nodes}->%*;
|
|
|
|
|
2023-12-09 20:05:07 +00:00
|
|
|
my $steps = 0;
|
|
|
|
my @paths = grep { /A$/ } keys %nodes;
|
|
|
|
my $next_index = 0;
|
2023-12-08 15:52:54 +00:00
|
|
|
|
2023-12-09 20:31:25 +00:00
|
|
|
my @equations = map { equation_for($_,\@directions,\%nodes) } @paths;
|
2023-12-08 15:52:54 +00:00
|
|
|
|
2023-12-09 20:31:25 +00:00
|
|
|
return lcm map { $_->{b} } @equations;
|
2023-12-08 15:52:54 +00:00
|
|
|
|
2023-12-09 20:31:25 +00:00
|
|
|
for(@equations) {
|
|
|
|
$_->{i} = 1;
|
|
|
|
$_->{total} = $_->{b}+$_->{m};
|
|
|
|
}
|
2023-12-09 16:47:37 +00:00
|
|
|
|
2023-12-09 20:31:25 +00:00
|
|
|
until( all { $_->{total} == $equations[0]->{total} } @equations ) {
|
|
|
|
my $i = max map { $_->{total} } @equations;
|
|
|
|
|
|
|
|
for(@equations) {
|
|
|
|
while( $_->{total}<$i) {
|
|
|
|
$_->{total}+=$_->{m};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
# use DDP; p @equations;
|
|
|
|
}
|
2023-12-08 15:31:44 +00:00
|
|
|
|
2023-12-09 20:31:25 +00:00
|
|
|
$equations[0]->{total};
|
2023-12-09 20:05:07 +00:00
|
|
|
}
|
2023-12-08 15:52:54 +00:00
|
|
|
|
|
|
|
1;
|