Day 10 solution
This one was an absolute beating for me. I am so bad at these sorts of problems. Ultimately I settled on a probably-not-ideal solution that crawls the graph with offsets of each variant of (+/-x,+/-y), marking nodes visited as we come across them so that we end up with a list of asteroids that we can see. Given that this is day 10, and knowing how bad I am at math, I'm assuming this is very far from the intended solution, but it works reasonably quickly and I managed to come up with it myself, so I'm not going to stress too much about it. For asteroid destruction, the best method I could come up with for finding the correct order was to implement an entire Vector class and sort by angle, which worked, but again, I can't decide if it was the intended solution or not. I should start reusing past years' codebases so I don't have to keep building a utility library from scratch.
This commit is contained in:
171
days/10.go
Normal file
171
days/10.go
Normal file
@ -0,0 +1,171 @@
|
||||
package days
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
u "parnic.com/aoc2019/utilities"
|
||||
)
|
||||
|
||||
type Day10 struct {
|
||||
asteroids [][]bool
|
||||
idealLocation u.Vec2[int]
|
||||
}
|
||||
|
||||
func (d *Day10) Parse() {
|
||||
lines := u.GetStringLines("10p")
|
||||
d.asteroids = make([][]bool, len(lines))
|
||||
for i, line := range lines {
|
||||
d.asteroids[i] = make([]bool, len(line))
|
||||
for j, ch := range line {
|
||||
d.asteroids[i][j] = ch == '#'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d Day10) Num() int {
|
||||
return 10
|
||||
}
|
||||
|
||||
// func (d Day10) draw() {
|
||||
// for i := range d.asteroids {
|
||||
// for j := range d.asteroids[i] {
|
||||
// if !d.asteroids[i][j].First {
|
||||
// fmt.Print(".")
|
||||
// } else {
|
||||
// num := d.asteroids[i][j].Second
|
||||
// ch := rune('0') + rune(num)
|
||||
// if num >= 10 {
|
||||
// ch = '+'
|
||||
// }
|
||||
// fmt.Printf("%c", ch)
|
||||
// }
|
||||
// }
|
||||
// fmt.Println()
|
||||
// }
|
||||
// }
|
||||
|
||||
func (d Day10) getVisibleAsteroids(i1, j1 int) []u.Vec2[int] {
|
||||
visited := make([]u.Vec2[int], 0)
|
||||
foundAsteroids := make([]u.Vec2[int], 0)
|
||||
|
||||
findNext := func(startX, startY, incX, incY int) *u.Vec2[int] {
|
||||
var found *u.Vec2[int]
|
||||
if incX == 0 && incY == 0 {
|
||||
return found
|
||||
}
|
||||
|
||||
x := startX + incX
|
||||
y := startY + incY
|
||||
for x < len(d.asteroids) && x >= 0 && y < len(d.asteroids[x]) && y >= 0 {
|
||||
currPair := u.Vec2[int]{X: x, Y: y}
|
||||
if !u.ArrayContains(visited, currPair) {
|
||||
visited = append(visited, currPair)
|
||||
|
||||
if d.asteroids[x][y] {
|
||||
if found == nil {
|
||||
found = &currPair
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
x += incX
|
||||
y += incY
|
||||
}
|
||||
|
||||
return found
|
||||
}
|
||||
|
||||
for incX := 0; ; {
|
||||
plusXValid := i1+incX < len(d.asteroids)
|
||||
minusXValid := i1-incX >= 0
|
||||
if !plusXValid && !minusXValid {
|
||||
break
|
||||
}
|
||||
|
||||
for incY := 0; ; {
|
||||
plusYValid := j1+incY < len(d.asteroids[0])
|
||||
minusYValid := j1-incY >= 0
|
||||
if !plusYValid && !minusYValid {
|
||||
break
|
||||
}
|
||||
|
||||
if found := findNext(i1, j1, incX, incY); found != nil {
|
||||
foundAsteroids = append(foundAsteroids, *found)
|
||||
}
|
||||
if found := findNext(i1, j1, incX, -incY); found != nil {
|
||||
foundAsteroids = append(foundAsteroids, *found)
|
||||
}
|
||||
if found := findNext(i1, j1, -incX, incY); found != nil {
|
||||
foundAsteroids = append(foundAsteroids, *found)
|
||||
}
|
||||
if found := findNext(i1, j1, -incX, -incY); found != nil {
|
||||
foundAsteroids = append(foundAsteroids, *found)
|
||||
}
|
||||
|
||||
incY++
|
||||
}
|
||||
|
||||
incX++
|
||||
}
|
||||
|
||||
return foundAsteroids
|
||||
}
|
||||
|
||||
func (d Day10) numVisibleAsteroids(i1, j1 int) int {
|
||||
return len(d.getVisibleAsteroids(i1, j1))
|
||||
}
|
||||
|
||||
func (d *Day10) removeAsteroids(locs ...u.Vec2[int]) {
|
||||
for _, loc := range locs {
|
||||
if !d.asteroids[loc.X][loc.Y] {
|
||||
panic("tried to remove non-asteroid")
|
||||
}
|
||||
|
||||
d.asteroids[loc.X][loc.Y] = false
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Day10) Part1() string {
|
||||
mostAsteroids := 0
|
||||
for i := range d.asteroids {
|
||||
for j := range d.asteroids[i] {
|
||||
if d.asteroids[i][j] {
|
||||
numVisible := d.numVisibleAsteroids(i, j)
|
||||
if numVisible > mostAsteroids {
|
||||
mostAsteroids = numVisible
|
||||
d.idealLocation = u.Vec2[int]{X: i, Y: j}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf("Most visible asteroids: %s%d%s at (%d,%d)", u.TextBold, mostAsteroids, u.TextReset, d.idealLocation.Y, d.idealLocation.X)
|
||||
}
|
||||
|
||||
func (d *Day10) Part2() string {
|
||||
findNumVaporized := 200
|
||||
var targetLocation u.Vec2[int]
|
||||
|
||||
vaporized := 0
|
||||
for vaporized < findNumVaporized {
|
||||
visibleAsteroids := d.getVisibleAsteroids(d.idealLocation.X, d.idealLocation.Y)
|
||||
if len(visibleAsteroids) == 0 {
|
||||
panic("no more asteroids to vaporize")
|
||||
}
|
||||
|
||||
if vaporized+len(visibleAsteroids) < findNumVaporized {
|
||||
vaporized += len(visibleAsteroids)
|
||||
d.removeAsteroids(visibleAsteroids...)
|
||||
continue
|
||||
}
|
||||
|
||||
sort.Slice(visibleAsteroids, func(i, j int) bool {
|
||||
return d.idealLocation.AngleBetween(visibleAsteroids[i]) > d.idealLocation.AngleBetween(visibleAsteroids[j])
|
||||
})
|
||||
targetLocation = visibleAsteroids[findNumVaporized-1-vaporized]
|
||||
break
|
||||
}
|
||||
|
||||
return fmt.Sprintf("#%d asteroid to be vaporized is at (%d,%d), transformed: %s%d%s", findNumVaporized, targetLocation.Y, targetLocation.X, u.TextBold, (targetLocation.Y*100)+targetLocation.X, u.TextReset)
|
||||
}
|
33
inputs/10p.txt
Normal file
33
inputs/10p.txt
Normal file
@ -0,0 +1,33 @@
|
||||
.#......##.#..#.......#####...#..
|
||||
...#.....##......###....#.##.....
|
||||
..#...#....#....#............###.
|
||||
.....#......#.##......#.#..###.#.
|
||||
#.#..........##.#.#...#.##.#.#.#.
|
||||
..#.##.#...#.......#..##.......##
|
||||
..#....#.....#..##.#..####.#.....
|
||||
#.............#..#.........#.#...
|
||||
........#.##..#..#..#.#.....#.#..
|
||||
.........#...#..##......###.....#
|
||||
##.#.###..#..#.#.....#.........#.
|
||||
.#.###.##..##......#####..#..##..
|
||||
.........#.......#.#......#......
|
||||
..#...#...#...#.#....###.#.......
|
||||
#..#.#....#...#.......#..#.#.##..
|
||||
#.....##...#.###..#..#......#..##
|
||||
...........#...#......#..#....#..
|
||||
#.#.#......#....#..#.....##....##
|
||||
..###...#.#.##..#...#.....#...#.#
|
||||
.......#..##.#..#.............##.
|
||||
..###........##.#................
|
||||
###.#..#...#......###.#........#.
|
||||
.......#....#.#.#..#..#....#..#..
|
||||
.#...#..#...#......#....#.#..#...
|
||||
#.#.........#.....#....#.#.#.....
|
||||
.#....#......##.##....#........#.
|
||||
....#..#..#...#..##.#.#......#.#.
|
||||
..###.##.#.....#....#.#......#...
|
||||
#.##...#............#..#.....#..#
|
||||
.#....##....##...#......#........
|
||||
...#...##...#.......#....##.#....
|
||||
.#....#.#...#.#...##....#..##.#.#
|
||||
.#.#....##.......#.....##.##.#.##
|
5
inputs/10s1.txt
Normal file
5
inputs/10s1.txt
Normal file
@ -0,0 +1,5 @@
|
||||
.#..#
|
||||
.....
|
||||
#####
|
||||
....#
|
||||
...##
|
10
inputs/10s2.txt
Normal file
10
inputs/10s2.txt
Normal file
@ -0,0 +1,10 @@
|
||||
......#.#.
|
||||
#..#.#....
|
||||
..#######.
|
||||
.#.#.###..
|
||||
.#..#.....
|
||||
..#....#.#
|
||||
#..#....#.
|
||||
.##.#..###
|
||||
##...#..#.
|
||||
.#....####
|
10
inputs/10s3.txt
Normal file
10
inputs/10s3.txt
Normal file
@ -0,0 +1,10 @@
|
||||
#.#...#.#.
|
||||
.###....#.
|
||||
.#....#...
|
||||
##.#.#.#.#
|
||||
....#.#.#.
|
||||
.##..###.#
|
||||
..#...##..
|
||||
..##....##
|
||||
......#...
|
||||
.####.###.
|
10
inputs/10s4.txt
Normal file
10
inputs/10s4.txt
Normal file
@ -0,0 +1,10 @@
|
||||
.#..#..###
|
||||
####.###.#
|
||||
....###.#.
|
||||
..###.##.#
|
||||
##.##.#.#.
|
||||
....###..#
|
||||
..#.#..#.#
|
||||
#..#.#.###
|
||||
.##...##.#
|
||||
.....#.#..
|
20
inputs/10s5.txt
Normal file
20
inputs/10s5.txt
Normal file
@ -0,0 +1,20 @@
|
||||
.#..##.###...#######
|
||||
##.############..##.
|
||||
.#.######.########.#
|
||||
.###.#######.####.#.
|
||||
#####.##.#.##.###.##
|
||||
..#####..#.#########
|
||||
####################
|
||||
#.####....###.#.#.##
|
||||
##.#################
|
||||
#####.##.###..####..
|
||||
..######..##.#######
|
||||
####.##.####...##..#
|
||||
.#####..#.######.###
|
||||
##...#.##########...
|
||||
#.##########.#######
|
||||
.####.#.###.###.#.##
|
||||
....##.##.###..#####
|
||||
.#.#.###########.###
|
||||
#.#.#.#####.####.###
|
||||
###.##.####.##.#..##
|
5
inputs/10s6.txt
Normal file
5
inputs/10s6.txt
Normal file
@ -0,0 +1,5 @@
|
||||
.#....#####...#..
|
||||
##...##.#####..##
|
||||
##...#...#.#####.
|
||||
..#.....#...###..
|
||||
..#.#.....#....##
|
1
main.go
1
main.go
@ -40,6 +40,7 @@ var dayMap = []day{
|
||||
&days.Day07{},
|
||||
&days.Day08{},
|
||||
&days.Day09{},
|
||||
&days.Day10{},
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
29
utilities/constraints.go
Normal file
29
utilities/constraints.go
Normal file
@ -0,0 +1,29 @@
|
||||
package utilities
|
||||
|
||||
type Ordered interface {
|
||||
Integer | Float | ~string
|
||||
}
|
||||
|
||||
type Signed interface {
|
||||
~int | ~int8 | ~int16 | ~int32 | ~int64
|
||||
}
|
||||
|
||||
type Unsigned interface {
|
||||
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
|
||||
}
|
||||
|
||||
type Integer interface {
|
||||
Signed | Unsigned
|
||||
}
|
||||
|
||||
type Float interface {
|
||||
~float32 | ~float64
|
||||
}
|
||||
|
||||
type Complex interface {
|
||||
~complex64 | ~complex128
|
||||
}
|
||||
|
||||
type Number interface {
|
||||
Integer | Float
|
||||
}
|
39
utilities/vector.go
Normal file
39
utilities/vector.go
Normal file
@ -0,0 +1,39 @@
|
||||
package utilities
|
||||
|
||||
import "math"
|
||||
|
||||
type Vec2[T Number] struct {
|
||||
X T
|
||||
Y T
|
||||
}
|
||||
|
||||
func (v Vec2[T]) Dot(other Vec2[T]) T {
|
||||
return (v.X * other.X) + (v.Y * other.Y)
|
||||
}
|
||||
|
||||
func (v Vec2[T]) Len() T {
|
||||
return T(math.Sqrt(float64(v.LenSquared())))
|
||||
}
|
||||
|
||||
func (v Vec2[T]) LenSquared() T {
|
||||
return (v.X * v.X) + (v.Y * v.Y)
|
||||
}
|
||||
|
||||
func (v Vec2[T]) To(other Vec2[T]) Vec2[T] {
|
||||
return Vec2[T]{
|
||||
X: v.X - other.X,
|
||||
Y: v.Y - other.Y,
|
||||
}
|
||||
}
|
||||
|
||||
func (v Vec2[T]) AngleBetween(other Vec2[T]) float64 {
|
||||
rad := math.Atan2(float64(other.Y-v.Y), float64(other.X-v.X))
|
||||
return rad * 180 / math.Pi
|
||||
}
|
||||
|
||||
func VecBetween[T Number](a, b Vec2[T]) Vec2[T] {
|
||||
return Vec2[T]{
|
||||
X: a.X - b.X,
|
||||
Y: a.Y - b.Y,
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user