first 4 days of 2024
This commit is contained in:
parent
be223b6cef
commit
0ebf67a5cc
22
2024/01/Part1.pm
Normal file
22
2024/01/Part1.pm
Normal file
@ -0,0 +1,22 @@
|
||||
package Day1::Part1;
|
||||
|
||||
use 5.36.0;
|
||||
|
||||
use List::Util qw/ sum pairmap /;
|
||||
use List::MoreUtils qw/ part zip /;
|
||||
|
||||
sub read_file(@lines) {
|
||||
my $i = 0;
|
||||
my @lists = part { $i++ % 2} map { split } @lines;
|
||||
return @lists;
|
||||
}
|
||||
|
||||
|
||||
sub solve(@lists) {
|
||||
for my $x (1,0) {
|
||||
$lists[$x] = [ sort { $a <=> $b } $lists[$x]->@* ];
|
||||
}
|
||||
return sum pairmap { abs $a - $b } zip $lists[0]->@*, $lists[1]->@*;
|
||||
}
|
||||
|
||||
1;
|
17
2024/01/Part2.pm
Normal file
17
2024/01/Part2.pm
Normal file
@ -0,0 +1,17 @@
|
||||
package Day1::Part2;
|
||||
|
||||
use 5.36.0;
|
||||
|
||||
use List::Util qw/ sum pairmap /;
|
||||
use List::MoreUtils qw/ part zip /;
|
||||
|
||||
sub solve($l1,$l2) {
|
||||
my %occur;
|
||||
|
||||
$occur{$_}++ for @$l2;
|
||||
|
||||
no warnings qw/ uninitialized /;
|
||||
sum map { $occur{$_}*$_ } @$l1;
|
||||
}
|
||||
|
||||
1;
|
8
2024/01/main.ts
Normal file
8
2024/01/main.ts
Normal file
@ -0,0 +1,8 @@
|
||||
export function add(a: number, b: number): number {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
// Learn more at https://docs.deno.com/runtime/manual/examples/module_metadata#concepts
|
||||
if (import.meta.main) {
|
||||
console.log("Add 2 + 3 =", add(2, 3));
|
||||
}
|
34
2024/01/part1.ts
Normal file
34
2024/01/part1.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import * as fs from "node:fs/promises";
|
||||
|
||||
export async function readFile(filename: string): Promise<number[][]> {
|
||||
const lines = await fs
|
||||
.readFile(filename, { encoding: "utf8" })
|
||||
.then((lines: string) => lines.split(/\n/))
|
||||
.then((lines: string[]) =>
|
||||
lines.filter((x) => x).map((x) =>
|
||||
x.split(/ +/).map((x) => Number(x))
|
||||
)
|
||||
);
|
||||
|
||||
const l1: number[] = [];
|
||||
const l2: number[] = [];
|
||||
|
||||
lines.forEach(([a, b]) => {
|
||||
l1.push(a);
|
||||
l2.push(b);
|
||||
});
|
||||
|
||||
return [l1, l2];
|
||||
}
|
||||
|
||||
export function solve(...lists: number[][]) {
|
||||
lists.forEach((l) => l.sort());
|
||||
|
||||
let sum = 0;
|
||||
|
||||
for (const i in lists[0]) {
|
||||
sum += Math.abs(lists[0][i] - lists[1][i]);
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
15
2024/01/test.t
Normal file
15
2024/01/test.t
Normal file
@ -0,0 +1,15 @@
|
||||
use lib qw/ . /;
|
||||
|
||||
use Part1;
|
||||
use Part2;
|
||||
|
||||
use Test2::V0;
|
||||
use Path::Tiny;
|
||||
|
||||
my @lists = Day1::Part1::read_file( path('input')->lines );
|
||||
|
||||
is Day1::Part1::solve(@lists) => 1889772;
|
||||
|
||||
is Day1::Part2::solve(@lists) => 23228917;
|
||||
|
||||
done_testing();
|
9
2024/01/test.ts
Normal file
9
2024/01/test.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { expect } from 'jsr:@std/expect';
|
||||
|
||||
import { readFile, solve as d1Solve } from './part1.ts';
|
||||
|
||||
const input = readFile( import.meta.dirname + '/input');
|
||||
|
||||
Deno.test( 'part 1', async () => {
|
||||
expect(d1Solve(...((await input) as any))).toEqual(1889772);
|
||||
});
|
32
2024/02/Part1.pm
Normal file
32
2024/02/Part1.pm
Normal file
@ -0,0 +1,32 @@
|
||||
package Day2::Part1;
|
||||
|
||||
use 5.36.0;
|
||||
|
||||
use List::Util qw/ sum pairmap /;
|
||||
use List::MoreUtils qw/ part zip /;
|
||||
|
||||
sub read_file(@lines) {
|
||||
return map { [split] } @lines;
|
||||
}
|
||||
|
||||
sub is_safe(@report) {
|
||||
my $asc = $report[1] - $report[0];
|
||||
|
||||
my $level = shift @report;
|
||||
|
||||
while(@report) {
|
||||
my $next = shift @report;
|
||||
my $delta = $next - $level;
|
||||
return 0 unless $delta*$asc >= 0;
|
||||
return 0 unless 1 <= abs($delta) <= 3;
|
||||
$level = $next;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub solve(@reports) {
|
||||
return sum map { is_safe(@$_) } @reports;
|
||||
}
|
||||
|
||||
1;
|
25
2024/02/Part2.pm
Normal file
25
2024/02/Part2.pm
Normal file
@ -0,0 +1,25 @@
|
||||
use lib qw/ . /;
|
||||
|
||||
use Part1;
|
||||
|
||||
package Day2::Part2;
|
||||
|
||||
use 5.36.0;
|
||||
|
||||
use List::Util qw/ sum pairmap /;
|
||||
use List::MoreUtils qw/ part zip /;
|
||||
|
||||
sub is_safe_dampened(@report) {
|
||||
for my $i ( 0..$#report) {
|
||||
my @copy = @report;
|
||||
splice @copy, $i, 1;
|
||||
return 1 if Day2::Part1::is_safe(@copy);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub solve(@reports) {
|
||||
return sum map { is_safe_dampened(@$_) } @reports;
|
||||
}
|
||||
|
||||
1;
|
34
2024/02/part1.ts
Normal file
34
2024/02/part1.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import * as fs from "node:fs/promises";
|
||||
|
||||
export function readInput(filename: string): Promise<number[][]> {
|
||||
return fs
|
||||
.readFile(filename, { encoding: "utf8" })
|
||||
.then((lines: string) => lines.split(/\n/))
|
||||
.then((lines: string[]) =>
|
||||
lines.filter((x) => x).map((x) =>
|
||||
x.split(/ +/).map((x) => Number(x))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export function isSafe(report: readonly number[]): boolean {
|
||||
const r = [ ...report ];
|
||||
|
||||
const asc = r[1] - r[0];
|
||||
|
||||
let level = r.shift();
|
||||
|
||||
while (r.length) {
|
||||
const next = r.shift();
|
||||
const delta = next! - level!;
|
||||
if (delta * asc < 0) return false;
|
||||
if (Math.abs(delta) < 1 || Math.abs(delta) > 3) return false;
|
||||
level = next;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function solve(reports: number[][]): number {
|
||||
return reports.filter(isSafe).length;
|
||||
}
|
13
2024/02/part2.ts
Normal file
13
2024/02/part2.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { isSafe } from './part1.ts';
|
||||
|
||||
function isSafeDampened(report: number[]) {
|
||||
for( let i =0; i < report.length; i++) {
|
||||
const copy = [...report];
|
||||
copy.splice( i, 1);
|
||||
if( isSafe(copy) ) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
export function solve(reports: number[][]) {
|
||||
return reports.filter(isSafeDampened).length;
|
||||
}
|
6
2024/02/sample
Normal file
6
2024/02/sample
Normal file
@ -0,0 +1,6 @@
|
||||
7 6 4 2 1
|
||||
1 2 7 8 9
|
||||
9 7 6 2 1
|
||||
1 3 2 4 5
|
||||
8 6 4 4 1
|
||||
1 3 6 7 9
|
22
2024/02/test.t
Normal file
22
2024/02/test.t
Normal file
@ -0,0 +1,22 @@
|
||||
use lib qw~ . ~;
|
||||
|
||||
use Part1;
|
||||
use Part2;
|
||||
|
||||
use Test2::V0;
|
||||
use Path::Tiny;
|
||||
|
||||
my @sample_reports = Day2::Part1::read_file( path('sample')->lines );
|
||||
my @reports = Day2::Part1::read_file( path('input')->lines );
|
||||
|
||||
subtest 'part 1' => sub {
|
||||
is Day2::Part1::is_safe(qw/ 7 6 4 2 1 /) => 1;
|
||||
is Day2::Part1::solve(@sample_reports) => 2;
|
||||
is Day2::Part1::solve(@reports) => 598;
|
||||
};
|
||||
|
||||
subtest 'part 2' => sub {
|
||||
is Day2::Part2::solve(@reports) => 634;
|
||||
};
|
||||
|
||||
done_testing();
|
14
2024/02/test.ts
Normal file
14
2024/02/test.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { expect } from 'jsr:@std/expect';
|
||||
|
||||
import { readInput, solve as p1Solve } from './part1.ts';
|
||||
import { solve as p2Solve } from './part2.ts';
|
||||
|
||||
const reports = await readInput( import.meta.dirname + '/input');
|
||||
|
||||
Deno.test( 'part 1', () => {
|
||||
expect( p1Solve(reports)).toEqual(598);
|
||||
});
|
||||
|
||||
Deno.test( 'part 2', () => {
|
||||
expect( p2Solve(reports)).toEqual(634);
|
||||
});
|
11
2024/03/Part1.pm
Normal file
11
2024/03/Part1.pm
Normal file
@ -0,0 +1,11 @@
|
||||
use 5.36.0;
|
||||
|
||||
package Day3::Part1;
|
||||
|
||||
sub solve($program) {
|
||||
my $total = 0;
|
||||
$total += $1 * $2 while $program =~ /mul \( (\d+) , (\d+) \)/xg;
|
||||
return $total;
|
||||
}
|
||||
|
||||
1;
|
15
2024/03/Part2.pm
Normal file
15
2024/03/Part2.pm
Normal file
@ -0,0 +1,15 @@
|
||||
use lib qw/ . /;
|
||||
|
||||
use Part1;
|
||||
|
||||
package Day3::Part2;
|
||||
|
||||
use 5.36.0;
|
||||
|
||||
sub solve($program) {
|
||||
my $p = $program;
|
||||
$p =~ s/ don't\(\) .*? (do\(\)|\Z) //smgx;
|
||||
return Day3::Part1::solve($p);
|
||||
}
|
||||
|
||||
1;
|
20
2024/03/test.t
Normal file
20
2024/03/test.t
Normal file
@ -0,0 +1,20 @@
|
||||
use lib qw~ . ~;
|
||||
|
||||
use Part1;
|
||||
use Part2;
|
||||
|
||||
use Test2::V0;
|
||||
use Path::Tiny;
|
||||
|
||||
# my @sample_reports = Day2::Part1::read_file( path('sample')->slurp );
|
||||
my $program = path('input')->slurp ;
|
||||
|
||||
subtest 'part 1' => sub {
|
||||
is Day3::Part1::solve($program) => 184576302;
|
||||
};
|
||||
|
||||
subtest 'part 2' => sub {
|
||||
is Day3::Part2::solve($program) => 118173507;
|
||||
};
|
||||
|
||||
done_testing();
|
47
2024/04/Part1.pm
Normal file
47
2024/04/Part1.pm
Normal file
@ -0,0 +1,47 @@
|
||||
package Part1;
|
||||
|
||||
use 5.36.0;
|
||||
|
||||
no warnings qw/ uninitialized /;
|
||||
|
||||
use Math::VectorXYZ::2D;
|
||||
use List::Util qw/ sum pairmap /;
|
||||
use List::MoreUtils qw/ part zip /;
|
||||
|
||||
sub read_file (@lines) {
|
||||
return [ map { [ split '' ] } @lines ];
|
||||
}
|
||||
|
||||
my @directions;
|
||||
for my $x ( -1 .. 1 ) {
|
||||
for my $y ( -1 .. 1 ) {
|
||||
push @directions, Vec( $x, $y ) if $x or $y;
|
||||
}
|
||||
}
|
||||
|
||||
sub find_word ( $grid, $letters, $loc, $dir ) {
|
||||
|
||||
return 1 unless @$letters;
|
||||
|
||||
$loc += $dir;
|
||||
return 0 if $loc->[0] < 0 or $loc->[1] < 0;
|
||||
|
||||
return 0 if $grid->[ $loc->[0] ][ $loc->[1] ] ne shift @$letters;
|
||||
|
||||
return find_word( $grid, $letters, $loc, $dir );
|
||||
}
|
||||
|
||||
sub solve ($grid) {
|
||||
my $total = 0;
|
||||
for my $x ( 0 .. $grid->$#* ) {
|
||||
for my $y ( 0 .. $grid->[0]->$#* ) {
|
||||
if ( $grid->[$x][$y] eq 'X' ) {
|
||||
$total += find_word( $grid, [qw/M A S/], Vec( $x, $y ), $_ )
|
||||
for @directions;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $total;
|
||||
}
|
||||
|
||||
1;
|
42
2024/04/Part2.pm
Normal file
42
2024/04/Part2.pm
Normal file
@ -0,0 +1,42 @@
|
||||
package Part2;
|
||||
|
||||
use 5.36.0;
|
||||
|
||||
no warnings qw/ uninitialized /;
|
||||
|
||||
use Math::VectorXYZ::2D;
|
||||
use List::Util qw/ sum pairmap /;
|
||||
use List::MoreUtils qw/ part zip /;
|
||||
|
||||
sub find_word ( $grid, @locs ) {
|
||||
|
||||
for (@locs) {
|
||||
return 0 if $_->[0] < 0 or $_->[1] < 0;
|
||||
}
|
||||
|
||||
my $letters = join '', sort map { $grid->[ $_->[0] ][ $_->[1] ] } @locs;
|
||||
|
||||
return $letters eq 'MS';
|
||||
|
||||
}
|
||||
|
||||
sub solve ($grid) {
|
||||
|
||||
my $total = 0;
|
||||
for my $x ( 0 .. $grid->$#* ) {
|
||||
for my $y ( 0 .. $grid->[0]->$#* ) {
|
||||
if ( $grid->[$x][$y] eq 'A' ) {
|
||||
$total++ if 2 == grep {
|
||||
find_word(
|
||||
$grid,
|
||||
Vec( $x, $y ) - Vec(@$_),
|
||||
Vec( $x, $y ) + Vec(@$_)
|
||||
)
|
||||
} [ 1, 1 ], [ -1, 1 ];
|
||||
}
|
||||
}
|
||||
}
|
||||
return $total;
|
||||
}
|
||||
|
||||
1;
|
10
2024/04/sample
Normal file
10
2024/04/sample
Normal file
@ -0,0 +1,10 @@
|
||||
MMMSXXMASM
|
||||
MSAMXMSMSA
|
||||
AMXSXMAAMM
|
||||
MSAMASMSMX
|
||||
XMASAMXAMM
|
||||
XXAMMXXAMA
|
||||
SMSMSASXSS
|
||||
SAXAMASAAA
|
||||
MAMMMXMMMM
|
||||
MXMXAXMASX
|
22
2024/04/test.t
Normal file
22
2024/04/test.t
Normal file
@ -0,0 +1,22 @@
|
||||
use lib qw~ . ~;
|
||||
|
||||
use Part1;
|
||||
use Part2;
|
||||
|
||||
use Test2::V0;
|
||||
use Path::Tiny;
|
||||
|
||||
my $sample = Part1::read_file( path('sample')->lines );
|
||||
my $input= Part1::read_file( path('input')->lines );
|
||||
|
||||
subtest 'part 1' => sub {
|
||||
is Part1::solve($sample) => 18;
|
||||
is Part1::solve($input) => 2336;
|
||||
};
|
||||
|
||||
subtest 'part 2' => sub {
|
||||
is Part2::solve($sample) => 9;
|
||||
is Part2::solve($input) => 1831;
|
||||
};
|
||||
|
||||
done_testing();
|
1
2024/cpanfile
Normal file
1
2024/cpanfile
Normal file
@ -0,0 +1 @@
|
||||
requires 'Math::VectorXYZ';
|
1
2024/settings.json
Normal file
1
2024/settings.json
Normal file
@ -0,0 +1 @@
|
||||
{ "deno.enable": true}
|
Loading…
Reference in New Issue
Block a user