-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
161 lines (128 loc) · 3.33 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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
package main
import (
"bufio"
"flag"
"fmt"
"os"
"regexp"
"strconv"
)
var (
methodP *string
)
func parseFlags() {
methodP = flag.String("method", "all", "The method/part that should be run, valid are p1,p2 and test")
flag.Parse()
}
func main() {
parseFlags()
switch *methodP {
case "all":
fmt.Println("Silver:" + PartOne("input"))
fmt.Println("Gold:" + PartTwo("input"))
case "p1":
fmt.Println("Silver:" + PartOne("input"))
break
case "p2":
fmt.Println("Gold:" + PartTwo("input"))
break
}
}
func PartOne(filename string) string {
input := readInput(filename)
targetZone, lowestPointInGrid := createTargetZone(input[0])
currentMaxHeight := 0
for x := 0; x < 300; x++ {
for y := 0; y < 300; y++ {
maxHeight, didWeHitTarget := fireProbe(x, y, targetZone, lowestPointInGrid)
if didWeHitTarget && maxHeight > currentMaxHeight {
// Find point with highest hit
currentMaxHeight = maxHeight
}
}
}
num := strconv.Itoa(currentMaxHeight)
return num
}
func PartTwo(filename string) string {
input := readInput(filename)
targetZone, lowestPointInGrid := createTargetZone(input[0])
hits := 0
for x := 0; x < 300; x++ {
for y := -300; y < 300; y++ {
_, didWeHitTarget := fireProbe(x, y, targetZone, lowestPointInGrid)
if didWeHitTarget {
// Find point with highest hit
hits++
}
}
}
num := strconv.Itoa(hits)
return num
}
type Point struct {
X int
Y int
}
func fireProbe(xVelo, yVelo int, targetGrid map[Point]bool, lowestPointInTarget int) (int, bool) {
hitTarget := false
maxHeight := 0
// Check if we hit target based on xVelo and yVelo
// The probe's x position increases by its x velocity.
// The probe's y position increases by its y velocity.
// Due to drag, the probe's x velocity changes by 1 toward the value 0; that is, it decreases by 1 if it is greater than 0, increases by 1 if it is less than 0, or does not change if it is already 0.
// Due to gravity, the probe's y velocity decreases by 1.
currentX := 0
currentY := 0
for !hitTarget {
// run a step
currentX += xVelo
currentY += yVelo
if xVelo < 0 {
xVelo++
} else if xVelo > 0 {
xVelo--
}
yVelo--
if currentY > maxHeight {
maxHeight = currentY
}
// Check if we hit target
if targetGrid[Point{currentX, currentY}] {
hitTarget = true
break
}
// If we are below target, we will never hit, so break out
if currentY < lowestPointInTarget {
break
}
}
return maxHeight, hitTarget
}
// Read data from input.txt
// Return the string, so that we can deal with it however
func readInput(filename string) []string {
var input []string
f, _ := os.Open(filename + ".txt")
scanner := bufio.NewScanner(f)
for scanner.Scan() {
input = append(input, scanner.Text())
}
return input
}
func createTargetZone(input string) (map[Point]bool, int) {
pointsInGrid := make(map[Point]bool)
// target area: x=185..221, y=-122..-74
gridRegex := regexp.MustCompile("target area: x=([0-9]+)..([0-9]+), y=(-[0-9]+)..(-[0-9]+)")
gridString := gridRegex.FindAllStringSubmatch(input, 1)
xMin, _ := strconv.Atoi(gridString[0][1])
xMax, _ := strconv.Atoi(gridString[0][2])
yMin, _ := strconv.Atoi(gridString[0][3])
yMax, _ := strconv.Atoi(gridString[0][4])
for x := xMin; x < xMax+1; x++ {
for y := yMin; y < yMax+1; y++ {
pointsInGrid[Point{x, y}] = true
}
}
return pointsInGrid, yMin
}