2020
This commit is contained in:
parent
6c0551059f
commit
8011c14aeb
13
2020/01/part1.pl
Normal file
13
2020/01/part1.pl
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
use 5.20.0;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use Path::Tiny;
|
||||||
|
|
||||||
|
my @expenses = path('input')->lines;
|
||||||
|
|
||||||
|
while(my $this = shift @expenses) {
|
||||||
|
my $that = 2020 - $this;
|
||||||
|
next unless grep { $_ == $that } @expenses;
|
||||||
|
|
||||||
|
print join " ", $this, $that, $this*$that;
|
||||||
|
}
|
30
2020/01/part2.pl
Normal file
30
2020/01/part2.pl
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
use 5.20.0;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use Path::Tiny;
|
||||||
|
use List::AllUtils qw/ product /;
|
||||||
|
|
||||||
|
use experimental qw/ signatures /;
|
||||||
|
|
||||||
|
my @expenses = path('input')->lines;
|
||||||
|
|
||||||
|
$, = " ";
|
||||||
|
print product find_group( \@expenses, 2020, 3, [] )->@*;
|
||||||
|
|
||||||
|
sub find_group($list,$goal,$n,$so_far) {
|
||||||
|
|
||||||
|
if( $n == 1 ) {
|
||||||
|
if( grep { $_ == $goal } @$list ) {
|
||||||
|
return [ @$so_far, $goal ];
|
||||||
|
};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
my @list = grep { $_ < $goal } @$list;
|
||||||
|
|
||||||
|
while ( my $next = shift @list ) {
|
||||||
|
my $result = find_group( \@list, $goal - $next, $n-1, [ @$so_far, $next ] ) or next;
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
22
2020/02/part1.pl
Normal file
22
2020/02/part1.pl
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
use 5.20.0;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use Path::Tiny;
|
||||||
|
|
||||||
|
use experimental qw/
|
||||||
|
signatures
|
||||||
|
postderef
|
||||||
|
/;
|
||||||
|
|
||||||
|
my @lines = path(shift)->lines;
|
||||||
|
|
||||||
|
print scalar grep { is_valid($_) } @lines;
|
||||||
|
|
||||||
|
sub is_valid($line) {
|
||||||
|
$line =~ /(?<min>\d+)-(?<max>\d+) (?<letter>\w): (?<password>\w+)/;
|
||||||
|
|
||||||
|
my $min = $+{min};
|
||||||
|
my $max = $+{max};
|
||||||
|
my @matches = $+{password} =~ /$+{letter}/g;
|
||||||
|
return ( @matches >= $min and @matches <= $max );
|
||||||
|
}
|
20
2020/02/part2.pl
Normal file
20
2020/02/part2.pl
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
use 5.20.0;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use Path::Tiny;
|
||||||
|
|
||||||
|
use experimental qw/
|
||||||
|
signatures
|
||||||
|
postderef
|
||||||
|
/;
|
||||||
|
|
||||||
|
my @lines = path(shift)->lines;
|
||||||
|
|
||||||
|
print scalar grep { is_valid($_) } @lines;
|
||||||
|
|
||||||
|
sub is_valid($line) {
|
||||||
|
$line =~ /(?<min>\d+)-(?<max>\d+) (?<letter>\w): (?<password>\w+)/;
|
||||||
|
|
||||||
|
return 1 == grep { $_ eq $+{letter} }
|
||||||
|
(split '', $+{password})[ map { $_ -1 } @+{'min','max'} ];
|
||||||
|
}
|
24
2020/03/part1.pl
Normal file
24
2020/03/part1.pl
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
use 5.20.0;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use experimental qw/
|
||||||
|
signatures
|
||||||
|
postderef
|
||||||
|
/;
|
||||||
|
|
||||||
|
use Path::Tiny;
|
||||||
|
|
||||||
|
my @forest = path(shift)->lines({chomp => 1 });
|
||||||
|
|
||||||
|
my $trees = 0;
|
||||||
|
|
||||||
|
my $i = 0;
|
||||||
|
for my $line ( @forest ) {
|
||||||
|
$trees++ if '#' eq substr $line, $i, 1;
|
||||||
|
$i+=3;
|
||||||
|
$i %= length $line;
|
||||||
|
}
|
||||||
|
|
||||||
|
print $trees;
|
||||||
|
|
||||||
|
|
46
2020/03/part2.pl
Normal file
46
2020/03/part2.pl
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
use 5.20.0;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use experimental qw/
|
||||||
|
signatures
|
||||||
|
postderef
|
||||||
|
/;
|
||||||
|
|
||||||
|
use Path::Tiny;
|
||||||
|
|
||||||
|
my @forest = path(shift)->lines({chomp => 1 });
|
||||||
|
|
||||||
|
|
||||||
|
sub go_down($forest,$right,$down=1) {
|
||||||
|
my $trees = 0;
|
||||||
|
my @forest = @$forest;
|
||||||
|
|
||||||
|
my $line = shift @forest;
|
||||||
|
my $i = 0;
|
||||||
|
|
||||||
|
use DDP;
|
||||||
|
|
||||||
|
while( $line) {
|
||||||
|
|
||||||
|
|
||||||
|
$trees++ if '#' eq substr $line, $i, 1;
|
||||||
|
$i+=$right;
|
||||||
|
$i %= length $line;
|
||||||
|
|
||||||
|
$line = shift @forest for 1..$down;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $trees
|
||||||
|
}
|
||||||
|
|
||||||
|
use List::AllUtils qw/ product /;
|
||||||
|
$, = " ";
|
||||||
|
print product map { go_down([@forest],@$_) } (
|
||||||
|
[1,1],
|
||||||
|
[3,1],
|
||||||
|
[5,1],
|
||||||
|
[7,1],
|
||||||
|
[1,2],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
11
2020/03/test
Normal file
11
2020/03/test
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
..##.......
|
||||||
|
#...#...#..
|
||||||
|
.#....#..#.
|
||||||
|
..#.#...#.#
|
||||||
|
.#...##..#.
|
||||||
|
..#.##.....
|
||||||
|
.#.#.#....#
|
||||||
|
.#........#
|
||||||
|
#.##...#...
|
||||||
|
#...##....#
|
||||||
|
.#..#...#.#
|
25
2020/04/part1.pm
Normal file
25
2020/04/part1.pm
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
use 5.20.0;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use Path::Tiny;
|
||||||
|
use List::AllUtils qw/all/;
|
||||||
|
|
||||||
|
use parent qw/ Exporter/;
|
||||||
|
|
||||||
|
use experimental qw/
|
||||||
|
signatures
|
||||||
|
postderef
|
||||||
|
/;
|
||||||
|
|
||||||
|
our @EXPORT = qw/ valid_passports /;
|
||||||
|
|
||||||
|
sub valid_passports($file) {
|
||||||
|
my $data = path($file)->slurp;
|
||||||
|
|
||||||
|
my @passports = map { +{ split /:| |\n/ } } split "\n\n", $data;
|
||||||
|
|
||||||
|
return scalar grep {
|
||||||
|
my $p = $_;
|
||||||
|
all { $p->{$_} } qw/ byr iyr eyr hgt hcl ecl pid /
|
||||||
|
} @passports;
|
||||||
|
}
|
47
2020/04/part2.pm
Normal file
47
2020/04/part2.pm
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
use 5.20.0;
|
||||||
|
no warnings;
|
||||||
|
|
||||||
|
use Path::Tiny;
|
||||||
|
use List::AllUtils qw/all/;
|
||||||
|
|
||||||
|
use parent qw/ Exporter/;
|
||||||
|
|
||||||
|
use experimental qw/
|
||||||
|
signatures
|
||||||
|
postderef
|
||||||
|
/;
|
||||||
|
|
||||||
|
our @EXPORT = qw/ valid_passports_2 validate_passport /;
|
||||||
|
|
||||||
|
my %validator = (
|
||||||
|
byr => sub($x) { $x >= 1920 and $x <= 2002 },
|
||||||
|
iyr => sub($x) { $x >= 2010 and $x <= 2020 },
|
||||||
|
eyr => sub($x) { $x >= 2020 and $x <= 2030 },
|
||||||
|
hgt => sub($x) { $x =~ /(in|cm)$/ and (
|
||||||
|
$& eq 'in' ? ( $x >= 59 and $x <= 76) :( $x >= 150 and $x <= 193)
|
||||||
|
)},
|
||||||
|
hcl => sub($x) {
|
||||||
|
!!($x =~ /^#[0-9a-f]{6}$/)
|
||||||
|
},
|
||||||
|
ecl => sub($x) { $x =~ /^(amb|blu|brn|gry|grn|hzl|oth)$/ },
|
||||||
|
pid => sub($x) { $x =~ /^\d{9}$/ },
|
||||||
|
);
|
||||||
|
|
||||||
|
use List::AllUtils qw/ pairmap /;
|
||||||
|
|
||||||
|
sub validate_passport(%passport) {
|
||||||
|
pairmap { $a => $validator{$a}->($b) } %passport;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub valid_passports_2($file) {
|
||||||
|
my $data = path($file)->slurp;
|
||||||
|
|
||||||
|
my @passports = map { +{ split /:| |\n/ } } split "\n\n", $data;
|
||||||
|
|
||||||
|
return scalar grep {
|
||||||
|
my $p = $_;
|
||||||
|
all { $validator{$_}->($p->{$_}) } qw/ byr iyr eyr hgt hcl ecl pid /
|
||||||
|
} @passports;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
13
2020/04/test
Normal file
13
2020/04/test
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
ecl:gry pid:860033327 eyr:2020 hcl:#fffffd
|
||||||
|
byr:1937 iyr:2017 cid:147 hgt:183cm
|
||||||
|
|
||||||
|
iyr:2013 ecl:amb cid:350 eyr:2023 pid:028048884
|
||||||
|
hcl:#cfa07d byr:1929
|
||||||
|
|
||||||
|
hcl:#ae17e1 iyr:2013
|
||||||
|
eyr:2024
|
||||||
|
ecl:brn pid:760753108 byr:1931
|
||||||
|
hgt:179cm
|
||||||
|
|
||||||
|
hcl:#cfa07d eyr:2025 pid:166559648
|
||||||
|
iyr:2011 ecl:brn hgt:59in
|
11
2020/04/tests.t
Normal file
11
2020/04/tests.t
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
use Test::More;
|
||||||
|
|
||||||
|
BEGIN { push @INC, '.'; }
|
||||||
|
|
||||||
|
use part1;
|
||||||
|
|
||||||
|
is valid_passports('test') => 2;
|
||||||
|
|
||||||
|
is valid_passports('input') => 210;
|
||||||
|
|
||||||
|
done_testing();
|
19
2020/04/tests2.t
Normal file
19
2020/04/tests2.t
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
use Test2::V0;
|
||||||
|
|
||||||
|
BEGIN { push @INC, '.'; }
|
||||||
|
|
||||||
|
use List::AllUtils qw/ pairmap /;
|
||||||
|
use part2;
|
||||||
|
|
||||||
|
is { pairmap { $a => !!$b } validate_passport(
|
||||||
|
pid => '087499704', hgt => '74in',
|
||||||
|
ecl => 'grn', iyr => 2012, eyr => 2030, byr => 1980,
|
||||||
|
hcl => '#623a2f')
|
||||||
|
} => {
|
||||||
|
map {
|
||||||
|
$_ => 1 } qw/ pid hgt ecl iyr eyr byr hcl /
|
||||||
|
};
|
||||||
|
|
||||||
|
is valid_passports_2('input') => 131;
|
||||||
|
|
||||||
|
done_testing();
|
34
2020/05/part1.pm
Normal file
34
2020/05/part1.pm
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package part1;
|
||||||
|
|
||||||
|
use 5.20.0;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use experimental qw/
|
||||||
|
signatures
|
||||||
|
postderef
|
||||||
|
switch
|
||||||
|
/;
|
||||||
|
|
||||||
|
use parent qw/ Exporter::Tiny /;
|
||||||
|
|
||||||
|
our @EXPORT = qw/ resolve /;
|
||||||
|
|
||||||
|
sub resolve($code) {
|
||||||
|
my @row = ( 0, 127 );
|
||||||
|
my @column = ( 0, 7 );
|
||||||
|
|
||||||
|
for ( split '', $code ) {
|
||||||
|
when ('F') { $row[1] = $row[0] + int( ( $row[1] - $row[0] ) / 2 ) }
|
||||||
|
when ('B') { $row[0] = $row[0] + 1 + int( ( $row[1] - $row[0] ) / 2 ) }
|
||||||
|
when ('L') {
|
||||||
|
$column[1] = $column[0] + int( ( $column[1] - $column[0] ) / 2 )
|
||||||
|
}
|
||||||
|
when ('R') {
|
||||||
|
$column[0] = $column[0] + 1 +
|
||||||
|
int( ( $column[1] - $column[0] ) / 2 )
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return 8 * $row[0] + $column[0];
|
||||||
|
}
|
26
2020/05/part2.pm
Normal file
26
2020/05/part2.pm
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package part2;
|
||||||
|
|
||||||
|
use 5.20.0;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use experimental qw/
|
||||||
|
signatures
|
||||||
|
postderef
|
||||||
|
switch
|
||||||
|
/;
|
||||||
|
|
||||||
|
use part1;
|
||||||
|
|
||||||
|
sub solution(@codes) {
|
||||||
|
my @positions = sort { $a <=> $b } map { resolve($_) } @codes;
|
||||||
|
|
||||||
|
my $i = $positions[0];
|
||||||
|
|
||||||
|
for (@positions) {
|
||||||
|
return $_ - 1 if $_ != $i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
||||||
|
|
21
2020/05/tests.t
Normal file
21
2020/05/tests.t
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
use Test2::V0;
|
||||||
|
|
||||||
|
BEGIN { push @INC, '.' }
|
||||||
|
|
||||||
|
use Path::Tiny;
|
||||||
|
use List::AllUtils qw/ max /;
|
||||||
|
|
||||||
|
use part1;
|
||||||
|
use part2;
|
||||||
|
|
||||||
|
subtest "part1" => sub {
|
||||||
|
is resolve('BFFFBBFRRR') => 567;
|
||||||
|
|
||||||
|
is max( map { resolve($_) } path('input')->lines ) => 813;
|
||||||
|
};
|
||||||
|
|
||||||
|
subtest part2 => sub {
|
||||||
|
is part2::solution( path('input')->lines ) => 612;
|
||||||
|
};
|
||||||
|
|
||||||
|
done_testing();
|
21
2020/06/part1.pm
Normal file
21
2020/06/part1.pm
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package part1;
|
||||||
|
|
||||||
|
use 5.20.0;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use Path::Tiny;
|
||||||
|
use List::AllUtils qw/ sum /;
|
||||||
|
|
||||||
|
use experimental qw/
|
||||||
|
signatures
|
||||||
|
postderef
|
||||||
|
/;
|
||||||
|
|
||||||
|
sub solution($input) {
|
||||||
|
return sum map {
|
||||||
|
my %x = map { $_ => $_ } /(\w)/g;
|
||||||
|
scalar keys %x;
|
||||||
|
} split "\n\n", $input;
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
18
2020/06/part2.pm
Normal file
18
2020/06/part2.pm
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package part2;
|
||||||
|
|
||||||
|
use 5.20.0;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use List::AllUtils qw/ sum reduce /;
|
||||||
|
use Set::Object qw/ set /;
|
||||||
|
|
||||||
|
use experimental qw/ signatures postderef /;
|
||||||
|
|
||||||
|
sub solution($input) {
|
||||||
|
return sum map {
|
||||||
|
my $answers = reduce { $a * $b } map { set( split '' ) } split "\n";
|
||||||
|
$answers->size;
|
||||||
|
} split "\n\n", $input;
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
11
2020/06/tests.t
Normal file
11
2020/06/tests.t
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
use Test2::V0;
|
||||||
|
|
||||||
|
BEGIN { push @INC, '.'; }
|
||||||
|
use part1;
|
||||||
|
use part2;
|
||||||
|
use Path::Tiny;
|
||||||
|
|
||||||
|
is part1::solution( path('input')->slurp ) => 6633;
|
||||||
|
is part2::solution( path('input')->slurp ) => 3202;
|
||||||
|
|
||||||
|
done_testing();
|
42
2020/07/part1.pm
Normal file
42
2020/07/part1.pm
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
package part1;
|
||||||
|
|
||||||
|
use 5.20.0;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use experimental qw/
|
||||||
|
signatures
|
||||||
|
postderef
|
||||||
|
/;
|
||||||
|
|
||||||
|
sub parse_line($line) {
|
||||||
|
$line =~ s/(\w+ \w+) bags//;
|
||||||
|
my $bag = $1;
|
||||||
|
|
||||||
|
my %content = ();
|
||||||
|
|
||||||
|
while ( $line =~ /(\d+) (\w+ \w+) bag/g ) {
|
||||||
|
$content{$2} = $1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $bag => \%content;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub contains( $name, $target, $bags ) {
|
||||||
|
|
||||||
|
return 1 if $bags->{$name}{$target};
|
||||||
|
|
||||||
|
for ( keys $bags->{$name}->%* ) {
|
||||||
|
return 1 if contains( $_, $target, $bags );
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub solution(@lines) {
|
||||||
|
my %bags = map { parse_line($_) } @lines;
|
||||||
|
|
||||||
|
return scalar grep { contains($_, 'shiny gold', \%bags) } keys %bags;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
29
2020/07/part2.pl
Normal file
29
2020/07/part2.pl
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package part2;
|
||||||
|
|
||||||
|
|
||||||
|
use 5.20.0;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use experimental qw/
|
||||||
|
signatures
|
||||||
|
postderef
|
||||||
|
/;
|
||||||
|
|
||||||
|
require './part1.pm';
|
||||||
|
|
||||||
|
sub contains($name, $bags) {
|
||||||
|
my $contained = 0;
|
||||||
|
|
||||||
|
while( my( $name, $qty ) = each $bags->{$name}->%* ) {
|
||||||
|
$contained += $qty * ( 1+ contains($name, $bags));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $contained;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub solution(@lines) {
|
||||||
|
my %bags = map { part1::parse_line($_) } @lines;
|
||||||
|
|
||||||
|
return contains('shiny gold', \%bags );
|
||||||
|
}
|
45
2020/07/tests.t
Normal file
45
2020/07/tests.t
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
use Test2::V0;
|
||||||
|
use Path::Tiny;
|
||||||
|
|
||||||
|
require './part1.pm';
|
||||||
|
require './part2.pl';
|
||||||
|
|
||||||
|
my $sample = <<'END';
|
||||||
|
light red bags contain 1 bright white bag, 2 muted yellow bags.
|
||||||
|
dark orange bags contain 3 bright white bags, 4 muted yellow bags.
|
||||||
|
bright white bags contain 1 shiny gold bag.
|
||||||
|
muted yellow bags contain 2 shiny gold bags, 9 faded blue bags.
|
||||||
|
shiny gold bags contain 1 dark olive bag, 2 vibrant plum bags.
|
||||||
|
dark olive bags contain 3 faded blue bags, 4 dotted black bags.
|
||||||
|
vibrant plum bags contain 5 faded blue bags, 6 dotted black bags.
|
||||||
|
faded blue bags contain no other bags.
|
||||||
|
dotted black bags contain no other bags.
|
||||||
|
END
|
||||||
|
|
||||||
|
subtest part1 => sub {
|
||||||
|
is part1::solution(split "\n", $sample) => 4;
|
||||||
|
|
||||||
|
is part1::solution(path('input')->lines) => 278;
|
||||||
|
};
|
||||||
|
|
||||||
|
subtest part2 => sub {
|
||||||
|
is part2::solution( sample2() ) => 126, 'example';
|
||||||
|
|
||||||
|
is part2::solution(path('input')->lines) => 45157, 'solution';
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
done_testing();
|
||||||
|
|
||||||
|
sub sample2 {
|
||||||
|
return split "\n", <<'END';
|
||||||
|
shiny gold bags contain 2 dark red bags.
|
||||||
|
dark red bags contain 2 dark orange bags.
|
||||||
|
dark orange bags contain 2 dark yellow bags.
|
||||||
|
dark yellow bags contain 2 dark green bags.
|
||||||
|
dark green bags contain 2 dark blue bags.
|
||||||
|
dark blue bags contain 2 dark violet bags.
|
||||||
|
dark violet bags contain no other bags.
|
||||||
|
END
|
||||||
|
}
|
||||||
|
|
43
2020/08/part1.pm
Normal file
43
2020/08/part1.pm
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package part1;
|
||||||
|
|
||||||
|
use 5.20.0;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use experimental qw/
|
||||||
|
signatures
|
||||||
|
postderef
|
||||||
|
switch
|
||||||
|
/;
|
||||||
|
|
||||||
|
sub parse_code($lines) {
|
||||||
|
return map { [ split ] }
|
||||||
|
split "\n", $lines
|
||||||
|
}
|
||||||
|
|
||||||
|
sub run_once($index,$accum,$code) {
|
||||||
|
my( $op, $val ) = $code->[$index]->@*;
|
||||||
|
|
||||||
|
given( $op ) {
|
||||||
|
when( 'nop' ) { $index++ }
|
||||||
|
when( 'acc' ) { $index++; $accum += $val; }
|
||||||
|
when( 'jmp' ) { $index += $val; }
|
||||||
|
}
|
||||||
|
|
||||||
|
return ( $index, $accum );
|
||||||
|
}
|
||||||
|
|
||||||
|
sub solution($lines) {
|
||||||
|
my @code = parse_code($lines);
|
||||||
|
|
||||||
|
my $index = 0;
|
||||||
|
my $accum = 0;
|
||||||
|
my %seen;
|
||||||
|
|
||||||
|
until( $seen{$index}++ ) {
|
||||||
|
($index,$accum) = run_once($index,$accum,\@code);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $accum;
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
44
2020/08/part2.pm
Normal file
44
2020/08/part2.pm
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package part2;
|
||||||
|
|
||||||
|
use 5.20.0;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
require './part1.pm';
|
||||||
|
|
||||||
|
use experimental qw/
|
||||||
|
signatures
|
||||||
|
postderef
|
||||||
|
switch
|
||||||
|
/;
|
||||||
|
|
||||||
|
sub run_instance(@code) {
|
||||||
|
|
||||||
|
my $index = 0;
|
||||||
|
my $accum = 0;
|
||||||
|
my %seen;
|
||||||
|
|
||||||
|
until( $seen{$index}++ ) {
|
||||||
|
($index,$accum) = part1::run_once($index,$accum,\@code);
|
||||||
|
|
||||||
|
return $accum if $index >= @code;
|
||||||
|
}
|
||||||
|
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub solution($lines) {
|
||||||
|
my @code = part1::parse_code($lines);
|
||||||
|
|
||||||
|
for(0..$#code) {
|
||||||
|
next if $code[$_][0] eq 'acc';
|
||||||
|
my @new_code = @code;
|
||||||
|
$new_code[$_] = [ $code[$_]->@* ];
|
||||||
|
$new_code[$_][0] = $new_code[$_][0] eq 'nop' ? 'jmp' : 'nop';
|
||||||
|
|
||||||
|
my $result = run_instance(@new_code);
|
||||||
|
|
||||||
|
return $result if $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
25
2020/08/tests.t
Normal file
25
2020/08/tests.t
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
use Test2::V0;
|
||||||
|
use Path::Tiny;
|
||||||
|
|
||||||
|
require './part1.pm';
|
||||||
|
require './part2.pm';
|
||||||
|
|
||||||
|
subtest part1 => sub {
|
||||||
|
is part1::solution(<<END) => 5, 'sample';
|
||||||
|
nop +0
|
||||||
|
acc +1
|
||||||
|
jmp +4
|
||||||
|
acc +3
|
||||||
|
jmp -3
|
||||||
|
acc -99
|
||||||
|
acc +1
|
||||||
|
jmp -4
|
||||||
|
acc +6
|
||||||
|
END
|
||||||
|
|
||||||
|
is part1::solution( path('input')->slurp ) => 1262, 'part1';
|
||||||
|
};
|
||||||
|
|
||||||
|
is part2::solution( path('input')->slurp ) => 1643, 'part2';
|
||||||
|
|
||||||
|
done_testing();
|
37
2020/09/part1.pm
Normal file
37
2020/09/part1.pm
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package part1;
|
||||||
|
|
||||||
|
use 5.20.0;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use experimental qw/
|
||||||
|
signatures
|
||||||
|
postderef
|
||||||
|
/;
|
||||||
|
|
||||||
|
sub solution($n, $entries) {
|
||||||
|
my @numbers = split "\n", $entries;
|
||||||
|
|
||||||
|
my %seen;
|
||||||
|
my @previous;
|
||||||
|
|
||||||
|
# prime the pump
|
||||||
|
while( @previous < $n ) {
|
||||||
|
my $n = shift @numbers;
|
||||||
|
$seen{$n + $_}++ for @previous;
|
||||||
|
push @previous, $n;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(my $next = shift @numbers) {
|
||||||
|
return $next unless $seen{$next};
|
||||||
|
|
||||||
|
my $goner = shift @previous;
|
||||||
|
$seen{$goner + $_}-- for @previous;
|
||||||
|
$seen{$next + $_}++ for @previous;
|
||||||
|
|
||||||
|
push @previous, $next;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
35
2020/09/part2.pm
Normal file
35
2020/09/part2.pm
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package part2;
|
||||||
|
|
||||||
|
use 5.20.0;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use experimental qw/
|
||||||
|
signatures
|
||||||
|
postderef
|
||||||
|
/;
|
||||||
|
|
||||||
|
use List::AllUtils qw/ minmax sum /;
|
||||||
|
|
||||||
|
sub solution($target, $entries) {
|
||||||
|
my @numbers = split "\n", $entries;
|
||||||
|
|
||||||
|
my $sum = 0;
|
||||||
|
my @seq;
|
||||||
|
|
||||||
|
while( @numbers ) {
|
||||||
|
while( $sum < $target ) {
|
||||||
|
push @seq, shift @numbers;
|
||||||
|
$sum += $seq[-1];
|
||||||
|
}
|
||||||
|
while( $sum > $target ) {
|
||||||
|
$sum -= shift @seq;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( $sum == $target ) {
|
||||||
|
return sum minmax @seq;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
38
2020/09/tests.t
Normal file
38
2020/09/tests.t
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
use Test2::V0;
|
||||||
|
use Path::Tiny;
|
||||||
|
|
||||||
|
require './part1.pm';
|
||||||
|
require './part2.pm';
|
||||||
|
|
||||||
|
subtest part1 => sub {
|
||||||
|
is part1::solution( 5, <<'END') => 127;
|
||||||
|
35
|
||||||
|
20
|
||||||
|
15
|
||||||
|
25
|
||||||
|
47
|
||||||
|
40
|
||||||
|
62
|
||||||
|
55
|
||||||
|
65
|
||||||
|
95
|
||||||
|
102
|
||||||
|
117
|
||||||
|
150
|
||||||
|
182
|
||||||
|
127
|
||||||
|
219
|
||||||
|
299
|
||||||
|
277
|
||||||
|
309
|
||||||
|
576
|
||||||
|
END
|
||||||
|
|
||||||
|
is part1::solution( 25, path('input')->slurp ) => 26796446;
|
||||||
|
};
|
||||||
|
|
||||||
|
subtest part2 => sub {
|
||||||
|
is part2::solution( 26796446, path('input')->slurp ) => 3353494;
|
||||||
|
};
|
||||||
|
|
||||||
|
done_testing();
|
20
2020/10/part1.pm
Normal file
20
2020/10/part1.pm
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package part1;
|
||||||
|
|
||||||
|
use 5.20.0;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use List::AllUtils qw/ part /;
|
||||||
|
|
||||||
|
use experimental qw/ signatures postderef /;
|
||||||
|
|
||||||
|
sub solution(@lines) {
|
||||||
|
@lines = sort {$a<=>$b}@lines;
|
||||||
|
unshift @lines, 0;
|
||||||
|
push @lines, $lines[-1] + 3;
|
||||||
|
|
||||||
|
my @diffs = part { $_ } map { $lines[$_] - $lines[$_-1] } 1..$#lines;
|
||||||
|
|
||||||
|
return $diffs[1]->@* * $diffs[3]->@*;
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
38
2020/10/part2.pm
Normal file
38
2020/10/part2.pm
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
package part2;
|
||||||
|
|
||||||
|
use 5.20.0;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use List::AllUtils qw/ /;
|
||||||
|
|
||||||
|
require './part1.pm';
|
||||||
|
|
||||||
|
use experimental qw/ signatures postderef /;
|
||||||
|
|
||||||
|
use Memoize;
|
||||||
|
|
||||||
|
memoize('ways');
|
||||||
|
|
||||||
|
sub ways($first, @rest) {
|
||||||
|
return 1 unless @rest;
|
||||||
|
|
||||||
|
my $ways = 0;
|
||||||
|
|
||||||
|
while( my $next = shift @rest ) {
|
||||||
|
last if $next - $first > 3;
|
||||||
|
$ways += ways($next, @rest);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ways;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub solution(@lines) {
|
||||||
|
@lines = sort {$a<=>$b}@lines;
|
||||||
|
unshift @lines, 0;
|
||||||
|
push @lines, $lines[-1] + 3;
|
||||||
|
|
||||||
|
return ways(@lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
31
2020/10/sample2
Normal file
31
2020/10/sample2
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
28
|
||||||
|
33
|
||||||
|
18
|
||||||
|
42
|
||||||
|
31
|
||||||
|
14
|
||||||
|
46
|
||||||
|
20
|
||||||
|
48
|
||||||
|
47
|
||||||
|
24
|
||||||
|
23
|
||||||
|
49
|
||||||
|
45
|
||||||
|
19
|
||||||
|
38
|
||||||
|
39
|
||||||
|
11
|
||||||
|
1
|
||||||
|
32
|
||||||
|
25
|
||||||
|
35
|
||||||
|
8
|
||||||
|
17
|
||||||
|
7
|
||||||
|
9
|
||||||
|
4
|
||||||
|
2
|
||||||
|
34
|
||||||
|
10
|
||||||
|
3
|
20
2020/10/tests.t
Normal file
20
2020/10/tests.t
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
use Test2::V0;
|
||||||
|
use Path::Tiny;
|
||||||
|
|
||||||
|
require './part1.pm';
|
||||||
|
require './part2.pm';
|
||||||
|
|
||||||
|
my @sample2 = path('sample2')->lines;
|
||||||
|
my @input = path('input')->lines;
|
||||||
|
|
||||||
|
subtest part1 => sub {
|
||||||
|
is part1::solution(@sample2) => 220, 'sample2';
|
||||||
|
|
||||||
|
is part1::solution( @input) => 1700;
|
||||||
|
};
|
||||||
|
|
||||||
|
subtest part2 => sub {
|
||||||
|
is part2::solution(@input ) => 12401793332096;
|
||||||
|
};
|
||||||
|
|
||||||
|
done_testing();
|
67
2020/11/part1.pm
Normal file
67
2020/11/part1.pm
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
package P1;
|
||||||
|
|
||||||
|
use 5.20.0;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use List::AllUtils qw/ /;
|
||||||
|
|
||||||
|
use Moose;
|
||||||
|
|
||||||
|
use experimental qw/ signatures postderef /;
|
||||||
|
|
||||||
|
sub neighbours ( $self, $i, $j, $grid ) {
|
||||||
|
|
||||||
|
my $n = 0;
|
||||||
|
|
||||||
|
for my $x ( -1, 0, 1 ) {
|
||||||
|
for my $y ( -1, 0, 1 ) {
|
||||||
|
next unless $x or $y;
|
||||||
|
my ( $c, $d ) = ( $i + $x, $j + $y );
|
||||||
|
next if $c < 0 or $d < 0;
|
||||||
|
|
||||||
|
no warnings;
|
||||||
|
$n += $grid->[$c][$d] eq '#';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $n;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sub iterate ( $self, $room ) {
|
||||||
|
|
||||||
|
my @grid = map { [ split '' ] } split "\n", $room;
|
||||||
|
my @next = map { [@$_] } @grid;
|
||||||
|
|
||||||
|
for my $i ( 0 .. $#grid ) {
|
||||||
|
my $row = $grid[$i];
|
||||||
|
for my $j ( 0 .. $row->$#* ) {
|
||||||
|
if ( $row->[$j] eq 'L' ) {
|
||||||
|
if ( not $self->neighbours( $i, $j, \@grid ) ) {
|
||||||
|
$next[$i][$j] = '#';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elsif ( $row->[$j] eq '#' ) {
|
||||||
|
if ( $self->neighbours( $i, $j, \@grid ) >= 4 ) {
|
||||||
|
$next[$i][$j] = 'L';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return join "\n", map { join '', @$_ } @next;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub solution ( $self, $room ) {
|
||||||
|
my $previous;
|
||||||
|
|
||||||
|
no warnings;
|
||||||
|
while ( $room ne $previous ) {
|
||||||
|
( $previous, $room ) = ( $room, $self->iterate($room) );
|
||||||
|
}
|
||||||
|
|
||||||
|
my @m = $room =~ /(#)/g;
|
||||||
|
return scalar @m;
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
71
2020/11/part2.pm
Normal file
71
2020/11/part2.pm
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
package P2;
|
||||||
|
|
||||||
|
use 5.20.0;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use List::AllUtils qw/ /;
|
||||||
|
use Math::Vector::Real;
|
||||||
|
|
||||||
|
require './part1.pm';
|
||||||
|
|
||||||
|
use Moose;
|
||||||
|
extends 'P1';
|
||||||
|
|
||||||
|
use experimental qw/ signatures postderef /;
|
||||||
|
|
||||||
|
sub neighbours ( $self, $i, $j, $grid ) {
|
||||||
|
|
||||||
|
my $n = 0;
|
||||||
|
|
||||||
|
for my $x ( -1, 0, 1 ) {
|
||||||
|
for my $y ( -1, 0, 1 ) {
|
||||||
|
next unless $x or $y;
|
||||||
|
|
||||||
|
my $delta = V( $x, $y );
|
||||||
|
my $c = V( $i, $j );
|
||||||
|
|
||||||
|
while () {
|
||||||
|
$c += $delta;
|
||||||
|
|
||||||
|
last if grep { $_ < 0 } @$c;
|
||||||
|
my $x = $grid->[ $c->[0] ][ $c->[1] ];
|
||||||
|
|
||||||
|
last if !$x or $x eq 'L';
|
||||||
|
|
||||||
|
next if $x eq '.';
|
||||||
|
|
||||||
|
$n++;
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $n;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sub iterate ( $self, $room ) {
|
||||||
|
|
||||||
|
my @grid = map { [ split '' ] } split "\n", $room;
|
||||||
|
my @next = map { [@$_] } @grid;
|
||||||
|
|
||||||
|
for my $i ( 0 .. $#grid ) {
|
||||||
|
my $row = $grid[$i];
|
||||||
|
for my $j ( 0 .. $row->$#* ) {
|
||||||
|
if ( $row->[$j] eq 'L' ) {
|
||||||
|
if ( not $self->neighbours( $i, $j, \@grid ) ) {
|
||||||
|
$next[$i][$j] = '#';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elsif ( $row->[$j] eq '#' ) {
|
||||||
|
if ( $self->neighbours( $i, $j, \@grid ) >= 5 ) {
|
||||||
|
$next[$i][$j] = 'L';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return join "\n", map { join '', @$_ } @next;
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
10
2020/11/sample
Normal file
10
2020/11/sample
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#.##.##.##
|
||||||
|
#######.##
|
||||||
|
#.#.#..#..
|
||||||
|
####.##.##
|
||||||
|
#.##.##.##
|
||||||
|
#.#####.##
|
||||||
|
..#.#.....
|
||||||
|
##########
|
||||||
|
#.######.#
|
||||||
|
#.#####.##
|
20
2020/11/tests.t
Normal file
20
2020/11/tests.t
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
use Test2::V0;
|
||||||
|
use Path::Tiny;
|
||||||
|
|
||||||
|
require './part1.pm';
|
||||||
|
require './part2.pm';
|
||||||
|
|
||||||
|
my $sample = path('sample')->slurp;
|
||||||
|
my $input = path('input')->slurp;
|
||||||
|
|
||||||
|
subtest part1 => sub {
|
||||||
|
is P1->new->solution( $sample ) => 37;
|
||||||
|
is P1->new->solution( $input ) => 2427;
|
||||||
|
};
|
||||||
|
|
||||||
|
subtest part2 => sub {
|
||||||
|
is P2->new->solution( $sample ) => 26;
|
||||||
|
is P2->new->solution( $input ) => 2199;
|
||||||
|
};
|
||||||
|
|
||||||
|
done_testing();
|
66
2020/12/part1.pm
Normal file
66
2020/12/part1.pm
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
package P1;
|
||||||
|
|
||||||
|
use 5.20.0;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use List::AllUtils qw/ /;
|
||||||
|
use Math::Vector::Real;
|
||||||
|
|
||||||
|
use Moose;
|
||||||
|
use MooseX::MungeHas 'is_rw';
|
||||||
|
|
||||||
|
use experimental qw/ signatures postderef switch /;
|
||||||
|
|
||||||
|
has coords => sub {
|
||||||
|
return V(0,0);
|
||||||
|
};
|
||||||
|
|
||||||
|
has facing => sub {
|
||||||
|
1;
|
||||||
|
};
|
||||||
|
|
||||||
|
my @delta = (
|
||||||
|
V(0,1),
|
||||||
|
V(1,0),
|
||||||
|
V(0,-1),
|
||||||
|
V(-1,0),
|
||||||
|
);
|
||||||
|
|
||||||
|
sub delta {
|
||||||
|
return \@delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub turn($self,$n) {
|
||||||
|
my $d = ($self->facing + $n/90)%4;
|
||||||
|
$self->facing($d);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub move($self,$m) {
|
||||||
|
$m =~ /(.)(\d+)/;
|
||||||
|
|
||||||
|
my ( $x, $c ) = ($1,$2);
|
||||||
|
|
||||||
|
my $coords = $self->coords;
|
||||||
|
|
||||||
|
given($x) {
|
||||||
|
$coords += $c * $delta[$self->facing] when 'F';
|
||||||
|
$coords += $c * $delta[0] when 'N';
|
||||||
|
$coords += $c * $delta[1] when 'E';
|
||||||
|
$coords += $c * $delta[2] when 'S';
|
||||||
|
$coords += $c * $delta[3] when 'W';
|
||||||
|
$self->turn($c) when 'R';
|
||||||
|
$self->turn(-$c) when 'L';
|
||||||
|
}
|
||||||
|
|
||||||
|
$self->coords($coords);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub solution($class,@instructions) {
|
||||||
|
my $self = $class->new;
|
||||||
|
|
||||||
|
$self->move($_) for @instructions;
|
||||||
|
|
||||||
|
$self->coords->manhattan_dist(V(0,0));
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
57
2020/12/part2.pm
Normal file
57
2020/12/part2.pm
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
package P2;
|
||||||
|
|
||||||
|
use 5.20.0;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use List::AllUtils qw/ /;
|
||||||
|
use Math::Vector::Real;
|
||||||
|
|
||||||
|
require './part1.pm';
|
||||||
|
|
||||||
|
use Moose;
|
||||||
|
use MooseX::MungeHas 'is_rw';
|
||||||
|
|
||||||
|
extends 'P1';
|
||||||
|
|
||||||
|
use experimental qw/ signatures postderef /;
|
||||||
|
|
||||||
|
has +facing => sub { V(10,1) };
|
||||||
|
|
||||||
|
sub turn($self,$n) {
|
||||||
|
my $f = $self->facing;
|
||||||
|
my $d = ($n/90)%4;
|
||||||
|
given( $d ) {
|
||||||
|
return V($f->[1], -$f->[0]) when 1;
|
||||||
|
return V(-$f->[0], -$f->[1]) when 2;
|
||||||
|
return V(-$f->[1], $f->[0]) when 3;
|
||||||
|
}
|
||||||
|
return $f;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub move($self,$m) {
|
||||||
|
$m =~ /(.)(\d+)/;
|
||||||
|
|
||||||
|
my ( $x, $c ) = ($1,$2);
|
||||||
|
|
||||||
|
my $coords = $self->coords;
|
||||||
|
my $facing = $self->facing;
|
||||||
|
|
||||||
|
|
||||||
|
given($x) {
|
||||||
|
$coords += $c * $self->facing when 'F';
|
||||||
|
$facing += $c * $self->delta->[0] when 'N';
|
||||||
|
$facing += $c * $self->delta->[1] when 'E';
|
||||||
|
$facing += $c * $self->delta->[2] when 'S';
|
||||||
|
$facing += $c * $self->delta->[3] when 'W';
|
||||||
|
$facing = $self->turn($c) when 'R';
|
||||||
|
$facing = $self->turn(-$c) when 'L';
|
||||||
|
}
|
||||||
|
|
||||||
|
$self->facing($facing);
|
||||||
|
$self->coords($coords);
|
||||||
|
|
||||||
|
warn $self->facing;
|
||||||
|
warn $self->coords;
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
24
2020/12/tests.t
Normal file
24
2020/12/tests.t
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
use Test2::V0;
|
||||||
|
use Path::Tiny;
|
||||||
|
|
||||||
|
require './part1.pm';
|
||||||
|
require './part2.pm';
|
||||||
|
|
||||||
|
my @input = path('input')->lines;
|
||||||
|
|
||||||
|
0 and subtest part1 => sub {
|
||||||
|
is P1->solution(@input) => 1221;
|
||||||
|
};
|
||||||
|
|
||||||
|
subtest part2 => sub {
|
||||||
|
is P2->solution(qw/
|
||||||
|
F10
|
||||||
|
N3
|
||||||
|
F7
|
||||||
|
R90
|
||||||
|
F11 /) => 286, 'example';
|
||||||
|
|
||||||
|
is P2->solution(@input ) => 59435;
|
||||||
|
};
|
||||||
|
|
||||||
|
done_testing();
|
22
2020/13/part1.pm
Normal file
22
2020/13/part1.pm
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package part1;
|
||||||
|
|
||||||
|
use 5.20.0;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use List::AllUtils qw/ min /;
|
||||||
|
|
||||||
|
use experimental qw/ signatures postderef /;
|
||||||
|
|
||||||
|
sub solution($timestamp,@entries) {
|
||||||
|
@entries = grep { $_ ne 'x' } @entries;
|
||||||
|
|
||||||
|
my %sched = map {
|
||||||
|
(int($timestamp / $_)+1 )* $_ => $_
|
||||||
|
} @entries;
|
||||||
|
|
||||||
|
my $k = min keys %sched;
|
||||||
|
$sched{ $k } * ( $k - $timestamp ) ;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
54
2020/13/part2.pm
Normal file
54
2020/13/part2.pm
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
package part2;
|
||||||
|
|
||||||
|
use 5.20.0;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use List::AllUtils qw/ min max /;
|
||||||
|
use POSIX qw/ ceil /;
|
||||||
|
|
||||||
|
require './part1.pm';
|
||||||
|
|
||||||
|
use experimental qw/ signatures postderef /;
|
||||||
|
|
||||||
|
sub find($t, $next=undef, @buses) {
|
||||||
|
|
||||||
|
return 0 unless $next;
|
||||||
|
|
||||||
|
if( $next eq 'x' ) {
|
||||||
|
return find($t+1, @buses );
|
||||||
|
}
|
||||||
|
|
||||||
|
my $n = $t / $next;
|
||||||
|
my $nint = int $n;
|
||||||
|
|
||||||
|
if( $nint == $n ) {
|
||||||
|
return find( $t+1, @buses );
|
||||||
|
}
|
||||||
|
|
||||||
|
return (1+$nint)*$next;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sub solution(@buses) {
|
||||||
|
@buses = map { $_ eq 'x'?1:$_
|
||||||
|
} @buses;
|
||||||
|
|
||||||
|
my $t = 1;
|
||||||
|
T: while() {
|
||||||
|
my $i = 0;
|
||||||
|
my @min = map {
|
||||||
|
my $s = $t + $i++;
|
||||||
|
$_ * ceil($s/$_);
|
||||||
|
} @buses;
|
||||||
|
warn join " ", @min;
|
||||||
|
for(0..$#min-1) {
|
||||||
|
if( $min[$_] != $min[$_+1]-1 ) {
|
||||||
|
$t = max map { $min[$_] - $_ } 0..$#min;
|
||||||
|
next T;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
18
2020/13/tests.t
Normal file
18
2020/13/tests.t
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
use Test2::V0;
|
||||||
|
use Path::Tiny;
|
||||||
|
|
||||||
|
require './part1.pm';
|
||||||
|
require './part2.pm';
|
||||||
|
|
||||||
|
my @input = path('input')->lines;
|
||||||
|
|
||||||
|
subtest part1 => sub {
|
||||||
|
is part1::solution( $input[0], split ',', $input[1] ) => 171;
|
||||||
|
};
|
||||||
|
|
||||||
|
subtest part2 => sub {
|
||||||
|
is part2::solution( 17, 'x', 13, 19 ) => 3417;
|
||||||
|
# is part2::solution( split ',', $input[1] ) => 171;
|
||||||
|
};
|
||||||
|
|
||||||
|
done_testing();
|
31
2020/14/part1.pm
Normal file
31
2020/14/part1.pm
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package part1;
|
||||||
|
|
||||||
|
use 5.20.0;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use List::AllUtils qw/ zip pairmap reduce sum/;
|
||||||
|
|
||||||
|
use experimental qw/ signatures postderef /;
|
||||||
|
|
||||||
|
sub solution(@lines) {
|
||||||
|
my @mask;
|
||||||
|
my @mem;
|
||||||
|
|
||||||
|
while( my $line = shift @lines ) {
|
||||||
|
if( $line =~ /mask = (.*)/ ) {
|
||||||
|
@mask = split '', $1;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
$line =~ /mem\[(\d+)\] = (\d+)/ or die;
|
||||||
|
|
||||||
|
my @num = split '', sprintf "%036b", $2;
|
||||||
|
|
||||||
|
$mem[$1] = reduce { 2*$a + $b } pairmap { $a eq 'X' ? $b : $a } zip @mask, @num;
|
||||||
|
}
|
||||||
|
|
||||||
|
no warnings;
|
||||||
|
return sum @mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
44
2020/14/part2.pm
Normal file
44
2020/14/part2.pm
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package part2;
|
||||||
|
|
||||||
|
use 5.20.0;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use List::AllUtils qw/ zip pairmap sum reduce/;
|
||||||
|
|
||||||
|
require './part1.pm';
|
||||||
|
|
||||||
|
use experimental qw/ signatures postderef /;
|
||||||
|
|
||||||
|
sub solution(@lines) {
|
||||||
|
my @mask;
|
||||||
|
my %mem;
|
||||||
|
|
||||||
|
while( my $line = shift @lines ) {
|
||||||
|
warn $line;
|
||||||
|
if( $line =~ /mask = (.*)/ ) {
|
||||||
|
@mask = split '', $1;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
$line =~ /mem\[(\d+)\] = (\d+)/ or die;
|
||||||
|
|
||||||
|
my $value = $2;
|
||||||
|
my @num = split '', sprintf "%036b", $1;
|
||||||
|
|
||||||
|
my $l = join '', pairmap { $a || $b } zip @mask, @num;
|
||||||
|
|
||||||
|
my $num = $l =~ s/X/%d/g;
|
||||||
|
|
||||||
|
for( 0..(2**$num)-1 ) {
|
||||||
|
my $address = reduce {
|
||||||
|
2*$a + $b
|
||||||
|
} split '', sprintf $l, split '', sprintf "%0${num}b", $_;
|
||||||
|
$mem{$address} = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
no warnings;
|
||||||
|
return sum values %mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
4
2020/14/sample1
Normal file
4
2020/14/sample1
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
mask = XXXXXXXXXXXXXXXXXXXXXXXXXXXXX1XXXX0X
|
||||||
|
mem[8] = 11
|
||||||
|
mem[7] = 101
|
||||||
|
mem[8] = 0
|
4
2020/14/sample2
Normal file
4
2020/14/sample2
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
mask = 000000000000000000000000000000X1001X
|
||||||
|
mem[42] = 100
|
||||||
|
mask = 00000000000000000000000000000000X0XX
|
||||||
|
mem[26] = 1
|
22
2020/14/tests.t
Normal file
22
2020/14/tests.t
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
use Test2::V0;
|
||||||
|
use Path::Tiny;
|
||||||
|
|
||||||
|
require './part1.pm';
|
||||||
|
require './part2.pm';
|
||||||
|
|
||||||
|
my @sample1 = path('sample1')->lines;
|
||||||
|
my @input = path('input')->lines;
|
||||||
|
|
||||||
|
subtest part1 => sub {
|
||||||
|
skip_all;
|
||||||
|
is part1::solution(@sample1) => 165;
|
||||||
|
is part1::solution(@input) => 14954914379452;
|
||||||
|
};
|
||||||
|
|
||||||
|
subtest part2 => sub {
|
||||||
|
my @sample2 = path('sample2')->lines;
|
||||||
|
is part2::solution(@sample2) => 208;
|
||||||
|
is part2::solution(@input) => 3415488160714;
|
||||||
|
};
|
||||||
|
|
||||||
|
done_testing();
|
41
2020/15/part1.pm
Normal file
41
2020/15/part1.pm
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package part1;
|
||||||
|
|
||||||
|
use 5.20.0;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use List::AllUtils qw/ /;
|
||||||
|
|
||||||
|
use experimental qw/ signatures postderef /;
|
||||||
|
|
||||||
|
sub solution(@seeds) {
|
||||||
|
my $last = shift @seeds;
|
||||||
|
my $turn = 1;
|
||||||
|
my %said;
|
||||||
|
|
||||||
|
for(@seeds) {
|
||||||
|
$said{$last} ||= [];
|
||||||
|
push $said{$last}->@*, $turn++;
|
||||||
|
$last = $_;
|
||||||
|
}
|
||||||
|
|
||||||
|
until( $turn == 2020 ) {
|
||||||
|
if( !$said{$last} ) {
|
||||||
|
$said{$last} = [$turn];
|
||||||
|
$last = 0
|
||||||
|
} else {
|
||||||
|
push $said{$last}->@*, $turn;
|
||||||
|
if( $said{$last}->@* > 2 ) {
|
||||||
|
shift $said{$last}->@*;
|
||||||
|
}
|
||||||
|
$last = $said{$last}[-1] - $said{$last}[-2];
|
||||||
|
}
|
||||||
|
|
||||||
|
$turn++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $last;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
44
2020/15/part2.pm
Normal file
44
2020/15/part2.pm
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package part2;
|
||||||
|
|
||||||
|
use 5.20.0;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use List::AllUtils qw/ /;
|
||||||
|
|
||||||
|
require './part1.pm';
|
||||||
|
|
||||||
|
use experimental qw/ signatures postderef /;
|
||||||
|
|
||||||
|
sub solution(@seeds) {
|
||||||
|
my $last = shift @seeds;
|
||||||
|
my $turn = 1;
|
||||||
|
my %said;
|
||||||
|
|
||||||
|
for(@seeds) {
|
||||||
|
$said{$last} ||= [];
|
||||||
|
push $said{$last}->@*, $turn++;
|
||||||
|
$last = $_;
|
||||||
|
}
|
||||||
|
|
||||||
|
until( $turn == 30000000 ) {
|
||||||
|
if( !$said{$last} ) {
|
||||||
|
$said{$last} = [$turn];
|
||||||
|
$last = 0
|
||||||
|
} else {
|
||||||
|
push $said{$last}->@*, $turn;
|
||||||
|
if( $said{$last}->@* > 2 ) {
|
||||||
|
shift $said{$last}->@*;
|
||||||
|
}
|
||||||
|
$last = $said{$last}[-1] - $said{$last}[-2];
|
||||||
|
}
|
||||||
|
|
||||||
|
$turn++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $last;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
1;
|
16
2020/15/tests.t
Normal file
16
2020/15/tests.t
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
use Test2::V0;
|
||||||
|
use Path::Tiny;
|
||||||
|
|
||||||
|
require './part1.pm';
|
||||||
|
require './part2.pm';
|
||||||
|
|
||||||
|
subtest part1 => sub {
|
||||||
|
is part1::solution(0,3,6) => 436;
|
||||||
|
is part1::solution(0,13,1,16,6,17) => 234;
|
||||||
|
};
|
||||||
|
|
||||||
|
subtest part2 => sub {
|
||||||
|
is part2::solution(0,13,1,16,6,17) => 8984;
|
||||||
|
};
|
||||||
|
|
||||||
|
done_testing();
|
27
2020/16/part1.pm
Normal file
27
2020/16/part1.pm
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package part1;
|
||||||
|
|
||||||
|
use 5.20.0;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use List::AllUtils qw/ sum /;
|
||||||
|
use Range::Merge qw/ merge /;
|
||||||
|
|
||||||
|
use experimental qw/ signatures postderef /;
|
||||||
|
|
||||||
|
sub numbers_out_of_range($input) {
|
||||||
|
my $ranges = merge([ map { [ split '-' ] } $input =~ /(\d+-\d+)/g]);
|
||||||
|
|
||||||
|
$input =~ /nearby tickets:(.*)/s;
|
||||||
|
my @tickets = $1 =~ /(\d+)/g;
|
||||||
|
|
||||||
|
return grep {
|
||||||
|
not( $_ >= $ranges->[0][0] and $_ <= $ranges->[0][1])
|
||||||
|
} @tickets;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sub solution($input) {
|
||||||
|
return sum numbers_out_of_range($input);
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
87
2020/16/part2.pm
Normal file
87
2020/16/part2.pm
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
package part2;
|
||||||
|
|
||||||
|
use 5.20.0;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use List::AllUtils qw/ pairmap zip product /;
|
||||||
|
use Range::Merge qw/ merge /;
|
||||||
|
use Set::Object qw/ set /;
|
||||||
|
|
||||||
|
require './part1.pm';
|
||||||
|
|
||||||
|
use experimental qw/ signatures postderef /;
|
||||||
|
|
||||||
|
sub inRanges($n, $ranges) {
|
||||||
|
|
||||||
|
for (@$ranges) {
|
||||||
|
return 1 if $_->[0] <= $n and $_->[1] >= $n;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub possibilities($n,$fields) {
|
||||||
|
|
||||||
|
return set(
|
||||||
|
grep { inRanges($n, $fields->{$_})} keys %$fields
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sub solution($input) {
|
||||||
|
my ( $fields, $myticket, $tickets ) = split "\n\n", $input;
|
||||||
|
|
||||||
|
my %fields = map {
|
||||||
|
my ( $name, $ranges) = split ':';
|
||||||
|
$name => merge([ map { [ split '-'] } $ranges =~ /(\d+-\d+)/g ])
|
||||||
|
} split "\n", $fields;
|
||||||
|
|
||||||
|
my @global;
|
||||||
|
|
||||||
|
for my $ticket ( split "\n", $tickets ) {
|
||||||
|
next if $ticket =~ /nearby/;
|
||||||
|
|
||||||
|
my @fields = split ',', $ticket;
|
||||||
|
|
||||||
|
@fields = map { possibilities($_,\%fields) } @fields;
|
||||||
|
|
||||||
|
next if grep { not $_->size } @fields;
|
||||||
|
|
||||||
|
if(!@global) {
|
||||||
|
@global = @fields;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
@global = pairmap { $a*$b } zip @global, @fields;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
use DDP; say join " ", @$_ for @global;
|
||||||
|
|
||||||
|
my %indexes;
|
||||||
|
|
||||||
|
LOOP: while() {
|
||||||
|
for( 0..$#global ) {
|
||||||
|
if( $global[$_]->size == 1 ) {
|
||||||
|
my $e = $global[$_];
|
||||||
|
$indexes{$global[$_][0]} = $_;
|
||||||
|
@global = map { $_ - $e } @global;
|
||||||
|
redo LOOP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
last LOOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
p %indexes;
|
||||||
|
|
||||||
|
my @myt = $myticket =~ /(\d+)/g;
|
||||||
|
|
||||||
|
return product
|
||||||
|
@myt[
|
||||||
|
map { $indexes{$_} }
|
||||||
|
grep { /departure/ } keys %indexes ];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
11
2020/16/sample
Normal file
11
2020/16/sample
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
class: 0-1 or 4-19
|
||||||
|
row: 0-5 or 8-19
|
||||||
|
seat: 0-13 or 16-19
|
||||||
|
|
||||||
|
your ticket:
|
||||||
|
11,12,13
|
||||||
|
|
||||||
|
nearby tickets:
|
||||||
|
3,9,18
|
||||||
|
15,1,5
|
||||||
|
5,14,9
|
17
2020/16/tests.t
Normal file
17
2020/16/tests.t
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
use Test2::V0;
|
||||||
|
use Path::Tiny;
|
||||||
|
|
||||||
|
require './part1.pm';
|
||||||
|
require './part2.pm';
|
||||||
|
|
||||||
|
my $input = path('input')->slurp;
|
||||||
|
|
||||||
|
subtest part1 => sub {
|
||||||
|
is part1::solution($input) => 20048;
|
||||||
|
};
|
||||||
|
|
||||||
|
subtest part2 => sub {
|
||||||
|
is part2::solution($input) => 4810284647569;
|
||||||
|
};
|
||||||
|
|
||||||
|
done_testing();
|
13
2020/template/part1.pm
Normal file
13
2020/template/part1.pm
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package part1;
|
||||||
|
|
||||||
|
use 5.20.0;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use List::AllUtils qw/ /;
|
||||||
|
|
||||||
|
use experimental qw/ signatures postderef /;
|
||||||
|
|
||||||
|
sub solution() {
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
15
2020/template/part2.pm
Normal file
15
2020/template/part2.pm
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package part2;
|
||||||
|
|
||||||
|
use 5.20.0;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use List::AllUtils qw/ /;
|
||||||
|
|
||||||
|
require './part1.pm';
|
||||||
|
|
||||||
|
use experimental qw/ signatures postderef /;
|
||||||
|
|
||||||
|
sub solution() {
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
15
2020/template/tests.t
Normal file
15
2020/template/tests.t
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
use Test2::V0;
|
||||||
|
use Path::Tiny;
|
||||||
|
|
||||||
|
require './part1.pm';
|
||||||
|
require './part2.pm';
|
||||||
|
|
||||||
|
subtest part1 => sub {
|
||||||
|
is part1::solution( ) => 'TODO';
|
||||||
|
};
|
||||||
|
|
||||||
|
subtest part2 => sub {
|
||||||
|
is part2::solution( ) => 'TODO';
|
||||||
|
};
|
||||||
|
|
||||||
|
done_testing();
|
Loading…
Reference in New Issue
Block a user