01020304050607080910111213141516171819202122232425

Advent of Code

2019/12

The N-Body Problem

in C#

by encse

The space near Jupiter is not a very safe place; you need to be careful of a big distracting red spot, extreme radiation, and a whole lot of moons swirling around. You decide to start by tracking the four largest moons: Io, Europa, Ganymede, and Callisto.

After a brief scan, you calculate the position of each moon (your puzzle input). You just need to simulate their motion so you can avoid them.

Read the full puzzle.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

namespace AdventOfCode.Y2019.Day12;

[ProblemName("The N-Body Problem")]
class Solution : Solver {

    public object PartOne(string input) => (
            from planet in Simulate(input).ElementAt(999)
            let pot = planet.pos.Select(Math.Abs).Sum()
            let kin = planet.vel.Select(Math.Abs).Sum()
            select pot * kin
        ).Sum();

    public object PartTwo(string input) {
        var statesByDim = new long[3];
        for (var dim = 0; dim < 3; dim++) {
            var states = new HashSet<(int,int,int,int,int,int,int,int)>();
            foreach (var planets in Simulate(input)) {
                var state = (planets[0].pos[dim], planets[1].pos[dim], planets[2].pos[dim], planets[3].pos[dim],
                             planets[0].vel[dim], planets[1].vel[dim], planets[2].vel[dim], planets[3].vel[dim]);
                if (states.Contains(state)) {
                    break;
                }
                states.Add(state);
            }
            statesByDim[dim] = states.Count;
        }

        return Lcm(statesByDim[0], Lcm(statesByDim[1], statesByDim[2]));
    }

    long Lcm(long a, long b) => a * b / Gcd(a, b);
    long Gcd(long a, long b) => b == 0 ? a : Gcd(b, a % b);

    IEnumerable<(int[] pos, int[] vel)[]> Simulate(string input) {
        var planets = (
            from line in input.Split("\n")
            let m = Regex.Matches(line, @"-?\d+")
            let pos = (from v in m select int.Parse(v.Value)).ToArray()
            let vel = new int[3]
            select (pos, vel)
        ).ToArray();

        while (true) {
            foreach (var planetA in planets) {
                foreach (var planetB in planets) {
                    for (var dim = 0; dim < 3; dim++) {
                        planetA.vel[dim] += Math.Sign(planetB.pos[dim] - planetA.pos[dim]);
                    }
                }
            }

            foreach (var planet in planets) {
                for (var dim = 0; dim < 3; dim++) {
                    planet.pos[dim] += planet.vel[dim];
                }
            }

            yield return planets;
        }
    }
}

Please ☆ my repo if you like it!

© 2025 Advent of Code is a registered trademark in the US Images provided by Bing image creator