package main import ( "bufio" "fmt" "log" "os" "strings" ) func abs(a int) int { if a < 0 { a = -a } return a } type Moon struct { x, y, z int vx, vy, vz int } func (m *Moon) CalcVelocity(self int, moons []Moon) { for i := range moons { if i == self { continue } if m.x > moons[i].x { m.vx-- } else if m.x < moons[i].x { m.vx++ } if m.y > moons[i].y { m.vy-- } else if m.y < moons[i].y { m.vy++ } if m.z > moons[i].z { m.vz-- } else if m.z < moons[i].z { m.vz++ } } } func (m *Moon) Step() { m.x += m.vx m.y += m.vy m.z += m.vz } func (m *Moon) Energy() int { pot := abs(m.x) + abs(m.y) + abs(m.z) kin := abs(m.vx) + abs(m.vy) + abs(m.vz) return pot * kin } func IterateMoons(moons []Moon, steps int, debug bool) int { for i := 0; i < steps; i++ { if debug { fmt.Printf("Step %d\n", i+1) } for j := range moons { moons[j].CalcVelocity(j, moons) } for j := range moons { moons[j].Step() if debug { fmt.Printf("%+v\n", moons[j]) } } if debug { fmt.Println() } } var energy int for i := range moons { energy += moons[i].Energy() } return energy } func gcd(a, b int) int { for b != 0 { a, b = b, a%b /*t := b b = a % b a = t*/ } return a } func lcm(a, b, c int) int { result := a * b / gcd(a, b) result = result * c / gcd(result, c) return result } func FindSteps(moons []Moon, debug bool) int { initial := make([]Moon, len(moons)) var xFound, yFound, zFound bool xSteps, ySteps, zSteps := 1, 1, 1 copy(initial, moons) for { for i := range moons { moons[i].CalcVelocity(i, moons) } xLooped := true yLooped := true zLooped := true for i := range moons { moons[i].Step() if moons[i].x != initial[i].x || moons[i].vx != initial[i].vx { xLooped = false } if moons[i].y != initial[i].y || moons[i].vy != initial[i].vy { yLooped = false } if moons[i].z != initial[i].z || moons[i].vz != initial[i].vz { zLooped = false } } if xLooped { xFound = true } if yLooped { yFound = true } if zLooped { zFound = true } if !xFound { xSteps++ } if !yFound { ySteps++ } if !zFound { zSteps++ } if xFound && yFound && zFound { break } } return lcm(xSteps, ySteps, zSteps) } func main() { input, err := os.Open("input.txt") if err != nil { log.Fatal(fmt.Errorf("could not open input file: %w", err)) } defer input.Close() scanner := bufio.NewScanner(input) scanner.Split(bufio.ScanLines) moons := make([]Moon, 0) for scanner.Scan() { var moon Moon line := strings.TrimSpace(scanner.Text()) fmt.Sscanf(line, "", &moon.x, &moon.y, &moon.z) moons = append(moons, moon) } fmt.Printf("Part 1: %d\n", IterateMoons(moons, 1000, false)) fmt.Printf("Part 2: %d\n", FindSteps(moons, false)) }