mirror of
https://github.com/Threnklyn/advent-of-code-go.git
synced 2026-06-07 12:45:10 +02:00
might be making a mistake starting 2018...
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
|
||||
"adventofcode/day10/part2/trig"
|
||||
"adventofcode/util"
|
||||
)
|
||||
|
||||
/*
|
||||
Overall approach:
|
||||
- need to make a map of some kind
|
||||
make it a slice where each element is a struct
|
||||
- each struct will contain:
|
||||
x
|
||||
y
|
||||
degOffVert float64 (degrees 0 -> 360)
|
||||
distance float64
|
||||
- iterate through the slice of structs
|
||||
- store the index of the minimum distance
|
||||
|
||||
- remove it from the slice of structs
|
||||
- if this is the 200th iteration, store the x and y to return at the end
|
||||
- NOTE there are a limited number of asteroids because of the fixed size of the input, so having a O(200 * n) where n is the number of Asteroids, is not a _terrible_ time complexity
|
||||
*/
|
||||
|
||||
// Asteroid data
|
||||
type Asteroid struct {
|
||||
x int
|
||||
y int
|
||||
degOffVert float64
|
||||
distance float64
|
||||
}
|
||||
|
||||
func main() {
|
||||
// read input.txt file, split it into a slice of lines
|
||||
input := util.ReadFile("../input.txt")
|
||||
stringSlice := strings.Split(input, "\n")
|
||||
|
||||
// generate 2D grid of each character from stringSlice
|
||||
inputGrid := make([][]string, len(stringSlice))
|
||||
for i, str := range stringSlice {
|
||||
inputGrid[i] = strings.Split(str, "")
|
||||
}
|
||||
|
||||
allAsteroids := makeAsteroidsSlice(inputGrid)
|
||||
|
||||
// need to start this just to the left of zero to get that as the first input
|
||||
lastDegreeUsed := 359.999999
|
||||
// to store the last vaporized asteroid to output its coordinates
|
||||
var lastAsteroid Asteroid
|
||||
|
||||
for i := 0; i < 200; i++ {
|
||||
// iterate through all of allAsteroids and find the next closest degree
|
||||
var indexOfAsteroidToDelete int // will be updated by iMin
|
||||
|
||||
// reset the minDegDiff and minDist for each run of the outer loop
|
||||
minDegDiff, minDist := math.Inf(1), math.Inf(1) // I can use inf now b/c I'm using float64's!
|
||||
|
||||
// iterate over the entire slice of asteroids
|
||||
for iMin, eAsteroid := range allAsteroids {
|
||||
// calculate the degrees difference
|
||||
degDiff := eAsteroid.degOffVert - lastDegreeUsed
|
||||
if degDiff <= 0 { // account for the diff passing over zero
|
||||
degDiff += 360
|
||||
}
|
||||
// if this asteroid has a smaller degrees difference, update all min values
|
||||
if degDiff < minDegDiff {
|
||||
minDist = eAsteroid.distance
|
||||
minDegDiff = degDiff
|
||||
indexOfAsteroidToDelete = iMin
|
||||
} else if degDiff == minDegDiff && minDist > eAsteroid.distance {
|
||||
// OR if the degDiff is the same but the distance to 13,11 is smaller
|
||||
// update just the minDistance and index for this asteroid
|
||||
minDist = eAsteroid.distance
|
||||
indexOfAsteroidToDelete = iMin
|
||||
}
|
||||
}
|
||||
|
||||
// remove the element at index indexOfAst
|
||||
// this doesn't maintain order, but I don't care about order right now
|
||||
lastAsteroid = allAsteroids[indexOfAsteroidToDelete]
|
||||
|
||||
// swap last element to indexToDelete
|
||||
allAsteroids[indexOfAsteroidToDelete] = allAsteroids[len(allAsteroids)-1]
|
||||
// re-size slice to effectively pop last element off of slice
|
||||
allAsteroids = allAsteroids[:len(allAsteroids)-1]
|
||||
|
||||
// update last deg used by adding the diff to it
|
||||
lastDegreeUsed += minDegDiff
|
||||
if lastDegreeUsed >= 360 {
|
||||
// if we pass over 360, subtract 360
|
||||
lastDegreeUsed -= 360
|
||||
}
|
||||
}
|
||||
|
||||
// print the last used asteroid
|
||||
fmt.Println("Last asteroid", lastAsteroid)
|
||||
// print the AoC-formatted answer
|
||||
fmt.Println("Advent of code answer: ", lastAsteroid.y*100+lastAsteroid.x)
|
||||
}
|
||||
|
||||
func makeAsteroidsSlice(grid [][]string) []Asteroid {
|
||||
result := make([]Asteroid, 0)
|
||||
|
||||
// iterate through the entire grid
|
||||
for rowIndex, rowSlice := range grid {
|
||||
for colIndex, element := range rowSlice {
|
||||
// if an asteroid is found...
|
||||
if element == "#" && !(rowIndex == 13 && colIndex == 11) {
|
||||
// calculate the degree and dist
|
||||
// degree, dist := trig.TangentAndDistance(13, 11, rowIndex, colIndex)
|
||||
// create an instance of an Asteroid struct and append it to the result slice
|
||||
ast := Asteroid{
|
||||
x: rowIndex,
|
||||
y: colIndex,
|
||||
degOffVert: trig.AngleOffVertical(13, 11, rowIndex, colIndex),
|
||||
distance: trig.Distance(13, 11, rowIndex, colIndex),
|
||||
}
|
||||
result = append(result, ast)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package trig
|
||||
|
||||
import "math"
|
||||
|
||||
/*
|
||||
AngleOffVertical takes in two 2D points, it calculates the angle
|
||||
between the line and a vertical line (straight up from origin)
|
||||
NOTE: "up"/"top" and "down" are lexically flipped b/c of drawing a grid
|
||||
where 0, 0 is the top left corner and higher numbers physically go DOWN
|
||||
but lexically increase/go UP 🤦♂️
|
||||
*/
|
||||
func AngleOffVertical(startX, startY, endX, endY int) float64 {
|
||||
rise := float64(endX) - float64(startX)
|
||||
run := float64(endY) - float64(startY)
|
||||
|
||||
var angle float64
|
||||
// basically a big if/elseif/else block
|
||||
switch {
|
||||
case run == 0 && rise < 0: // up
|
||||
angle = 0
|
||||
case run == 0 && rise > 0: // down
|
||||
angle = 180
|
||||
case rise == 0 && run < 0: // left
|
||||
angle = 270
|
||||
case rise == 0 && run > 0: // right
|
||||
angle = 90
|
||||
case rise < 0 && run > 0: // top right
|
||||
angle = -1 * math.Atan(run/rise) * 180 / math.Pi
|
||||
case rise > 0 && run > 0: // bottom right
|
||||
angle = 90 + math.Atan(rise/run)*180/math.Pi
|
||||
case rise > 0 && run < 0: // bottom left
|
||||
angle = 180 + -1*math.Atan(run/rise)*180/math.Pi
|
||||
case rise < 0 && run < 0: // top left
|
||||
angle = 270 + math.Atan(rise/run)*180/math.Pi
|
||||
}
|
||||
|
||||
return angle
|
||||
}
|
||||
|
||||
// Distance calculates the distance between two sets of 2D coordinates via Pythagorean's theorem
|
||||
func Distance(startX, startY, endX, endY int) float64 {
|
||||
dx := startX - endX
|
||||
dy := startY - endY
|
||||
return math.Sqrt(float64(dx*dx) + float64(dy*dy))
|
||||
}
|
||||
Reference in New Issue
Block a user