83 lines
1.9 KiB
Nix
83 lines
1.9 KiB
Nix
{lib, ...}: input: let
|
|
inherit (builtins) elemAt match filter foldl';
|
|
inherit (lib.strings) toIntBase10;
|
|
inherit (lib) mod;
|
|
|
|
acost = 3;
|
|
bcost = 1;
|
|
part2offset = 10000000000000;
|
|
|
|
machines = input
|
|
|> lib.trim
|
|
|> lib.splitString "\n\n"
|
|
|> map (text: let
|
|
parts = text |> lib.splitString "\n";
|
|
buttona = elemAt parts 0;
|
|
buttonb = elemAt parts 1;
|
|
prize = elemAt parts 2;
|
|
in {
|
|
a = buttonToVec buttona;
|
|
b = buttonToVec buttonb;
|
|
prize = prizeToVec prize;
|
|
}
|
|
)
|
|
;
|
|
|
|
buttonToVec = text: text
|
|
|> match ''Button .: X\+([0-9]+), Y\+([0-9]+)''
|
|
|> map toIntBase10
|
|
|> (nums: {
|
|
x = elemAt nums 0;
|
|
y = elemAt nums 1;
|
|
})
|
|
;
|
|
prizeToVec = text: text
|
|
|> match ''Prize: X=([0-9]+), Y=([0-9]+)''
|
|
|> map toIntBase10
|
|
|> (nums: {
|
|
x = elemAt nums 0;
|
|
y = elemAt nums 1;
|
|
})
|
|
;
|
|
|
|
getPresses = {a, b, prize}:
|
|
let
|
|
# see https://www.desmos.com/calculator/qfzdjjffso
|
|
# ma = 1.0 * a.y / a.x;
|
|
# mb = 1.0 * b.y / b.x;
|
|
# c = prize.y - prize.x * mb;
|
|
# x = c / (ma - mb);
|
|
|
|
# rearranged to avoid precision errors
|
|
x = (b.x * prize.y - prize.x * b.y) * a.x / (b.x * a.y - a.x * b.y);
|
|
|
|
apresses = x / a.x;
|
|
bpresses = (prize.x - x) / b.x;
|
|
in {
|
|
a = apresses;
|
|
b = bpresses;
|
|
doable = a.x * apresses + b.x * bpresses == prize.x &&
|
|
a.y * apresses + b.y * bpresses == prize.y;
|
|
};
|
|
|
|
in {
|
|
inherit machines buttonToVec prizeToVec getPresses;
|
|
|
|
part1result = machines
|
|
|> map getPresses
|
|
|> filter ({doable, ...}: doable)
|
|
|> foldl' (cost: {a,b,...}: cost + a * acost + b * bcost) 0
|
|
;
|
|
|
|
part2result = machines
|
|
|> map (machine: machine // {prize = {
|
|
x = machine.prize.x + part2offset;
|
|
y = machine.prize.y + part2offset;
|
|
};})
|
|
|> map getPresses
|
|
|> filter ({doable, ...}: doable)
|
|
|> foldl' (cost: {a,b,...}: cost + a * acost + b * bcost) 0
|
|
;
|
|
|
|
}
|