Compare commits
No commits in common. "919f966ec350dd595409dc07a1cc6a1fac612346" and "0ebf67a5cc015bda8bea7c89447b03a9a4aad364" have entirely different histories.
919f966ec3
...
0ebf67a5cc
3
.gitignore
vendored
3
.gitignore
vendored
@ -7,6 +7,3 @@ pnpm-lock.yaml
|
|||||||
*_LOCAL_*
|
*_LOCAL_*
|
||||||
*_REMOTE_*
|
*_REMOTE_*
|
||||||
*.orig
|
*.orig
|
||||||
deno.lock
|
|
||||||
input
|
|
||||||
solutions.yml
|
|
||||||
|
@ -1,41 +0,0 @@
|
|||||||
package Part1;
|
|
||||||
|
|
||||||
use 5.36.0;
|
|
||||||
use experimental 'declared_refs';
|
|
||||||
|
|
||||||
no warnings qw/ uninitialized /;
|
|
||||||
|
|
||||||
use List::AllUtils qw/ sum all /;
|
|
||||||
|
|
||||||
sub read_input ($file) {
|
|
||||||
my( $ordering, $manuals ) = split "\n\n", $file->slurp;
|
|
||||||
|
|
||||||
$ordering = [ map {
|
|
||||||
[ split '\|' ]
|
|
||||||
} split "\n", $ordering ];
|
|
||||||
|
|
||||||
$manuals = [ split "\n", $manuals ];
|
|
||||||
|
|
||||||
return { ordering => $ordering, manuals => $manuals };
|
|
||||||
}
|
|
||||||
|
|
||||||
sub good_manual( $ordering, $manual ) {
|
|
||||||
return all {
|
|
||||||
my $m = $_;
|
|
||||||
my ($i,$j) = map { index $manual, $m->[$_] } 0..1;
|
|
||||||
return 1 unless all { $_ > -1 } $i, $j;
|
|
||||||
return $i <= $j;
|
|
||||||
} @$ordering;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub solve ($input) {
|
|
||||||
return sum
|
|
||||||
map {
|
|
||||||
my @m = split ',';
|
|
||||||
$m[@m/2];
|
|
||||||
}
|
|
||||||
grep { good_manual($input->{ordering},$_) }
|
|
||||||
$input->{manuals}->@*;
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
@ -1,63 +0,0 @@
|
|||||||
use lib '.';
|
|
||||||
|
|
||||||
use Part1;
|
|
||||||
|
|
||||||
package Part2;
|
|
||||||
|
|
||||||
use 5.36.0;
|
|
||||||
use experimental 'declared_refs';
|
|
||||||
|
|
||||||
no warnings qw/ uninitialized /;
|
|
||||||
use List::AllUtils qw/ sum /;
|
|
||||||
|
|
||||||
sub read_input ($file) {
|
|
||||||
my ( $ordering, $manuals ) = split "\n\n", $file->slurp;
|
|
||||||
|
|
||||||
$ordering = [ map { [ split '\|' ] } split "\n", $ordering ];
|
|
||||||
|
|
||||||
$manuals = [ split "\n", $manuals ];
|
|
||||||
|
|
||||||
return { ordering => $ordering, manuals => $manuals };
|
|
||||||
}
|
|
||||||
|
|
||||||
use List::AllUtils qw/ first_index all /;
|
|
||||||
|
|
||||||
sub reshuffle_manual ( $ordering, $manual ) {
|
|
||||||
my @m = split ',', $manual;
|
|
||||||
|
|
||||||
my @ordering = grep {
|
|
||||||
my @o = @$_;
|
|
||||||
my $i = first_index { $_ == $o[0] } @m;
|
|
||||||
my $j = first_index { $_ == $o[1] } @m;
|
|
||||||
all { $_ > -1 } $i, $j;
|
|
||||||
} @$ordering;
|
|
||||||
|
|
||||||
my $redo = 1;
|
|
||||||
while ($redo) {
|
|
||||||
$redo = 0;
|
|
||||||
for my \@o(@ordering) {
|
|
||||||
my $i = first_index { $_ == $o[0] } @m;
|
|
||||||
my $j = first_index { $_ == $o[1] } @m;
|
|
||||||
|
|
||||||
next if $i < $j;
|
|
||||||
|
|
||||||
$redo = 1;
|
|
||||||
@m[ $i, $j ] = @m[ $j, $i ];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return join ',', @m;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub solve ($input) {
|
|
||||||
return sum
|
|
||||||
map {
|
|
||||||
my @m = split ',';
|
|
||||||
$m[ @m / 2 ];
|
|
||||||
}
|
|
||||||
map { reshuffle_manual( $input->{ordering}, $_ ) }
|
|
||||||
grep { !Part1::good_manual( $input->{ordering}, $_ ) }
|
|
||||||
$input->{manuals}->@*;
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
@ -1,28 +0,0 @@
|
|||||||
47|53
|
|
||||||
97|13
|
|
||||||
97|61
|
|
||||||
97|47
|
|
||||||
75|29
|
|
||||||
61|13
|
|
||||||
75|53
|
|
||||||
29|13
|
|
||||||
97|29
|
|
||||||
53|29
|
|
||||||
61|53
|
|
||||||
97|53
|
|
||||||
61|29
|
|
||||||
47|13
|
|
||||||
75|47
|
|
||||||
97|75
|
|
||||||
47|61
|
|
||||||
75|61
|
|
||||||
47|29
|
|
||||||
75|13
|
|
||||||
53|13
|
|
||||||
|
|
||||||
75,47,61,53,29
|
|
||||||
97,61,53,29,13
|
|
||||||
75,29,13
|
|
||||||
75,97,47,61,53
|
|
||||||
61,13,29
|
|
||||||
97,13,75,29,47
|
|
@ -1,25 +0,0 @@
|
|||||||
use lib qw~ . ~;
|
|
||||||
|
|
||||||
use Part1;
|
|
||||||
use Part2;
|
|
||||||
|
|
||||||
use Test2::V0;
|
|
||||||
use Path::Tiny;
|
|
||||||
use File::Serialize;
|
|
||||||
|
|
||||||
my $solutions = deserialize_file './solutions.yml';
|
|
||||||
|
|
||||||
my $sample = -f 'sample' && Part1::read_input( path('sample') );
|
|
||||||
my $input= -f 'input' && Part1::read_input( path('input') );
|
|
||||||
|
|
||||||
subtest 'part 1' => sub {
|
|
||||||
is Part1::solve($sample) => 143;
|
|
||||||
is Part1::solve($input) => $solutions->{part1};
|
|
||||||
};
|
|
||||||
|
|
||||||
subtest 'part 2' => sub {
|
|
||||||
is Part2::solve($sample) => 123;
|
|
||||||
is Part2::solve($input) => $solutions->{part2};
|
|
||||||
};
|
|
||||||
|
|
||||||
done_testing();
|
|
@ -1,65 +0,0 @@
|
|||||||
package Part1;
|
|
||||||
|
|
||||||
use Math::Vector::Real;
|
|
||||||
use 5.36.0;
|
|
||||||
|
|
||||||
no warnings qw/ uninitialized /;
|
|
||||||
|
|
||||||
sub read_input ($file) {
|
|
||||||
my @grid = map { [ split '' ] } $file->lines({chomp=>1});
|
|
||||||
return \@grid;
|
|
||||||
}
|
|
||||||
|
|
||||||
my @directions = map { V(@$_) } [-1,0], [ 0,1], [1,0], [0,-1];
|
|
||||||
|
|
||||||
sub find_guard($grid) {
|
|
||||||
for my $i (0..$grid->$#* ) {
|
|
||||||
for my $j ( 0..$grid->[0]->$#* ) {
|
|
||||||
return V($i,$j) if $grid->[$i][$j] eq '^';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
die "didn't find the guard!";
|
|
||||||
}
|
|
||||||
|
|
||||||
use List::AllUtils qw/ any /;
|
|
||||||
|
|
||||||
sub inside_grid($grid,$guard) {
|
|
||||||
return 0 if any { $_ < 0 } @$guard;
|
|
||||||
return $grid->[$guard->[0]][$guard->[1]];
|
|
||||||
}
|
|
||||||
|
|
||||||
sub solve ($grid) {
|
|
||||||
use DDP;
|
|
||||||
my $guard = find_guard($grid);
|
|
||||||
my $current_direction = 0;
|
|
||||||
|
|
||||||
use Clone qw/ clone /;
|
|
||||||
$grid = clone($grid);
|
|
||||||
|
|
||||||
my %seen;
|
|
||||||
$seen{"$guard"}++;
|
|
||||||
|
|
||||||
while() {
|
|
||||||
my $ahead = V(@$guard) + $directions[$current_direction];
|
|
||||||
last unless inside_grid($grid,$ahead);
|
|
||||||
if( $grid->[$ahead->[0]][$ahead->[1]] eq '#' ) {
|
|
||||||
$current_direction++;
|
|
||||||
$current_direction %= @directions;
|
|
||||||
redo;
|
|
||||||
}
|
|
||||||
$guard = $ahead;
|
|
||||||
$seen{"$guard"}++;
|
|
||||||
$grid->[$ahead->[0]][$ahead->[1]] = 'X';
|
|
||||||
}
|
|
||||||
use DDP;
|
|
||||||
# p %seen;
|
|
||||||
# p $guard;
|
|
||||||
# for my $l ( @$grid ) {
|
|
||||||
# say join '', @$l;
|
|
||||||
# }
|
|
||||||
|
|
||||||
return scalar keys %seen;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
@ -1,74 +0,0 @@
|
|||||||
|
|
||||||
use 5.36.0;
|
|
||||||
use lib '.';
|
|
||||||
|
|
||||||
use DDP;
|
|
||||||
|
|
||||||
use Part1;
|
|
||||||
|
|
||||||
package Part2;
|
|
||||||
|
|
||||||
use Math::Vector::Real;
|
|
||||||
use List::AllUtils qw/ uniq /;
|
|
||||||
|
|
||||||
my @directions = map { V(@$_) } [ -1, 0 ], [ 0, 1 ], [ 1, 0 ], [ 0, -1 ];
|
|
||||||
|
|
||||||
sub copy_grid ($grid) {
|
|
||||||
return [ map { [@$_] } @$grid ];
|
|
||||||
}
|
|
||||||
|
|
||||||
sub add_vectors($x,$y) {
|
|
||||||
return [ $x->[0]+$y->[0],$x->[1]+$y->[1]];
|
|
||||||
}
|
|
||||||
|
|
||||||
sub do_the_round ($grid) {
|
|
||||||
my $guard = Part1::find_guard($grid);
|
|
||||||
my $current_direction = 0;
|
|
||||||
|
|
||||||
my %seen;
|
|
||||||
|
|
||||||
my $loop = 0;
|
|
||||||
|
|
||||||
while () {
|
|
||||||
my $ahead = $guard + $directions[$current_direction];
|
|
||||||
last unless Part1::inside_grid( $grid, $ahead );
|
|
||||||
if ( $grid->[ $ahead->[0] ][ $ahead->[1] ] eq '#' ) {
|
|
||||||
$current_direction++;
|
|
||||||
$current_direction %= @directions;
|
|
||||||
redo;
|
|
||||||
}
|
|
||||||
$guard = $ahead;
|
|
||||||
if ( $seen{"$guard"}{$current_direction} ) {
|
|
||||||
$loop = 1;
|
|
||||||
last;
|
|
||||||
}
|
|
||||||
$seen{"$guard"}{$current_direction}++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
loop => $loop,
|
|
||||||
seen => [
|
|
||||||
keys %seen
|
|
||||||
]
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
sub solve ($grid) {
|
|
||||||
my $guard = Part1::find_guard($grid);
|
|
||||||
my $current_direction = 0;
|
|
||||||
|
|
||||||
my $r = do_the_round($grid);
|
|
||||||
|
|
||||||
my $loops = 0;
|
|
||||||
|
|
||||||
for my $loc ( grep { $grid->[ $_->[0] ][ $_->[1] ] ne '^' }
|
|
||||||
map { [/(\d+)/g] } $r->{seen}->@* ) {
|
|
||||||
my $copy = copy_grid($grid);
|
|
||||||
$copy->[ $loc->[0] ][ $loc->[1] ] = '#';
|
|
||||||
$loops++ if do_the_round($copy)->{loop};
|
|
||||||
}
|
|
||||||
|
|
||||||
return $loops;
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
@ -1,22 +0,0 @@
|
|||||||
#!/usr/bin/env perl
|
|
||||||
|
|
||||||
use 5.36.0;
|
|
||||||
|
|
||||||
use Benchmark qw/ timethis timeit /;
|
|
||||||
|
|
||||||
use lib qw~ . ~;
|
|
||||||
|
|
||||||
use Part1;
|
|
||||||
use Part2;
|
|
||||||
|
|
||||||
use Path::Tiny;
|
|
||||||
use File::Serialize;
|
|
||||||
|
|
||||||
my $sample = -f 'sample' && Part1::read_input( path('sample') );
|
|
||||||
my $input= -f 'input' && Part1::read_input( path('input') );
|
|
||||||
|
|
||||||
my $res;
|
|
||||||
$res = timeit(0, sub { Part1::solve($input) });
|
|
||||||
say "part 1: ", $res->cpu_a/$res->iters;
|
|
||||||
$res = timeit(0, sub { Part2::solve($input) });
|
|
||||||
say "part 2: ", $res->cpu_a/$res->iters;
|
|
@ -1,10 +0,0 @@
|
|||||||
....#.....
|
|
||||||
.........#
|
|
||||||
..........
|
|
||||||
..#.......
|
|
||||||
.......#..
|
|
||||||
..........
|
|
||||||
.#..^.....
|
|
||||||
........#.
|
|
||||||
#.........
|
|
||||||
......#...
|
|
@ -1,27 +0,0 @@
|
|||||||
#!/usr/bin/env perl
|
|
||||||
|
|
||||||
use lib qw~ . ~;
|
|
||||||
|
|
||||||
use Part1;
|
|
||||||
use Part2;
|
|
||||||
|
|
||||||
use Test2::V0;
|
|
||||||
use Path::Tiny;
|
|
||||||
use File::Serialize;
|
|
||||||
|
|
||||||
my $solutions = deserialize_file './solutions.yml';
|
|
||||||
|
|
||||||
my $sample = -f 'sample' && Part1::read_input( path('sample') );
|
|
||||||
my $input= -f 'input' && Part1::read_input( path('input') );
|
|
||||||
|
|
||||||
subtest 'part 1' => sub {
|
|
||||||
is Part1::solve($sample) => 41;
|
|
||||||
is Part1::solve($input) => $solutions->{part1};
|
|
||||||
};
|
|
||||||
|
|
||||||
subtest 'part 2' => sub {
|
|
||||||
is Part2::solve($sample) => 6;
|
|
||||||
# is Part2::solve($input) => $solutions->{part2};
|
|
||||||
};
|
|
||||||
|
|
||||||
done_testing();
|
|
@ -1,29 +0,0 @@
|
|||||||
use 5.36.0;
|
|
||||||
|
|
||||||
package Part1;
|
|
||||||
|
|
||||||
use List::AllUtils qw/ sum /;
|
|
||||||
|
|
||||||
no warnings qw/ uninitialized /;
|
|
||||||
|
|
||||||
sub read_input ($file) {
|
|
||||||
return [ map { [ split /[: ]+/ ] } $file->lines( { chomp => 1 } ) ];
|
|
||||||
}
|
|
||||||
|
|
||||||
sub valid_equation ( $total, @numbers ) {
|
|
||||||
return $numbers[0] == $total if @numbers == 1;
|
|
||||||
|
|
||||||
return 0 if $numbers[0] > $total;
|
|
||||||
|
|
||||||
my $i = shift @numbers;
|
|
||||||
my $j = shift @numbers;
|
|
||||||
return 1 if valid_equation( $total, $i*$j, @numbers );
|
|
||||||
return 1 if valid_equation( $total, $i+$j, @numbers );
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub solve ($equations) {
|
|
||||||
return sum map { $_->[0] } grep { valid_equation(@$_) } @$equations;
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
@ -1,27 +0,0 @@
|
|||||||
use lib '.';
|
|
||||||
|
|
||||||
use Part1;
|
|
||||||
|
|
||||||
package Part2;
|
|
||||||
|
|
||||||
use List::AllUtils qw/ sum /;
|
|
||||||
use 5.36.0;
|
|
||||||
|
|
||||||
sub valid_equation ( $total, @numbers ) {
|
|
||||||
return $numbers[0] == $total if @numbers == 1;
|
|
||||||
|
|
||||||
return 0 if $numbers[0] > $total;
|
|
||||||
|
|
||||||
my $i = shift @numbers;
|
|
||||||
my $j = shift @numbers;
|
|
||||||
return 1 if valid_equation( $total, "$i$j", @numbers );
|
|
||||||
return 1 if valid_equation( $total, $i*$j, @numbers );
|
|
||||||
return 1 if valid_equation( $total, $i+$j, @numbers );
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub solve ($equations) {
|
|
||||||
return sum map { $_->[0] } grep { valid_equation(@$_) } @$equations;
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
@ -1,9 +0,0 @@
|
|||||||
190: 10 19
|
|
||||||
3267: 81 40 27
|
|
||||||
83: 17 5
|
|
||||||
156: 15 6
|
|
||||||
7290: 6 8 6 15
|
|
||||||
161011: 16 10 13
|
|
||||||
192: 17 8 14
|
|
||||||
21037: 9 7 18 13
|
|
||||||
292: 11 6 16 20
|
|
@ -1,27 +0,0 @@
|
|||||||
use lib qw~ . ~;
|
|
||||||
|
|
||||||
use Part1;
|
|
||||||
use Part2;
|
|
||||||
|
|
||||||
use Test2::V0;
|
|
||||||
use Path::Tiny;
|
|
||||||
use File::Serialize;
|
|
||||||
|
|
||||||
my $solutions = deserialize_file './solutions.yml';
|
|
||||||
|
|
||||||
my $sample = -f 'sample' && Part1::read_input( path('sample') );
|
|
||||||
my $input= -f 'input' && Part1::read_input( path('input') );
|
|
||||||
|
|
||||||
subtest 'part 1' => sub {
|
|
||||||
is Part1::solve($sample) => 3749;
|
|
||||||
|
|
||||||
ok Part1::solve($input) > 14711898485202;
|
|
||||||
is Part1::solve($input) => $solutions->{part1};
|
|
||||||
};
|
|
||||||
|
|
||||||
subtest 'part 2' => sub {
|
|
||||||
is Part2::solve($sample) => 11387;
|
|
||||||
is Part2::solve($input) => $solutions->{part2};
|
|
||||||
};
|
|
||||||
|
|
||||||
done_testing();
|
|
@ -1,33 +0,0 @@
|
|||||||
use 5.36.0;
|
|
||||||
|
|
||||||
package Grid;
|
|
||||||
|
|
||||||
use Moo;
|
|
||||||
|
|
||||||
has grid => ( is => 'ro' );
|
|
||||||
|
|
||||||
has dimensions => is => 'lazy',
|
|
||||||
default => sub ($self) {
|
|
||||||
return [ 0 + $self->{grid}->@*, 0 + $self->{grid}[0]->@* ];
|
|
||||||
};
|
|
||||||
|
|
||||||
sub get($self,$i,$j) {
|
|
||||||
return $self->grid->[$i][$j];
|
|
||||||
}
|
|
||||||
|
|
||||||
sub foreach($self,$sub) {
|
|
||||||
for my $l ( 0..$self->dimensions->[0]-1) {
|
|
||||||
|
|
||||||
for my $c ( 0..$self->dimensions->[1]-1) {
|
|
||||||
$sub->($l,$c,$self->get($l,$c));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub is_inside($self,$i,$j) {
|
|
||||||
return 0 if $i < 0 or $j < 0;
|
|
||||||
return 0 if $i >= $self->dimensions->[0];
|
|
||||||
return 0 if $j >= $self->dimensions->[1];
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
1;
|
|
@ -1,49 +0,0 @@
|
|||||||
use lib qw/ . /;
|
|
||||||
|
|
||||||
package Part1;
|
|
||||||
|
|
||||||
use 5.36.0;
|
|
||||||
|
|
||||||
use List::AllUtils qw/ uniq /;
|
|
||||||
use Math::Vector::Real;
|
|
||||||
use Algorithm::Combinatorics qw(permutations variations);
|
|
||||||
use Grid;
|
|
||||||
|
|
||||||
no warnings qw/ uninitialized /;
|
|
||||||
|
|
||||||
sub read_input ($file) {
|
|
||||||
Grid->new( grid =>[
|
|
||||||
map { [ split '' ] }
|
|
||||||
$file->lines({chomp=>1}) ]);
|
|
||||||
}
|
|
||||||
|
|
||||||
sub find_antinodes($grid,@group) {
|
|
||||||
my %antinodes;
|
|
||||||
my $iter = variations(\@group,2);
|
|
||||||
while( my $p = $iter->next ) {
|
|
||||||
my( $x, $y) = @$p;
|
|
||||||
my $new = 2*$y-$x;
|
|
||||||
$antinodes{$new}++ if $grid->is_inside(@$new);
|
|
||||||
}
|
|
||||||
return keys %antinodes;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub solve ($grid) {
|
|
||||||
my %groups;
|
|
||||||
|
|
||||||
$grid->foreach( sub($l,$r,$content) {
|
|
||||||
return if $content eq '.';
|
|
||||||
my $g = ( $groups{$content} //= [] );
|
|
||||||
push @$g, V($l,$r);
|
|
||||||
});
|
|
||||||
|
|
||||||
my %antinodes;
|
|
||||||
|
|
||||||
for my $group ( values %groups ) {
|
|
||||||
$antinodes{$_}++ for find_antinodes($grid,@$group);
|
|
||||||
}
|
|
||||||
|
|
||||||
return scalar keys %antinodes;
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
@ -1,47 +0,0 @@
|
|||||||
use lib '.';
|
|
||||||
use 5.36.0;
|
|
||||||
|
|
||||||
use Part1;
|
|
||||||
|
|
||||||
package Part2;
|
|
||||||
|
|
||||||
use List::AllUtils qw/ uniq /;
|
|
||||||
use Math::Vector::Real;
|
|
||||||
use Algorithm::Combinatorics qw(permutations variations variations_with_repetition);
|
|
||||||
use Grid;
|
|
||||||
|
|
||||||
sub find_antinodes($grid,@group) {
|
|
||||||
my %antinodes;
|
|
||||||
my $iter = variations(\@group,2);
|
|
||||||
while( my $p = $iter->next ) {
|
|
||||||
my( $x, $y) = @$p;
|
|
||||||
my $delta = $y - $x;
|
|
||||||
$y = V(@$y);
|
|
||||||
|
|
||||||
while( $grid->is_inside(@$y) ) {
|
|
||||||
$antinodes{$y}++;
|
|
||||||
$y+=$delta;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return keys %antinodes;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub solve ($grid) {
|
|
||||||
my %groups;
|
|
||||||
|
|
||||||
$grid->foreach( sub($l,$r,$content) {
|
|
||||||
return if $content eq '.';
|
|
||||||
my $g = ( $groups{$content} //= [] );
|
|
||||||
push @$g, V($l,$r);
|
|
||||||
});
|
|
||||||
|
|
||||||
my %antinodes;
|
|
||||||
|
|
||||||
for my $group ( values %groups ) {
|
|
||||||
$antinodes{$_}++ for find_antinodes($grid,@$group);
|
|
||||||
}
|
|
||||||
|
|
||||||
return scalar keys %antinodes;
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
@ -1,12 +0,0 @@
|
|||||||
............
|
|
||||||
........0...
|
|
||||||
.....0......
|
|
||||||
.......0....
|
|
||||||
....0.......
|
|
||||||
......A.....
|
|
||||||
............
|
|
||||||
............
|
|
||||||
........A...
|
|
||||||
.........A..
|
|
||||||
............
|
|
||||||
............
|
|
@ -1,25 +0,0 @@
|
|||||||
use lib qw~ . ~;
|
|
||||||
|
|
||||||
use Part1;
|
|
||||||
use Part2;
|
|
||||||
|
|
||||||
use Test2::V0;
|
|
||||||
use Path::Tiny;
|
|
||||||
use File::Serialize;
|
|
||||||
|
|
||||||
my $solutions = deserialize_file './solutions.yml';
|
|
||||||
|
|
||||||
my $sample = -f 'sample' && Part1::read_input( path('sample') );
|
|
||||||
my $input= -f 'input' && Part1::read_input( path('input') );
|
|
||||||
|
|
||||||
subtest 'part 1' => sub {
|
|
||||||
is Part1::solve($sample) => 14;
|
|
||||||
is Part1::solve($input) => $solutions->{part1};
|
|
||||||
};
|
|
||||||
|
|
||||||
subtest 'part 2' => sub {
|
|
||||||
is Part2::solve($sample) => 34;
|
|
||||||
is Part2::solve($input) => $solutions->{part2};
|
|
||||||
};
|
|
||||||
|
|
||||||
done_testing();
|
|
@ -1,39 +0,0 @@
|
|||||||
package Part1;
|
|
||||||
|
|
||||||
use 5.36.0;
|
|
||||||
|
|
||||||
no warnings qw/ uninitialized /;
|
|
||||||
|
|
||||||
sub read_input ($file) {
|
|
||||||
my $i = 0;
|
|
||||||
my $data = 1;
|
|
||||||
my $x = [
|
|
||||||
map { ( ( $data++ % 2 ) ? $i++ : -1 ) x $_ }
|
|
||||||
split '', $file->slurp
|
|
||||||
];
|
|
||||||
return $x;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub solve (@disk) {
|
|
||||||
use DDP;
|
|
||||||
|
|
||||||
my $i = -1;
|
|
||||||
|
|
||||||
while( ++$i < $#disk ) {
|
|
||||||
pop @disk while $disk[-1] == -1;
|
|
||||||
|
|
||||||
next unless $disk[$i] == -1;
|
|
||||||
|
|
||||||
$disk[$i] = pop @disk;
|
|
||||||
}
|
|
||||||
|
|
||||||
my $checksum = 0;
|
|
||||||
|
|
||||||
$i = 0;
|
|
||||||
$checksum += $i++ * $_ for @disk;
|
|
||||||
|
|
||||||
return $checksum;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
@ -1,71 +0,0 @@
|
|||||||
use lib '.';
|
|
||||||
|
|
||||||
use Part1;
|
|
||||||
|
|
||||||
package Part2;
|
|
||||||
|
|
||||||
use 5.36.0;
|
|
||||||
|
|
||||||
sub read_input ($file) {
|
|
||||||
my $i = 0;
|
|
||||||
my $data = 1;
|
|
||||||
my $x = [
|
|
||||||
map { [ ( $data++ % 2 ) ? $i++ : -1, $_ ] }
|
|
||||||
split '', $file->slurp
|
|
||||||
];
|
|
||||||
return $x;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
sub print_disk(@disk) {
|
|
||||||
for (@disk) {
|
|
||||||
my @a = ($_->[0] == -1 ? '.':$_->[0]) x $_->[1];
|
|
||||||
print @a;
|
|
||||||
}
|
|
||||||
print "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
sub my_first_index($max,@disk) {
|
|
||||||
my $i = -1;
|
|
||||||
while(++$i < $max ) {
|
|
||||||
return $i if $_->[0] == -1 and $_->[1] >= $disk[$i][1];
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub solve (@disk) {
|
|
||||||
use DDP;
|
|
||||||
|
|
||||||
my $i = @disk;
|
|
||||||
|
|
||||||
use List::MoreUtils qw/ first_index /;
|
|
||||||
|
|
||||||
while( --$i >= 0 ) {
|
|
||||||
next if $i > $#disk;
|
|
||||||
|
|
||||||
next if $disk[$i][0] == -1;
|
|
||||||
|
|
||||||
my $swap = first_index {
|
|
||||||
$_->[0] == -1 and $_->[1] >= $disk[$i][1];
|
|
||||||
} @disk;
|
|
||||||
|
|
||||||
next if $swap == -1 or $swap >= $i;
|
|
||||||
|
|
||||||
$disk[$swap][1] -= $disk[$i][1];
|
|
||||||
splice @disk, $swap, 0, [ $disk[$i]->@* ];
|
|
||||||
$disk[++$i][0] = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
my $checksum = 0;
|
|
||||||
|
|
||||||
$i = 0;
|
|
||||||
while( my $p = shift @disk ) {
|
|
||||||
$checksum += $i++ * ( $_ == -1 ? 0 : $_ ) for ( $p->[0]) x $p->[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $checksum;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
@ -1 +0,0 @@
|
|||||||
2333133121414131402
|
|
@ -1,28 +0,0 @@
|
|||||||
use lib qw~ . ~;
|
|
||||||
|
|
||||||
use Part1;
|
|
||||||
use Part2;
|
|
||||||
|
|
||||||
use Test2::V0;
|
|
||||||
use Path::Tiny;
|
|
||||||
use File::Serialize;
|
|
||||||
|
|
||||||
my $solutions = deserialize_file './solutions.yml';
|
|
||||||
|
|
||||||
my $sample = -f 'sample' && Part1::read_input( path('sample') );
|
|
||||||
my $input= -f 'input' && Part1::read_input( path('input') );
|
|
||||||
|
|
||||||
subtest 'part 1' => sub {
|
|
||||||
skip_all;
|
|
||||||
is Part1::solve(@$sample) => 1928;
|
|
||||||
is Part1::solve(@$input) => $solutions->{part1};
|
|
||||||
};
|
|
||||||
|
|
||||||
subtest 'part 2' => sub {
|
|
||||||
my $sample = -f 'sample' && Part2::read_input( path('sample') );
|
|
||||||
my $input= -f 'input' && Part2::read_input( path('input') );
|
|
||||||
is Part2::solve(@$sample) => 2858;
|
|
||||||
is Part2::solve(@$input) => $solutions->{part2};
|
|
||||||
};
|
|
||||||
|
|
||||||
done_testing();
|
|
@ -1,58 +0,0 @@
|
|||||||
use lib qw/ . /;
|
|
||||||
use lib qw! ../../perl-lib !;
|
|
||||||
|
|
||||||
use 5.36.0;
|
|
||||||
use AoC::Puzzle;
|
|
||||||
|
|
||||||
package Part1;
|
|
||||||
|
|
||||||
use Moo;
|
|
||||||
|
|
||||||
use AoC::Grid;
|
|
||||||
use List::AllUtils qw/ sum /;
|
|
||||||
|
|
||||||
extends 'AoC::Puzzle';
|
|
||||||
|
|
||||||
has '+input', default => sub ($self) {
|
|
||||||
AoC::Grid->new( string => $self->file_slurp );
|
|
||||||
};
|
|
||||||
|
|
||||||
sub trailhead_score ( $self, $x, $y ) {
|
|
||||||
|
|
||||||
my $grid = $self->input;
|
|
||||||
my %endpoints;
|
|
||||||
|
|
||||||
my @points = ( [ $x, $y, 0 ] );
|
|
||||||
|
|
||||||
while ( my $p = shift @points ) {
|
|
||||||
if ( $p->[2] == 9 ) {
|
|
||||||
$endpoints{ join ':', @$p }++;
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
my $v = $p->[2] + 1;
|
|
||||||
push @points,
|
|
||||||
map { [ @$_, $v ] }
|
|
||||||
grep { $grid->get(@$_) == $v }
|
|
||||||
$grid->ortho_neighbors( $p->@[ 0, 1 ] );
|
|
||||||
}
|
|
||||||
|
|
||||||
return $self->trailhead_score_resolution(%endpoints);
|
|
||||||
}
|
|
||||||
|
|
||||||
sub trailhead_score_resolution ( $self, %endpoints ) {
|
|
||||||
return scalar keys %endpoints;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub solve ($self) {
|
|
||||||
my @points;
|
|
||||||
|
|
||||||
$self->input->foreach(
|
|
||||||
sub ( $x, $y, $v ) {
|
|
||||||
push @points, [ $x, $y ] if $v == 0;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return sum map { $self->trailhead_score(@$_) } @points;
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
@ -1,19 +0,0 @@
|
|||||||
use lib qw/ . /;
|
|
||||||
use lib qw! ../../perl-lib !;
|
|
||||||
|
|
||||||
use 5.36.0;
|
|
||||||
|
|
||||||
package Part2;
|
|
||||||
|
|
||||||
use Moo;
|
|
||||||
|
|
||||||
use AoC::Grid;
|
|
||||||
use List::AllUtils qw/ sum /;
|
|
||||||
|
|
||||||
extends 'Part1';
|
|
||||||
|
|
||||||
sub trailhead_score_resolution($self,%endpoints) {
|
|
||||||
return sum values %endpoints;
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
@ -1,8 +0,0 @@
|
|||||||
89010123
|
|
||||||
78121874
|
|
||||||
87430965
|
|
||||||
96549874
|
|
||||||
45678903
|
|
||||||
32019012
|
|
||||||
01329801
|
|
||||||
10456732
|
|
@ -1,22 +0,0 @@
|
|||||||
use lib qw~ . ~;
|
|
||||||
|
|
||||||
use Part1;
|
|
||||||
use Part2;
|
|
||||||
|
|
||||||
use Test2::V0;
|
|
||||||
use Path::Tiny;
|
|
||||||
use File::Serialize;
|
|
||||||
|
|
||||||
my $solutions = deserialize_file './solutions.yml';
|
|
||||||
|
|
||||||
subtest 'part 1' => sub {
|
|
||||||
is( Part1->new(file=>'sample')->solve() => 36 );
|
|
||||||
is( Part1->new(file=>'input')->solve() => $solutions->{part1} );
|
|
||||||
};
|
|
||||||
|
|
||||||
subtest 'part 2' => sub {
|
|
||||||
is( Part2->new(file=>'sample')->solve() => 81 );
|
|
||||||
is( Part2->new(file=>'input')->solve() => $solutions->{part2});
|
|
||||||
};
|
|
||||||
|
|
||||||
done_testing();
|
|
@ -1,3 +1 @@
|
|||||||
requires 'Math::VectorXYZ';
|
requires 'Math::VectorXYZ';
|
||||||
requires 'Math::VectorXYZ::XS';
|
|
||||||
requires 'Algorithm::Combinatorics';
|
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"tasks": {
|
|
||||||
"dev": "deno run --watch main.ts"
|
|
||||||
},
|
|
||||||
"imports": {
|
|
||||||
"@std/assert": "jsr:@std/assert@1"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,56 +0,0 @@
|
|||||||
use 5.36.0;
|
|
||||||
|
|
||||||
package AoC::Grid;
|
|
||||||
|
|
||||||
use Math::Vector::Real;
|
|
||||||
|
|
||||||
use Moo;
|
|
||||||
|
|
||||||
has grid => ( is => 'lazy', default => sub($self) {
|
|
||||||
return [
|
|
||||||
map { [ split '' ] } split "\n", $self->string
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
has string => ( is => 'ro' );
|
|
||||||
|
|
||||||
has dimensions => is => 'lazy',
|
|
||||||
default => sub ($self) {
|
|
||||||
return [ 0 + $self->grid->@*, 0 + $self->grid->[0]->@* ];
|
|
||||||
};
|
|
||||||
|
|
||||||
sub get($self,$i,$j) {
|
|
||||||
return unless $self->is_inside($i,$j);
|
|
||||||
return $self->grid->[$i][$j];
|
|
||||||
}
|
|
||||||
|
|
||||||
sub foreach($self,$sub) {
|
|
||||||
for my $l ( 0..$self->dimensions->[0]-1) {
|
|
||||||
|
|
||||||
for my $c ( 0..$self->dimensions->[1]-1) {
|
|
||||||
$sub->($l,$c,$self->get($l,$c));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub is_inside($self,$i,$j) {
|
|
||||||
return 0 if $i < 0 or $j < 0;
|
|
||||||
return 0 if $i >= $self->dimensions->[0];
|
|
||||||
return 0 if $j >= $self->dimensions->[1];
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub as_string($self) {
|
|
||||||
my $o = '';
|
|
||||||
for my $l ( $self->grid->@* ) {
|
|
||||||
$o .= join( '', @$l)."\n";
|
|
||||||
}
|
|
||||||
return $o;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub ortho_neighbors($self,$x,$y) {
|
|
||||||
return grep {
|
|
||||||
$self->is_inside(@$_)
|
|
||||||
} map { V($x,$y)+V(@$_) } [1,0],[0,1],[-1,0],[0,-1];
|
|
||||||
}
|
|
||||||
1;
|
|
@ -1,40 +0,0 @@
|
|||||||
use 5.36.0;
|
|
||||||
|
|
||||||
package AoC::Puzzle;
|
|
||||||
|
|
||||||
use Moo;
|
|
||||||
|
|
||||||
use Path::Tiny;
|
|
||||||
|
|
||||||
has file => ( is => 'ro' );
|
|
||||||
|
|
||||||
has path_file => (
|
|
||||||
is => 'lazy',
|
|
||||||
default => sub ($self) {
|
|
||||||
path( $self->file );
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
sub day_part ($self) {
|
|
||||||
$self =~ /Part(\d)/g;
|
|
||||||
return $1;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub file_lines ($self) {
|
|
||||||
$self->path_file->lines( { chomp => 1 } );
|
|
||||||
}
|
|
||||||
|
|
||||||
sub file_slurp ($self) {
|
|
||||||
my $content = $self->path_file->slurp;
|
|
||||||
chomp $content;
|
|
||||||
return $content;
|
|
||||||
}
|
|
||||||
|
|
||||||
has input => (
|
|
||||||
is => 'lazy',
|
|
||||||
default => sub { ... }
|
|
||||||
);
|
|
||||||
|
|
||||||
sub solve { ... }
|
|
||||||
|
|
||||||
1;
|
|
Loading…
Reference in New Issue
Block a user