Day 12 solution
Okay, I had to seek help on this one. The orbital period + least-common-multiple solution was not coming to me.
This commit is contained in:
156
days/12.go
Normal file
156
days/12.go
Normal file
@ -0,0 +1,156 @@
|
||||
package days
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
u "parnic.com/aoc2019/utilities"
|
||||
)
|
||||
|
||||
type moonData struct {
|
||||
pos u.Vec3[int]
|
||||
vel u.Vec3[int]
|
||||
}
|
||||
|
||||
func (m *moonData) applyGravity(other *moonData) {
|
||||
applyGravityAxis := func(pos1, pos2, vel1, vel2 *int) {
|
||||
if *pos1 < *pos2 {
|
||||
*vel1++
|
||||
*vel2--
|
||||
} else if *pos1 > *pos2 {
|
||||
*vel1--
|
||||
*vel2++
|
||||
}
|
||||
}
|
||||
|
||||
applyGravityAxis(&m.pos.X, &other.pos.X, &m.vel.X, &other.vel.X)
|
||||
applyGravityAxis(&m.pos.Y, &other.pos.Y, &m.vel.Y, &other.vel.Y)
|
||||
applyGravityAxis(&m.pos.Z, &other.pos.Z, &m.vel.Z, &other.vel.Z)
|
||||
}
|
||||
|
||||
func (m *moonData) applyVelocity() {
|
||||
m.pos.Add(m.vel)
|
||||
}
|
||||
|
||||
func (m moonData) getPotentialEnergy() int {
|
||||
return int(math.Abs(float64(m.pos.X))) +
|
||||
int(math.Abs(float64(m.pos.Y))) +
|
||||
int(math.Abs(float64(m.pos.Z)))
|
||||
}
|
||||
|
||||
func (m moonData) getKineticEnergy() int {
|
||||
return int(math.Abs(float64(m.vel.X))) +
|
||||
int(math.Abs(float64(m.vel.Y))) +
|
||||
int(math.Abs(float64(m.vel.Z)))
|
||||
}
|
||||
|
||||
func (m moonData) getTotalEnergy() int {
|
||||
return m.getPotentialEnergy() * m.getKineticEnergy()
|
||||
}
|
||||
|
||||
type Day12 struct {
|
||||
moons []*moonData
|
||||
}
|
||||
|
||||
func (d *Day12) Parse() {
|
||||
lines := u.GetStringLines("12p")
|
||||
d.moons = make([]*moonData, len(lines))
|
||||
for i, line := range lines {
|
||||
trimmed := line[1 : len(line)-1]
|
||||
vals := strings.Split(trimmed, ", ")
|
||||
x, _ := strconv.Atoi(vals[0][2:])
|
||||
y, _ := strconv.Atoi(vals[1][2:])
|
||||
z, _ := strconv.Atoi(vals[2][2:])
|
||||
d.moons[i] = &moonData{
|
||||
pos: u.Vec3[int]{X: x, Y: y, Z: z},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d Day12) Num() int {
|
||||
return 12
|
||||
}
|
||||
|
||||
func (d Day12) copyMoons() []*moonData {
|
||||
moons := make([]*moonData, len(d.moons))
|
||||
for i, moon := range d.moons {
|
||||
moonCopy := *moon
|
||||
moons[i] = &moonCopy
|
||||
}
|
||||
|
||||
return moons
|
||||
}
|
||||
|
||||
func getAllEnergy(moons ...*moonData) int {
|
||||
energy := 0
|
||||
for _, moon := range moons {
|
||||
energy += moon.getTotalEnergy()
|
||||
}
|
||||
return energy
|
||||
}
|
||||
|
||||
func (d *Day12) Part1() string {
|
||||
moons := d.copyMoons()
|
||||
|
||||
numSteps := 1000
|
||||
|
||||
for i := 0; i < numSteps; i++ {
|
||||
for i, moon1 := range moons {
|
||||
for _, moon2 := range moons[i+1:] {
|
||||
moon1.applyGravity(moon2)
|
||||
}
|
||||
|
||||
moon1.applyVelocity()
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf("Total energy after %d steps: %s%d%s", numSteps, u.TextBold, getAllEnergy(moons...), u.TextReset)
|
||||
}
|
||||
|
||||
func (d *Day12) Part2() string {
|
||||
moons := d.copyMoons()
|
||||
|
||||
orig := make([]u.Vec3[int], len(moons))
|
||||
for i, moon := range moons {
|
||||
orig[i] = moon.pos
|
||||
}
|
||||
period := u.Vec3[int]{}
|
||||
|
||||
for loops := 0; period.X == 0 || period.Y == 0 || period.Z == 0; loops++ {
|
||||
for i, moon1 := range moons {
|
||||
for _, moon2 := range moons[i+1:] {
|
||||
moon1.applyGravity(moon2)
|
||||
}
|
||||
moon1.applyVelocity()
|
||||
}
|
||||
|
||||
foundX := true
|
||||
foundY := true
|
||||
foundZ := true
|
||||
for i, moon := range moons {
|
||||
if moon.pos.X != orig[i].X || moon.vel.X != 0 {
|
||||
foundX = false
|
||||
}
|
||||
if moon.pos.Y != orig[i].Y || moon.vel.Y != 0 {
|
||||
foundY = false
|
||||
}
|
||||
if moon.pos.Z != orig[i].Z || moon.vel.Z != 0 {
|
||||
foundZ = false
|
||||
}
|
||||
}
|
||||
if foundX && period.X == 0 {
|
||||
period.X = loops + 1
|
||||
}
|
||||
if foundY && period.Y == 0 {
|
||||
period.Y = loops + 1
|
||||
}
|
||||
if foundZ && period.Z == 0 {
|
||||
period.Z = loops + 1
|
||||
}
|
||||
}
|
||||
|
||||
stepsRequired := u.LCM(period.X, period.Y, period.Z)
|
||||
return fmt.Sprintf("Iterations to reach a previous state: %s%d%s", u.TextBold, stepsRequired, u.TextReset)
|
||||
}
|
Reference in New Issue
Block a user