From 84569ee1c960f0421901461a25bbc4481e332556 Mon Sep 17 00:00:00 2001 From: Martin Zikmund Date: Fri, 13 Dec 2024 09:43:48 +0100 Subject: [PATCH] AoC 2024 Day 13 Solutions --- .../2024/13/Part1/Part1.cs | 99 +++++++++++++++++ .../2024/13/Part2/Part2.cs | 100 ++++++++++++++++++ src/AdventOfCode.Puzzles/2024/13/TestData.txt | 15 +++ 3 files changed, 214 insertions(+) create mode 100644 src/AdventOfCode.Puzzles/2024/13/Part1/Part1.cs create mode 100644 src/AdventOfCode.Puzzles/2024/13/Part2/Part2.cs create mode 100644 src/AdventOfCode.Puzzles/2024/13/TestData.txt diff --git a/src/AdventOfCode.Puzzles/2024/13/Part1/Part1.cs b/src/AdventOfCode.Puzzles/2024/13/Part1/Part1.cs new file mode 100644 index 0000000..6db981d --- /dev/null +++ b/src/AdventOfCode.Puzzles/2024/13/Part1/Part1.cs @@ -0,0 +1,99 @@ +using AdventOfCode.Puzzles.Tools; + +namespace AdventOfCode.Puzzles._2024._13.Part1; + +public partial class Part1 : IPuzzleSolution +{ + public Task SolveAsync(StreamReader inputReader) + { + long total = 0; + while (TryReadClawMachine(inputReader, out var clawMachine)) + { + var price = SolveClawMachine(clawMachine); + if (price > 0) + { + total += price; + } + } + + return Task.FromResult(total.ToString()); + } + + private long SolveClawMachine(ClawMachine clawMachine) + { + var buttonA = clawMachine.ButtonA; + var buttonB = clawMachine.ButtonB; + var prize = clawMachine.Prize; + + // a*ax + b*bx = prizeX + // a*ay + b*by = prizeY + // a = (prizeX - b*bx) / ax + // ((prizeX - b*bx) / ax) * ay + b*by = prizeY + // ((prizeX / ax) - (b*bx / ax)) * ay + b*by = prizeY + // (prizeX / ax) * ay - (b*bx / ax) * ay + b*by = prizeY + // - (b * bx / ax) * ay + b * by = prizeY - (prizeX / ax) * ay + // b * by - (b* bx / ax) * ay = prizeY - (prizeX / ax) * ay + // b * (by - (bx / ax) * ay) = prizeY - (prizeX / ax) * ay + // b = (prizeY - (prizeX / ax) * ay) / (by - (bx / ax) * ay) + + var prizeX = (double)prize.X; + var prizeY = (double)prize.Y; + var buttonAX = (double)buttonA.X; + var buttonAY = (double)buttonA.Y; + var buttonBX = (double)buttonB.X; + var buttonBY = (double)buttonB.Y; + + long b = (long)Math.Round((prizeY - (prizeX / buttonAX) * buttonAY) / (buttonBY - (buttonBX / buttonAX) * buttonAY)); + long a = (long)Math.Round((prizeX - b * buttonBX) / buttonAX); + + var actualX = a * buttonAX + b * buttonBX; + var actualY = a * buttonAY + b * buttonBY; + if (actualX == prize.X && actualY == prize.Y && a >= 0 && b >= 0) + { + return a * 3 + b; + } + + return -1; + } + + private bool TryReadClawMachine(StreamReader reader, out ClawMachine clawMachine) + { + clawMachine = default; + var line = reader.ReadLine(); + if (line == null) + { + return false; + } + + if (string.IsNullOrWhiteSpace(line)) + { + line = reader.ReadLine(); + } + + var buttonALine = line; + var buttonBLine = reader.ReadLine(); + var prizeLine = reader.ReadLine(); + + var parts = buttonALine.Split(":")[1].Split(','); + var buttonAX = int.Parse(parts[0].Trim().Substring(2)); + var buttonAY = int.Parse(parts[1].Trim().Substring(2)); + + parts = buttonBLine.Split(":")[1].Split(','); + var buttonBX = int.Parse(parts[0].Trim().Substring(2)); + var buttonBY = int.Parse(parts[1].Trim().Substring(2)); + + parts = prizeLine.Split(":")[1].Split(','); + var prizeX = int.Parse(parts[0].Trim().Substring(2)); + var prizeY = int.Parse(parts[1].Trim().Substring(2)); + + clawMachine = new ClawMachine( + (buttonAX, buttonAY), + (buttonBX, buttonBY), + (prizeX, prizeY) + ); + + return true; + } + + public record ClawMachine(Point ButtonA, Point ButtonB, Point Prize); +} diff --git a/src/AdventOfCode.Puzzles/2024/13/Part2/Part2.cs b/src/AdventOfCode.Puzzles/2024/13/Part2/Part2.cs new file mode 100644 index 0000000..ec4f02b --- /dev/null +++ b/src/AdventOfCode.Puzzles/2024/13/Part2/Part2.cs @@ -0,0 +1,100 @@ +using System.Diagnostics; +using AdventOfCode.Puzzles.Tools; + +namespace AdventOfCode.Puzzles._2024._13.Part2; + +public partial class Part2 : IPuzzleSolution +{ + public Task SolveAsync(StreamReader inputReader) + { + long total = 0; + while (TryReadClawMachine(inputReader, out var clawMachine)) + { + var price = SolveClawMachine(clawMachine); + if (price > 0) + { + total += price; + } + } + + return Task.FromResult(total.ToString()); + } + + private long SolveClawMachine(ClawMachine clawMachine) + { + var buttonA = clawMachine.ButtonA; + var buttonB = clawMachine.ButtonB; + var prize = clawMachine.Prize; + + // a*ax + b*bx = prizeX + // a*ay + b*by = prizeY + // a = (prizeX - b*bx) / ax + // ((prizeX - b*bx) / ax) * ay + b*by = prizeY + // ((prizeX / ax) - (b*bx / ax)) * ay + b*by = prizeY + // (prizeX / ax) * ay - (b*bx / ax) * ay + b*by = prizeY + // - (b * bx / ax) * ay + b * by = prizeY - (prizeX / ax) * ay + // b * by - (b* bx / ax) * ay = prizeY - (prizeX / ax) * ay + // b * (by - (bx / ax) * ay) = prizeY - (prizeX / ax) * ay + // b = (prizeY - (prizeX / ax) * ay) / (by - (bx / ax) * ay) + + var prizeX = 10000000000000 + (double)prize.X; + var prizeY = 10000000000000 + (double)prize.Y; + var buttonAX = (double)buttonA.X; + var buttonAY = (double)buttonA.Y; + var buttonBX = (double)buttonB.X; + var buttonBY = (double)buttonB.Y; + + long b = (long)Math.Round((prizeY - (prizeX / buttonAX) * buttonAY) / (buttonBY - (buttonBX / buttonAX) * buttonAY)); + long a = (long)Math.Round((prizeX - b * buttonBX) / buttonAX); + + var actualX = a * buttonAX + b * buttonBX; + var actualY = a * buttonAY + b * buttonBY; + if (actualX == prizeX && actualY == prizeY && a >= 0 && b >= 0) + { + return a * 3 + b; + } + + return -1; + } + + private bool TryReadClawMachine(StreamReader reader, out ClawMachine clawMachine) + { + clawMachine = default; + var line = reader.ReadLine(); + if (line == null) + { + return false; + } + + if (string.IsNullOrWhiteSpace(line)) + { + line = reader.ReadLine(); + } + + var buttonALine = line; + var buttonBLine = reader.ReadLine(); + var prizeLine = reader.ReadLine(); + + var parts = buttonALine.Split(":")[1].Split(','); + var buttonAX = int.Parse(parts[0].Trim().Substring(2)); + var buttonAY = int.Parse(parts[1].Trim().Substring(2)); + + parts = buttonBLine.Split(":")[1].Split(','); + var buttonBX = int.Parse(parts[0].Trim().Substring(2)); + var buttonBY = int.Parse(parts[1].Trim().Substring(2)); + + parts = prizeLine.Split(":")[1].Split(','); + var prizeX = int.Parse(parts[0].Trim().Substring(2)); + var prizeY = int.Parse(parts[1].Trim().Substring(2)); + + clawMachine = new ClawMachine( + (buttonAX, buttonAY), + (buttonBX, buttonBY), + (prizeX, prizeY) + ); + + return true; + } + + public record ClawMachine(Point ButtonA, Point ButtonB, Point Prize); +} diff --git a/src/AdventOfCode.Puzzles/2024/13/TestData.txt b/src/AdventOfCode.Puzzles/2024/13/TestData.txt new file mode 100644 index 0000000..912f482 --- /dev/null +++ b/src/AdventOfCode.Puzzles/2024/13/TestData.txt @@ -0,0 +1,15 @@ +Button A: X+94, Y+34 +Button B: X+22, Y+67 +Prize: X=8400, Y=5400 + +Button A: X+26, Y+66 +Button B: X+67, Y+21 +Prize: X=12748, Y=12176 + +Button A: X+17, Y+86 +Button B: X+84, Y+37 +Prize: X=7870, Y=6450 + +Button A: X+69, Y+23 +Button B: X+27, Y+71 +Prize: X=18641, Y=10279