-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
128 lines (107 loc) Β· 2.69 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package main
import (
"fmt"
"reflect"
"time"
"github.com/sanderploegsma/advent-of-code/2019/go/utils"
)
var input = [][]int{
{3, 2, -6, 0, 0, 0},
{-13, 18, 10, 0, 0, 0},
{-8, -1, 13, 0, 0, 0},
{5, 10, 4, 0, 0, 0},
}
func main() {
start := time.Now()
ans := TotalEnergy(SimulateN(input, 1000))
fmt.Println(1, ans, time.Since(start))
start = time.Now()
ans = CalculateCycle(input)
fmt.Println(2, ans, time.Since(start))
}
// CalculateCycle finds the number of steps needed to bring the given moons back to their original position.
// Because the movement on each axis is not influenced by the the other axes, we can determine the cycle for each axis
// individually, and then use the Least Common Multiplier to calculate the combined cycle.
func CalculateCycle(moons [][]int) int {
repeats := make(map[int]int)
for i := 0; i < 3; i++ {
steps := 0
sim := clone(moons)
for {
steps++
sim = SimulateAxis(sim, i)
if reflect.DeepEqual(sim, moons) {
repeats[i] = steps
break
}
}
}
return utils.LCM(repeats[0], repeats[1], repeats[2])
}
// SimulateN simulates the movement of the given moons for n steps.
func SimulateN(moons [][]int, n int) [][]int {
sim := clone(moons)
for i := 0; i < n; i++ {
sim = Simulate(sim)
}
return sim
}
// Simulate simulates a single movement step for all given moons.
func Simulate(moons [][]int) [][]int {
sim := clone(moons)
for i := 0; i < len(moons); i++ {
for j := i + 1; j < len(moons); j++ {
for axis := 0; axis < 3; axis++ {
dx1, dx2 := gravity(moons[i][axis], moons[j][axis])
sim[i][axis+3] += dx1
sim[j][axis+3] += dx2
}
}
}
for i := range sim {
for axis := 0; axis < 3; axis++ {
sim[i][axis] += sim[i][axis+3]
}
}
return sim
}
// SimulateAxis simulates a single movement step for a single given axis of all moons
func SimulateAxis(moons [][]int, axis int) [][]int {
sim := clone(moons)
for i := 0; i < len(moons); i++ {
for j := i + 1; j < len(moons); j++ {
di, dj := gravity(moons[i][axis], moons[j][axis])
sim[i][axis+3] += di
sim[j][axis+3] += dj
}
}
for i := range sim {
sim[i][axis] += sim[i][axis+3]
}
return sim
}
// TotalEnergy calculates the total amount of energy of all given moons.
func TotalEnergy(moons [][]int) int {
energy := 0
for _, m := range moons {
energy += (utils.Abs(m[0]) + utils.Abs(m[1]) + utils.Abs(m[2])) * (utils.Abs(m[3]) + utils.Abs(m[4]) + utils.Abs(m[5]))
}
return energy
}
func gravity(a, b int) (int, int) {
if a == b {
return 0, 0
}
if a > b {
return -1, 1
}
return 1, -1
}
func clone(moons [][]int) [][]int {
c := make([][]int, len(moons))
for i := range moons {
c[i] = make([]int, len(moons[i]))
copy(c[i], moons[i])
}
return c
}