diff --git a/day13.peggy b/day13.peggy new file mode 100644 index 0000000..647f2a0 --- /dev/null +++ b/day13.peggy @@ -0,0 +1,9 @@ +machines = machine|.., "\n"| + +machine = button button prize + +button = "Button" _ [AB] ":" _ "X+" @num _ "," _ "Y+" _ @num "\n" +prize = "Prize:" _ "X=" @num _ "," _ "Y=" _ @num "\n" + +num = n:$[0-9]+ { return parseInt(n, 10) } +_ = [ \t]* diff --git a/day13.ts b/day13.ts new file mode 100644 index 0000000..899fd12 --- /dev/null +++ b/day13.ts @@ -0,0 +1,38 @@ +import { type MainArgs, parseFile } from './lib/utils.ts'; + +type Parsed = number[][][]; + +function cranmer(coeff: number[]): number { + const [x0, y0, c0, x1, y1, c1] = coeff; + // Cranmer's rule + const D = x0 * y1 - y0 * x1; + const Dx = c0 * y1 - y0 * c1; + const Dy = x0 * c1 - c0 * x1; + if ((Dx % D) || (Dy % D)) { + return 0; + } + const x = Dx / D; + const y = Dy / D; + return (3 * x) + y; +} + +function part1(inp: Parsed): number { + return inp.reduce( + (t, [[x0, x1], [y0, y1], [c0, c1]]) => + t + cranmer([x0, y0, c0, x1, y1, c1]), + 0, + ); +} + +function part2(inp: Parsed): number { + return inp.reduce( + (t, [[x0, x1], [y0, y1], [c0, c1]]) => + t + cranmer([x0, y0, c0 + 10000000000000, x1, y1, c1 + 10000000000000]), + 0, + ); +} + +export default async function main(args: MainArgs): Promise<[number, number]> { + const inp = await parseFile(args); + return [part1(inp), part2(inp)]; +} diff --git a/inputs b/inputs index ee25601..7cedb20 160000 --- a/inputs +++ b/inputs @@ -1 +1 @@ -Subproject commit ee256012107eb30e9252cf6394fd92a7d5601a09 +Subproject commit 7cedb20b92ea6dcfe7375f374e0f38e3b251e1af diff --git a/lib/utils.ts b/lib/utils.ts index 75046e2..3efaa8d 100644 --- a/lib/utils.ts +++ b/lib/utils.ts @@ -211,6 +211,62 @@ export function divmod(x: T, y: T): [T, T] { return [Math.floor(q) as T, r]; } +export function abs(a: T): T { + if (typeof a === 'bigint') { + return (a < 0 ? -a : a) as T; + } + return Math.abs(a) as T; +} + +export function sign(a: T): T { + if (typeof a === 'bigint') { + if (a === 0n) { + return 0n as T; + } + return ((a < 0n) ? -1n : 1n) as T; + } + return Math.sign(a) as T; +} + +export function egcd( + a: T, + b: T, +): [gcd: T, a: T, b: T] { + const bi = typeof a === 'bigint'; + let s0 = (bi ? 1n : 1) as T; + let s1 = (bi ? 0n : 0) as T; + let t0 = s1; + let t1 = s0; + const sa = sign(a); + const sb = sign(b); + + // Needs to work for both 0 and 0n + // deno-lint-ignore eqeqeq + if (a == 0) { + return [b, s1, t1]; + } + if (!bi) { + if ((isNaN(a as number) || isNaN(b as number))) { + return [NaN as T, NaN as T, NaN as T]; + } + if ((!isFinite(a as number) || !isFinite(b as number))) { + return [Infinity as T, Infinity as T, Infinity as T]; + } + } + + a = abs(a); + b = abs(b); + + // deno-lint-ignore eqeqeq + while (b != 0) { + const [q, r] = divmod(a, b); + [s0, s1] = [s1, (s0 - (q * s1)) as T]; + [t0, t1] = [t1, (t0 - (q * t1)) as T]; + [a, b] = [b, r]; + } + return [a, sa * s0 as T, sb * t0 as T]; +} + export function gcd(...n: T[]): T { switch (n.length) { case 0: diff --git a/test/day13.js b/test/day13.js new file mode 100644 index 0000000..d346135 --- /dev/null +++ b/test/day13.js @@ -0,0 +1 @@ +export default [40069, 71493195288102];