day10: some cleanup

This commit is contained in:
alexchao26
2020-08-03 20:04:23 -04:00
parent 40f4e54bc2
commit 936489e620
5 changed files with 50 additions and 135 deletions
+1
View File
@@ -15,3 +15,4 @@ Day | Name | Type of Algo & Notes
7 | Amplification Circuit | - More Intcode... Piping together multiple Intcode computers 😳😳😳 <br> - Refactored Intcode computer to an OOP approach so a single computer maintains its data <br> - Also requires making __permutations generator__ <br> - Some gymnastics to make this circular, but its easier with this OOP approach and the "objects"/instances of a struct maintaining their own data <br> - Concurrency could be used to sync these Amps together... 7 | Amplification Circuit | - More Intcode... Piping together multiple Intcode computers 😳😳😳 <br> - Refactored Intcode computer to an OOP approach so a single computer maintains its data <br> - Also requires making __permutations generator__ <br> - Some gymnastics to make this circular, but its easier with this OOP approach and the "objects"/instances of a struct maintaining their own data <br> - Concurrency could be used to sync these Amps together...
8 | Space Image Format | 3D Array manipulation, pretty straight forward 8 | Space Image Format | 3D Array manipulation, pretty straight forward
9 | Sensor Boost | __MORE INTCODE. YAYY__ 🙃 <br> - A new parameter mode and opcode. <br> - __Really feeling the (tech) debt of some earlier design choices here, went back to refactor day07 before jumping into this one__, then it was a small bit of code for the relative param/opcode & resizing computer memory if necessary 9 | Sensor Boost | __MORE INTCODE. YAYY__ 🙃 <br> - A new parameter mode and opcode. <br> - __Really feeling the (tech) debt of some earlier design choices here, went back to refactor day07 before jumping into this one__, then it was a small bit of code for the relative param/opcode & resizing computer memory if necessary
10 | Monitoring Station | - This (part2) is my favorite algo... Yes I have a favorite algo <br> Fundamentally it's a geometry problem, angles and trig <br> - Part 1: Calculated via slopes <br> - Part 2: Using Arctangent to find angles an asteroid makes against a vertical line from the home base asteroid. Then those angles can be used to determine if Asteroids are covering each other, AND iterating through all of them can find the next angle Asteroid to vaporize
+14 -44
View File
@@ -1,24 +1,21 @@
package main package main
import ( import (
"bufio" "adventofcode/util"
"fmt" "fmt"
"log"
"os"
"path/filepath"
"strings" "strings"
) )
func main() { func main() {
// need to read the input.txt file (one folder up) // need to read the input.txt file and split each line into a slice
// it will be a 2D slice coming from readInputFile now input := util.ReadFile("../input.txt")
stringSlice := readInputFile("../input.txt") stringSlice := strings.Split(input, "\n")
// fmt.Println(stringSlice, len(stringSlice))
// split into a 2D grid with each character
gridSlice := make([][]string, len(stringSlice)) gridSlice := make([][]string, len(stringSlice))
for i, str := range stringSlice { for i, str := range stringSlice {
gridSlice[i] = strings.Split(str, "") gridSlice[i] = strings.Split(str, "")
} }
// fmt.Println(gridSlice, len(gridSlice))
// will be the final result value // will be the final result value
var result int var result int
@@ -29,9 +26,7 @@ func main() {
if element == "#" { if element == "#" {
// # are "asteroids", . are empty space // # are "asteroids", . are empty space
// helper function will return how many asteroids are "findable" from the current asteroid // helper function will return how many asteroids are "findable" from the current asteroid
visibleFromElement := visibleFromAsteroid(gridSlice, rowIndex, colIndex) visibleFromElement := visibleFromAsteroid(gridSlice, rowIndex, colIndex)
// fmt.Println("visible:", visibleFromElement)
// take max of return of helper function at end of each loop // take max of return of helper function at end of each loop
if result < visibleFromElement { if result < visibleFromElement {
@@ -43,53 +38,30 @@ func main() {
} }
// print out the max found // print out the max found
fmt.Println("result: ", result) fmt.Printf("best asteroid for the station: row[%v] col[%v]\n", finalCoords[0], finalCoords[1]) // [13, 11]
fmt.Println("best asteroid for the station is at row, col", finalCoords) // [13, 11] fmt.Println("from 13, 11 (y, x)", result)
fmt.Println("from 13, 11 (y, x)", visibleFromAsteroid(gridSlice, 13, 11))
} }
func readInputFile(path string) []string { // helper function will take, x and y coordinates, and the 2D slice
// var pixelString string // will create a two maps of floats to booleans
pixelSlice := make([]string, 0) // (one map to cover left side of asteroid, one map to cover right side of asteroid)
absPath, _ := filepath.Abs(path)
file, err := os.Open(absPath)
if err != nil {
log.Fatal(err)
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
// pixelString = line
pixelSlice = append(pixelSlice, line)
}
// return pixelString
return pixelSlice
}
// helper function will take, x and y coordinates, and the 2D slices?
// will create a two maps of floats to booleans (one map to cover left side of asteroid, one map to cover right side of asteroid)
// so that anything that is blocked will not be double counted // so that anything that is blocked will not be double counted
// will need edge case handling for planets vertically above or below the current asteroid // and edge case handling for planets vertically above or below the current asteroid
func visibleFromAsteroid(grid [][]string, row, col int) (result int) { func visibleFromAsteroid(grid [][]string, row, col int) (result int) {
// fmt.Println(grid)
// make the two maps // make the two maps
leftMap, rightMap := make(map[float64]bool), make(map[float64]bool) leftMap, rightMap := make(map[float64]bool), make(map[float64]bool)
// make the two booleans for up and down. nil value is false // make the two booleans for up and down. zero value is false
var upBool, downBool bool var upBool, downBool bool
// iterate through every element of the grid slices // iterate through every element of the grid slices
for rowIndex, rowSlice := range grid { for rowIndex, rowSlice := range grid {
for colIndex, element := range rowSlice { for colIndex, element := range rowSlice {
// NOTE this control flow is _GROSS_. Better solution in part2 solution
// ensure element is an asteroid & not the asteroid that the helper function is being run on // ensure element is an asteroid & not the asteroid that the helper function is being run on
if element == "#" && !(row == rowIndex && col == colIndex) { if element == "#" && !(row == rowIndex && col == colIndex) {
rise := rowIndex - row rise := rowIndex - row
run := colIndex - col run := colIndex - col
// fmt.Println("avoid zero division")
// handle if the found asteroid is directly above the inputted row/col asteroid // handle if the found asteroid is directly above the inputted row/col asteroid
if run == 0 { if run == 0 {
if rise < 0 { if rise < 0 {
@@ -107,7 +79,6 @@ func visibleFromAsteroid(grid [][]string, row, col int) (result int) {
} }
} else { } else {
slope := float64(rise) / float64(run) slope := float64(rise) / float64(run)
// fmt.Println(slope)
// handle left or right map // handle left or right map
if run < 0 { if run < 0 {
// leftMap // leftMap
@@ -127,6 +98,5 @@ func visibleFromAsteroid(grid [][]string, row, col int) (result int) {
} }
} }
// fmt.Println(leftMap, rightMap, upBool, downBool)
return result return result
} }
+6 -20
View File
@@ -10,7 +10,7 @@ import (
) )
/* /*
Overall approach... Overall approach:
- need to make a map of some kind - need to make a map of some kind
make it a slice where each element is a struct make it a slice where each element is a struct
- each struct will contain: - each struct will contain:
@@ -36,8 +36,8 @@ type Asteroid struct {
func main() { func main() {
// read input.txt file, split it into a slice of lines // read input.txt file, split it into a slice of lines
contents := util.ReadFile("../input.txt") // test/example case @ "./test.txt" input := util.ReadFile("../input.txt")
stringSlice := strings.Split(contents, "\n") stringSlice := strings.Split(input, "\n")
// generate 2D grid of each character from stringSlice // generate 2D grid of each character from stringSlice
inputGrid := make([][]string, len(stringSlice)) inputGrid := make([][]string, len(stringSlice))
@@ -45,18 +45,7 @@ func main() {
inputGrid[i] = strings.Split(str, "") inputGrid[i] = strings.Split(str, "")
} }
//* tests while building the TangetAndDistance function
// fmt.Println(trig.TangentAndDistance(13, 11, 0, 11)) // 0 13
// fmt.Println(trig.TangentAndDistance(13, 11, 15, 11)) // 180 2
// fmt.Println(trig.TangentAndDistance(13, 11, 13, 16)) // 90 5
// fmt.Println(trig.TangentAndDistance(13, 11, 13, 9)) // 270 2
// fmt.Println(trig.TangentAndDistance(1, 1, 0, 2)) // 45 some sqrt
// fmt.Println(trig.TangentAndDistance(1, 1, 2, 2)) // 135 some sqrt
// fmt.Println(trig.TangentAndDistance(1, 1, 2, 0)) // 225 some sqrt
// fmt.Println(trig.TangentAndDistance(1, 1, 0, 0)) // 315 some sqrt
allAsteroids := makeAsteroidsSlice(inputGrid) allAsteroids := makeAsteroidsSlice(inputGrid)
// fmt.Println(allAsteroids)
// need to start this just to the left of zero to get that as the first input // need to start this just to the left of zero to get that as the first input
lastDegreeUsed := 359.999999 lastDegreeUsed := 359.999999
@@ -105,9 +94,6 @@ func main() {
// if we pass over 360, subtract 360 // if we pass over 360, subtract 360
lastDegreeUsed -= 360 lastDegreeUsed -= 360
} }
// fmt.Println(minDegDiff)
// fmt.Println("lastAsteroid", i, lastAsteroid)
// fmt.Println(indexOfAsteroidToDelete, allAsteroids[indexOfAsteroidToDelete])
} }
// print the last used asteroid // print the last used asteroid
@@ -125,13 +111,13 @@ func makeAsteroidsSlice(grid [][]string) []Asteroid {
// if an asteroid is found... // if an asteroid is found...
if element == "#" && !(rowIndex == 13 && colIndex == 11) { if element == "#" && !(rowIndex == 13 && colIndex == 11) {
// calculate the degree and dist // calculate the degree and dist
degree, dist := trig.TangentAndDistance(13, 11, rowIndex, colIndex) // degree, dist := trig.TangentAndDistance(13, 11, rowIndex, colIndex)
// create an instance of an Asteroid struct and append it to the result slice // create an instance of an Asteroid struct and append it to the result slice
ast := Asteroid{ ast := Asteroid{
x: rowIndex, x: rowIndex,
y: colIndex, y: colIndex,
degOffVert: degree, degOffVert: trig.AngleOffVertical(13, 11, rowIndex, colIndex),
distance: dist, distance: trig.Distance(13, 11, rowIndex, colIndex),
} }
result = append(result, ast) result = append(result, ast)
} }
-20
View File
@@ -1,20 +0,0 @@
.#..##.###...#######
##.############..##.
.#.######.########.#
.###.#######.####.#.
#####.##.#.##.###.##
..#####..#.#########
####################
#.####....###.#.#.##
##.#################
#####.##.###..####..
..######..##.#######
####.##.####...##..#
.#####..#.######.###
##...#.##########...
#.##########.#######
.####.#.###.###.#.##
....##.##.###..#####
.#.#.###########.###
#.#.#.#####.####.###
###.##.####.##.#..##
+29 -51
View File
@@ -1,62 +1,40 @@
package trig package trig
import ( import "math"
"math"
)
// TangentAndDistance docz
// startX will "always" be 13
// startY will "always" be 11
// 0 <= angleOffVery < 360
func TangentAndDistance(startX, startY, endX, endY int) (angleOffVert, distance float64) {
rise, run := float64(endX)-float64(startX), float64(endY)-float64(startY)
// fmt.Println(rise, run)
// edge cases for verticals
if run == 0 && rise < 0 {
return 0, -1 * rise // endXY is up
}
if run == 0 && rise > 0 {
return 180, rise // endXY is down
}
// handle left or right?
if rise == 0 && run < 0 {
return 270, -1 * run // left
}
if rise == 0 && run > 0 {
return 90, run // right
}
// not verticals
// calculate return distance
distance = rise*rise + run*run
distance = math.Sqrt(distance)
// calculate arctangent which will be in radians
// determine quadrent
if rise < 0 && run > 0 { // top right
angleOffVert = -1 * math.Atan(run/rise) * 180 / math.Pi
} else if rise > 0 && run > 0 { // bottom right
angleOffVert = 90 + math.Atan(rise/run)*180/math.Pi
} else if rise > 0 && run < 0 { // bottom left
angleOffVert = 180 + -1*math.Atan(run/rise)*180/math.Pi
} else if rise < 0 && run < 0 { // top left
angleOffVert = 270 + math.Atan(rise/run)*180/math.Pi
}
return angleOffVert, distance
}
/* /*
AngleOffVertical takes in two 2D points, it calculates the angle AngleOffVertical takes in two 2D points, it calculates the angle
between the line between then and a vertical line. The angle between the line and a vertical line (straight up from origin)
returned is to the right of the vertical, i.e. from the vertical NOTE: "up"/"top" and "down" are lexically flipped b/c of drawing a grid
and through the (mathematical) first quadrant 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 { func AngleOffVertical(startX, startY, endX, endY int) float64 {
rise := float64(endX) - float64(startX)
run := float64(endY) - float64(startY)
return 0 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 // Distance calculates the distance between two sets of 2D coordinates via Pythagorean's theorem