about summary refs log tree commit diff
path: root/aoc2019/Day12.cs
diff options
context:
space:
mode:
Diffstat (limited to 'aoc2019/Day12.cs')
-rw-r--r--aoc2019/Day12.cs127
1 files changed, 127 insertions, 0 deletions
diff --git a/aoc2019/Day12.cs b/aoc2019/Day12.cs
new file mode 100644
index 0000000..04e215e
--- /dev/null
+++ b/aoc2019/Day12.cs
@@ -0,0 +1,127 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace aoc2019
+{
+    public sealed class Day12 : Day
+    {
+        private readonly List<Position> moons;
+        private int step;
+
+        public Day12() : base(12, "The N-Body Problem")
+        {
+            moons = Input
+                .Select(moon =>
+                    moon
+                        .TrimStart('<')
+                        .TrimEnd('>')
+                        .Split(",")
+                        .Select(val => int.Parse(val.Split("=").Last()))
+                )
+                .Select(moon => new Position(moon.ToList()))
+                .ToList();
+
+            foreach (var moon in moons)
+                moon.SetSiblings(moons);
+        }
+
+        public static long LCM(long a, long b)
+        {
+            return a * b / GCD(a, b);
+        }
+
+        public static long GCD(long a, long b)
+        {
+            if (b == 0) return a;
+            return GCD(b, a % b);
+        }
+
+        private void Step()
+        {
+            foreach (var moon in moons)
+                moon.Gravitate();
+
+            foreach (var moon in moons)
+                moon.Move();
+
+            step++;
+        }
+
+        public override string Part1()
+        {
+            while (step < 1000)
+                Step();
+
+            return $"{moons.Sum(p => p.TotalEnergy)}";
+        }
+
+        public override string Part2()
+        {
+            int cycleX = 0, cycleY = 0, cycleZ = 0;
+
+            while (cycleX == 0 || cycleY == 0 || cycleZ == 0)
+            {
+                Step();
+                if (cycleX == 0 && moons.All(m => m.dx == 0)) cycleX = step * 2;
+                if (cycleY == 0 && moons.All(m => m.dy == 0)) cycleY = step * 2;
+                if (cycleZ == 0 && moons.All(m => m.dz == 0)) cycleZ = step * 2;
+            }
+
+            return $"{LCM(cycleX, LCM(cycleY, cycleZ))}";
+        }
+
+        public class Position
+        {
+            public int dx, dy, dz;
+            private List<Position> siblings;
+            public int x, y, z;
+
+            public Position(IList<int> moon)
+            {
+                x = moon[0];
+                y = moon[1];
+                z = moon[2];
+                dx = 0;
+                dy = 0;
+                dz = 0;
+            }
+
+            internal int KineticEnergy =>
+                Math.Abs(x) + Math.Abs(y) + Math.Abs(z);
+
+            internal int PotentialEnergy =>
+                Math.Abs(dx) + Math.Abs(dy) + Math.Abs(dz);
+
+            internal int TotalEnergy =>
+                KineticEnergy * PotentialEnergy;
+
+            public void SetSiblings(List<Position> positions)
+            {
+                siblings = positions.Where(p => p != this).ToList();
+            }
+
+            public override string ToString()
+            {
+                return $"pos=<x={x}, y={y}, z={z}> vel=<x={dx}, y={dy}, z={dz}>";
+            }
+
+            internal void Gravitate()
+            {
+                foreach (var m in siblings)
+                {
+                    if (x != m.x) dx += x > m.x ? -1 : 1;
+                    if (y != m.y) dy += y > m.y ? -1 : 1;
+                    if (z != m.z) dz += z > m.z ? -1 : 1;
+                }
+            }
+
+            internal void Move()
+            {
+                x += dx;
+                y += dy;
+                z += dz;
+            }
+        }
+    }
+}
\ No newline at end of file