Compare commits

...

10 Commits

Author SHA1 Message Date
be223b6cef t Merge branch '2023-08' 2023-12-09 15:31:32 -05:00
d6ed288ea9 part 2 2023-12-09 15:31:25 -05:00
d1d38ba623 wip 2023-12-09 15:05:07 -05:00
450ac404f1 wip 2023-12-09 13:04:13 -05:00
9856545a59 Merge branch '2023-09' 2023-12-09 13:03:42 -05:00
09db491ae8 preset 2023-12-09 13:02:55 -05:00
66b259d3a2 part 2 2023-12-09 13:02:55 -05:00
c446579923 part 1 done, part2 wip 2023-12-09 13:02:55 -05:00
692e0301e7 part 1 wip 2023-12-08 10:52:54 -05:00
c7b8b6a8c8 prettier 2023-12-08 10:35:08 -05:00
15 changed files with 324 additions and 29 deletions

View File

@ -4,36 +4,38 @@ package Part1;
use List::AllUtils qw/ /; use List::AllUtils qw/ /;
sub parse_input($input) { sub parse_input ($input) {
my ( $directions, undef, @nodes ) = split "\n", $input; my ( $directions, undef, @nodes ) = split "\n", $input;
$directions = [ split "", $directions =~ s/R/1/gr =~ s/L/0/gr ]; $directions = [ split "", $directions =~ s/R/1/gr =~ s/L/0/gr ];
my %nodes; my %nodes;
for(@nodes) { for (@nodes) {
my @n = /([A-Z]+)/g; my @n = /([A-Z\d]+)/g;
$nodes{ shift @n } = \@n; $nodes{ shift @n } = \@n;
} }
return { return {
directions => $directions, directions => $directions,
nodes => \%nodes }; nodes => \%nodes
};
} }
sub solution_1 ($input) { sub solution_1 ($input) {
my $p = parse_input($input); my $p = parse_input($input);
my @directions = $p->{directions}->@*; my @directions = $p->{directions}->@*;
my %nodes = $p->{nodes}->%*; my %nodes = $p->{nodes}->%*;
my $visited = 0; my $visited = 0;
my $next_index = 0; my $next_index = 0;
my $current = 'AAA'; my $current = 'AAA';
while( $current ne 'ZZZ') { while ( $current ne 'ZZZ' ) {
$visited++; $visited++;
$current = $nodes{$current}->[ $directions[$next_index++ % @directions ] ]; $current =
$nodes{$current}->[ $directions[ $next_index++ % @directions ] ];
} }
return $visited; return $visited;

View File

@ -4,11 +4,124 @@ package Part2;
use Part1; use Part1;
use List::AllUtils qw/ /; use List::AllUtils qw/all first_index none min max product /;
use List::UtilsBy qw/ min_by max_by /;
use Math::Utils qw/ lcm /;
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;
}
}
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;
}
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;
}
sub solution_2 ($input) { sub solution_2 ($input) {
...; my $p = Part1::parse_input($input);
my @directions = $p->{directions}->@*;
my %nodes = $p->{nodes}->%*;
my $steps = 0;
my @paths = grep { /A$/ } keys %nodes;
my $next_index = 0;
my @equations = map { equation_for($_,\@directions,\%nodes) } @paths;
return lcm map { $_->{b} } @equations;
for(@equations) {
$_->{i} = 1;
$_->{total} = $_->{b}+$_->{m};
}
until( all { $_->{total} == $equations[0]->{total} } @equations ) {
my $i = max map { $_->{total} } @equations;
for(@equations) {
while( $_->{total}<$i) {
$_->{total}+=$_->{m};
}
}
# use DDP; p @equations;
}
$equations[0]->{total};
} }
1; 1;

View File

