12 changed files with 286 additions and 25 deletions
@ -0,0 +1,56 @@
@@ -0,0 +1,56 @@
|
||||
package Part1; |
||||
|
||||
use 5.36.0; |
||||
|
||||
our @ISA = 'Exporter'; |
||||
our @EXPORT_OK = qw/ part1 $sample /; |
||||
|
||||
use Path::Tiny; |
||||
|
||||
our $sample = path('./sample')->slurp; |
||||
|
||||
sub parse_heaps($heaps) { |
||||
my( $header, @crates ) = reverse split "\n", $heaps; |
||||
|
||||
my @stacks; |
||||
|
||||
while( $header !~ /^\s*$/ ) { |
||||
$header =~ s/^(\s+)\d//; |
||||
my $n = length $1; |
||||
@crates = map { no warnings; substr $_, $n } @crates; |
||||
|
||||
my @stack = grep { /\w/ } map { no warnings; s/(.)//; $1 } @crates; |
||||
push @stacks, \@stack; |
||||
} |
||||
|
||||
return @stacks; |
||||
} |
||||
|
||||
sub parse_commands($text) { |
||||
return map { [/\d+/g] } split "\n", $text |
||||
} |
||||
|
||||
sub move_stacks($stacks, $commands) { |
||||
for my $command ( @$commands ) { |
||||
for( 1..$command->[0] ) { |
||||
push $stacks->[$command->[2] - 1]->@*, |
||||
pop $stacks->[$command->[1]- 1]->@*; |
||||
|
||||
} |
||||
} |
||||
|
||||
return @$stacks; |
||||
} |
||||
|
||||
sub part1($text) { |
||||
my( $heaps, $commands ) = split "\n\n", $text; |
||||
|
||||
my @heaps = parse_heaps($heaps); |
||||
my @commands = parse_commands($commands); |
||||
|
||||
my @stacks = move_stacks( \@heaps, \@commands ); |
||||
|
||||
return join '', map { pop @$_ } @stacks; |
||||
} |
||||
|
||||
1; |
@ -0,0 +1,91 @@
@@ -0,0 +1,91 @@
|
||||
import * as R from "remeda"; |
||||
|
||||
import fs from "fs-extra"; |
||||
import path from "path"; |
||||
import { fileURLToPath } from "url"; |
||||
|
||||
export const readFile = (url, file) => |
||||
fs.readFileSync(path.join(fileURLToPath(new URL(".", url)), file), "utf8"); |
||||
|
||||
export const sample = readFile(import.meta.url, "sample"); |
||||
export const puzzleInput = readFile(import.meta.url, "input"); |
||||
|
||||
function parseHeaps(text) { |
||||
const lines = text.split("\n").filter(R.identity); |
||||
lines.reverse(); |
||||
|
||||
let [header, ...crates] = lines; |
||||
|
||||
const stacks = []; |
||||
|
||||
while (header.trimEnd()) { |
||||
header = header.replace(/^(\s+)\d/, (...args) => { |
||||
crates = crates.map((c) => c.slice(args[1].length)); |
||||
|
||||
const stack = []; |
||||
|
||||
crates = crates.map((l) => |
||||
l.replace(/./, (c) => { |
||||
if (c !== " ") stack.push(c); |
||||
return ""; |
||||
}) |
||||
); |
||||
|
||||
stacks.push(stack); |
||||
|
||||
return ""; |
||||
}); |
||||
} |
||||
|
||||
return stacks; |
||||
} |
||||
|
||||
function parseCommands(text) { |
||||
return text |
||||
.split("\n") |
||||
.filter(R.identity) |
||||
.map((line) => line.match(/\d+/g).map((x) => parseInt(x))); |
||||
} |
||||
|
||||
function moveStacks([stacks, commands]) { |
||||
for (let [move, from, to] of commands) { |
||||
console.log({ move, from, to }); |
||||
|
||||
while (move-- > 0) { |
||||
stacks[to - 1].push(stacks[from - 1].pop()); |
||||
} |
||||
} |
||||
|
||||
return stacks; |
||||
} |
||||
|
||||
<<<<<<< HEAD |
||||
const spy = (x) => { |
||||
console.log(x); |
||||
return x; |
||||
}; |
||||
|
||||
export const solutionPart1 = R.createPipe( |
||||
(text) => text.split("\n\n"), |
||||
([heaps, commands]) => [parseHeaps(heaps), parseCommands(commands)], |
||||
moveStacks, |
||||
spy, |
||||
======= |
||||
export const spy = (x) => { |
||||
console.log(x); |
||||
return x; |
||||
}; |
||||
|
||||
export const parseLines = ([heaps, commands]) => [ |
||||
parseHeaps(heaps), |
||||
parseCommands(commands), |
||||
]; |
||||
|
||||
export const solutionPart1 = R.createPipe( |
||||
(text) => text.split("\n\n"), |
||||
parseLines, |
||||
moveStacks, |
||||
>>>>>>> 2a1e7da (part 1) |
||||
R.map((x) => x.pop()), |
||||
(x) => x.join("") |
||||
); |
@ -1 +1,24 @@
@@ -1 +1,24 @@
|
||||
import * as R from "remeda"; |
||||
|
||||
import { parseLines, spy } from "./part1.js"; |
||||
|
||||
function moveStacks([stacks, commands]) { |
||||
for (let [move, from, to] of commands) { |
||||
console.log({ move, from, to }); |
||||
|
||||
stacks[to - 1].push( |
||||
...stacks[from - 1].splice(stacks[from - 1].length - move) |
||||
); |
||||
} |
||||
|
||||
return stacks; |
||||
} |
||||
|
||||
export default R.createPipe( |
||||
(text) => text.split("\n\n"), |
||||
parseLines, |
||||
moveStacks, |
||||
spy, |
||||
R.map((x) => x.pop()), |
||||
(x) => x.join("") |
||||
); |
||||
|
@ -0,0 +1,8 @@
@@ -0,0 +1,8 @@
|
||||
use 5.36.0; |
||||
|
||||
use Test2::V0; |
||||
|
||||
use Part1 qw/ part1 $sample /; |
||||
|
||||
is part1($sample) => 'CMZ'; |
||||
|
@ -1,20 +1,17 @@
@@ -1,20 +1,17 @@
|
||||
import { test, expect, describe } from "vitest"; |
||||
|
||||
import { expectSolution } from "../01/main.js"; |
||||
import { |
||||
solutionPart1, |
||||
puzzleInput, |
||||
} from "./part1.js"; |
||||
import { solutionPart1, puzzleInput } from "./part1.js"; |
||||
import { solutionPart2 } from "./part2.js"; |
||||
|
||||
describe("part 1", () => { |
||||
test.todo("solution", () => { |
||||
expectSolution(solutionPart1(puzzleInput)).toEqual('TODO'); |
||||
expectSolution(solutionPart1(puzzleInput)).toEqual("TODO"); |
||||
}); |
||||
}); |
||||
|
||||
describe("part 2", () => { |
||||
test.todo("solution", () => { |
||||
expectSolution(solutionPart2(puzzleInput)).toEqual('TODO'); |
||||
expectSolution(solutionPart2(puzzleInput)).toEqual("TODO"); |
||||
}); |
||||
}); |
||||
|
Loading…
Reference in new issue