Day 13: Claw Contraption

Megathread guidelines

  • Keep top level comments as only solutions, if you want to say something other than a solution put it in a new post. (replies to comments can be whatever)
  • You can send code in code blocks by using three backticks, the code, and then three backticks or use something such as https://topaz.github.io/paste/ if you prefer sending it through a URL

FAQ

  • @[email protected]
    link
    fedilink
    211 hours ago

    C#

    Thank goodness for high school algebra!

    using System.Diagnostics;
    using Common;
    
    namespace Day13;
    
    static class Program
    {
        static void Main()
        {
            var start = Stopwatch.GetTimestamp();
    
            var sampleInput = Input.ParseInput("sample.txt");
            var programInput = Input.ParseInput("input.txt");
    
            Console.WriteLine($"Part 1 sample: {Part1(sampleInput)}");
            Console.WriteLine($"Part 1 input: {Part1(programInput)}");
    
            Console.WriteLine($"Part 2 sample: {Part2(sampleInput)}");
            Console.WriteLine($"Part 2 input: {Part2(programInput)}");
    
            Console.WriteLine($"That took about {Stopwatch.GetElapsedTime(start)}");
        }
    
        static object Part1(Input i) => i.Machines
            .Select(m => CalculateCoins(m, 100))
            .Where(c => c > 0)
            .Sum();
    
        static object Part2(Input i) => i.Machines
            .Select(m => m with { Prize = new XYValues(
                m.Prize.X + 10000000000000,
                m.Prize.Y + 10000000000000) })
            .Select(m => CalculateCoins(m, long.MaxValue))
            .Where(c => c > 0)
            .Sum();
    
        static long CalculateCoins(Machine m, long limit)
        {
            var bBottom = (m.A.X * m.B.Y) - (m.A.Y * m.B.X);
            if (bBottom == 0) return -1;
    
            var bTop = (m.Prize.Y * m.A.X) - (m.Prize.X * m.A.Y);
            var b = bTop / bBottom;
            if ((b <= 0) || (b > limit)) return -1;
            
            var a = (m.Prize.X - (b * m.B.X)) / m.A.X;
            if ((a <= 0) || (a > limit)) return -1;
    
            var calcPrizeX = (a * m.A.X) + (b * m.B.X);
            var calcPrizeY = (a * m.A.Y) + (b * m.B.Y);
            if ((m.Prize.X != calcPrizeX) || (m.Prize.Y != calcPrizeY)) return -1;
    
            return (3 * a) + b;
        }
    }
    
    public record struct Machine(XYValues A, XYValues B, XYValues Prize);
    public record struct XYValues(long X, long Y);
    
    public class Input
    {
        private Input()
        {
        }
    
        public List<Machine> Machines { get; init; }
    
        public static Input ParseInput(string file)
        {
            var machines = new List<Machine>();
    
            var lines = File.ReadAllLines(file);
            for(int l=0; l<lines.Length; l+=4)
            {
                machines.Add(new Machine(
                    ParseXYValues(lines[l + 0]),
                    ParseXYValues(lines[l + 1]),
                    ParseXYValues(lines[l + 2])));
            }
    
            return new Input()
            {
                Machines = machines,
            };
        }
    
        private static readonly char[] XYDelimiters = ['X', 'Y', '=', '+', ',', ' '];
    
        private static XYValues ParseXYValues(string s)
        {
            var parts = s
                .Substring(s.IndexOf(':') + 1)
                .SplitAndTrim(XYDelimiters)
                .Select(long.Parse)
                .ToArray();
            
            return new XYValues(parts[0], parts[1]);
        }
    }