@ -9,8 +9,8 @@ use File::Serialize;
use Part1; use Part1;
use Part2; use Part2;
my $day = path('.')->absolute->basename =~ s/^0//r; my $day = path('.')->absolute->basename =~ s/^0//r;
my $year = path('.')->absolute->parent->basename; my $year = path('.')->absolute->parent->basename;
my $solutions = deserialize_file('solutions.yml'); my $solutions = deserialize_file('solutions.yml');
my @parts = ( my @parts = (
@ -36,6 +36,7 @@ for my $part (@parts) {
language => 'perl', language => 'perl',
part => $part->{part}, part => $part->{part},
time => $res->cpu_a / $res->iters, time => $res->cpu_a / $res->iters,
persec => $res->iters / $res->cpu_a,
timestamp => DateTime->now->iso8601, timestamp => DateTime->now->iso8601,
}; };
say to_json $result; say to_json $result;

View File

@ -6,20 +6,19 @@ use Path::Tiny;
use File::Serialize; use File::Serialize;
use Part1; use Part1;
use Part2;
my $input = path('input')->slurp; my $input = path('input')->slurp;
my $example = path('example')->slurp; my $example = path('example')->slurp;
my %solutions = deserialize_file('solutions.yml')->%*; my %solutions = deserialize_file('solutions.yml')->%*;
my $parsed = Part1::parse_input($example); my $parsed = Part1::parse_input($example);
use DDP; p $parsed; is $parsed->{directions} => [ 1, 0 ];
is $parsed->{nodes}{AAA} => [qw/ BBB CCC /];
is $parsed->{directions} => [1,0]; is Part1::solution_1($example) => 2;
is $parsed->{nodes}{AAA} => [ qw/ BBB CCC /]; is Part1::solution_1(<<'END') => 6;
is Part1::solution_1($example) => 2;
is Part1::solution_1(<<'END') => 6;
LLR LLR
AAA = (BBB, BBB) AAA = (BBB, BBB)
@ -27,11 +26,10 @@ BBB = (AAA, ZZZ)
ZZZ = (ZZZ, ZZZ) ZZZ = (ZZZ, ZZZ)
END END
SKIP: { SKIP: {
# skip "not there yet" if $solutions{1} eq 'TODO'; # skip "not there yet" if $solutions{1} eq 'TODO';
is Part1::solution_1($input) => $solutions{1}; is Part1::solution_1($input) => $solutions{1};
} }
done_testing; done_testing;

View File

@ -3,11 +3,42 @@ use 5.38.0;
use Test2::V0; use Test2::V0;
use Path::Tiny; use Path::Tiny;
use File::Serialize;
use Part2; use Part2;
my $input = path('input')->slurp; my $input = path('input')->slurp;
my $example = <<END;
LR
is Part2::solution_2($input) => 'TODO'; 11A = (11B, XXX)
11B = (XXX, 11Z)
11Z = (11B, XXX)
22A = (22B, XXX)
22B = (22C, 22C)
22C = (22Z, 22Z)
22Z = (22B, 22B)
XXX = (XXX, XXX)
END
my %solutions = deserialize_file('solutions.yml')->%*;
my $parsed = Part1::parse_input($example);
#is [Part2::get_cycle('11A',$parsed->{directions},$parsed->{nodes})] => [1,2];
##use DDP; my @x = Part2::get_cycle('22A',$parsed->{directions},$parsed->{nodes});p @x;
#is [Part2::get_cycle('22A',$parsed->{directions},$parsed->{nodes})] => [1,2,3];
#is Part2::solution_2($example) => 6;
$parsed = Part1::parse_input($input);
# my @initial = grep { /A$/ } keys $parsed->{nodes}->%*;
# for (@initial ) {
# say join " ", Part2::get_cycle($_,$parsed->{directions},$parsed->{nodes});
# }
is Part2::solution_2($input) => $solutions{2};
done_testing; done_testing;

View File

@ -1,2 +1,2 @@
1: 19631 1: 19631
2: TODO 2: 21003205388413

24
2023/09/Part1.pm Normal file
View File

@ -0,0 +1,24 @@
use 5.38.0;
package Part1;
use List::AllUtils qw/ all sum /;
sub predict(@entries) {
my $sum = 0;
until( all { !$_ } @entries ) {
$sum += $entries[-1];
@entries = map { $entries[$_]-$entries[$_-1] } 1..$#entries;
}
return $sum;
}
sub solution_1 ($input) {
my @lines = map { [split]} split "\n", $input;
return sum map { predict(@$_) } @lines;
}
1;

32
2023/09/Part2.pm Normal file
View File

@ -0,0 +1,32 @@
use 5.38.0;
package Part2;
use Part1;
use List::AllUtils qw/ all sum /;
sub predict(@entries) {
my $sum = 0;
my @first = ();
until( all { !$_ } @entries ) {
push @first, $entries[0];
@entries = map { $entries[$_]-$entries[$_-1] } 1..$#entries;
}
while(@first) {
$sum = pop( @first ) - $sum;
}
return $sum;
}
sub solution_2 ($input) {
my @lines = map { [split]} split "\n", $input;
return sum map { predict(@$_) } @lines;
}
1;

44
2023/09/benchmark.pl Normal file
View File

@ -0,0 +1,44 @@
use 5.38.0;
use Benchmark ':hireswallclock';
use Path::Tiny;
use JSON qw/ to_json /;
use DateTime;
use File::Serialize;
use Part1;
use Part2;
my $day = path('.')->absolute->basename =~ s/^0//r;
my $year = path('.')->absolute->parent->basename;
my $solutions = deserialize_file('solutions.yml');
my @parts = (
{ part => 1, sub => \&Part1::solution_1, expected => $solutions->{1} },
{ part => 2, sub => \&Part2::solution_2, expected => $solutions->{2} },
);
my $input = path('./input')->slurp;
for my $part (@parts) {
my $res = Benchmark::countit(
10,
sub {
$part->{sub}->($input) == $part->{expected} or die;
}
);
my $result = {
day => $day,
year => $year,
#variant => '',
language => 'perl',
part => $part->{part},
time => $res->cpu_a / $res->iters,
persec =>$res->iters/$res->cpu_a ,
timestamp => DateTime->now->iso8601,
};
say to_json $result;
}

17
2023/09/part1.t Normal file
View File

@ -0,0 +1,17 @@
use 5.38.0;
use Test2::V0;
use Path::Tiny;
use Part1;
my $input = path('input')->slurp;
is Part1::predict(qw/0 3 6 9 12 15/) => 18;
is Part1::predict(qw/1 3 6 10 15 21/) => 28;
is Part1::predict(qw/10 13 16 21 30 45/) => 68;
is Part1::solution_1($input) => 1884768153;
done_testing;

24
2023/09/part2.t Normal file
View File

@ -0,0 +1,24 @@
use 5.38.0;
use Test2::V0;
use Path::Tiny;
use Part2;
my $input = path('input')->slurp;
is Part2::predict(qw/0 3 6 9 12 15/) => -3;
is Part2::predict(qw/1 3 6 10 15 21/) => 0;
is Part2::predict(qw/10 13 16 21 30 45/) => 5;
is Part2::solution_2(<<END) => 2;
0 3 6 9 12 15
1 3 6 10 15 21
10 13 16 21 30 45
END
isnt Part2::solution_2($input) => -59;
is Part2::solution_2($input) => 1031;
done_testing;

2
2023/09/solutions.yml Normal file
View File

@ -0,0 +1,2 @@
1: 1884768153
2: 1031

View File

@ -16,3 +16,8 @@
{"year":"2023","part":2,"language":"perl","day":"6","time":7.07875059716474e-06,"timestamp":"2023-12-06T15:43:13","persec":141267.867298578} {"year":"2023","part":2,"language":"perl","day":"6","time":7.07875059716474e-06,"timestamp":"2023-12-06T15:43:13","persec":141267.867298578}
{"language":"perl","persec":85.2380952380952,"year":"2023","timestamp":"2023-12-07T16:08:30","time":0.011731843575419,"part":1,"day":"7"} {"language":"perl","persec":85.2380952380952,"year":"2023","timestamp":"2023-12-07T16:08:30","time":0.011731843575419,"part":1,"day":"7"}
{"day":"7","part":2,"persec":85.2380952380952,"year":"2023","timestamp":"2023-12-07T16:08:43","time":0.011731843575419,"language":"perl"} {"day":"7","part":2,"persec":85.2380952380952,"year":"2023","timestamp":"2023-12-07T16:08:43","time":0.011731843575419,"language":"perl"}
{"persec":113.488372093023,"timestamp":"2023-12-09T17:57:35","language":"perl","year":"2023","time":0.00881147540983607,"day":"9","part":1}
{"persec":109.783631232361,"timestamp":"2023-12-09T17:57:47","language":"perl","time":0.00910882604970008,"day":"9","part":2,"year":"2023"}
{"day":"8","persec":131.374407582938,"language":"perl","part":1,"time":0.00761183261183261,"timestamp":"2023-12-09T19:45:23","year":"2023"}
{"day":"8","language":"perl","time":0.0874789915966387,"year":"2023","timestamp":"2023-12-09T20:31:05","persec":11.431316042267,"part":2}

1
2023/cpanfile Normal file
View File

@ -0,0 +1 @@
requires 'Math::Utils';

View File

@ -9,8 +9,8 @@ use File::Serialize;
use Part1; use Part1;
use Part2; use Part2;
my $day = path('.')->absolute->basename =~ s/^0//r; my $day = path('.')->absolute->basename =~ s/^0//r;
my $year = path('.')->absolute->parent->basename; my $year = path('.')->absolute->parent->basename;
my $solutions = deserialize_file('solutions.yml'); my $solutions = deserialize_file('solutions.yml');
my @parts = ( my @parts = (
@ -36,6 +36,7 @@ for my $part (@parts) {
language => 'perl', language => 'perl',
part => $part->{part}, part => $part->{part},
time => $res->cpu_a / $res->iters, time => $res->cpu_a / $res->iters,
persec => $res->iters / $res->cpu_a,
timestamp => DateTime->now->iso8601, timestamp => DateTime->now->iso8601,
}; };
say to_json $result; say to_json $result;