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...
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
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
import (
"bufio"
"adventofcode/util"
"fmt"
"log"
"os"
"path/filepath"
"strings"
)
func main() {
// need to read the input.txt file (one folder up)
// it will be a 2D slice coming from readInputFile now
stringSlice := readInputFile("../input.txt")
// fmt.Println(stringSlice, len(stringSlice))
// need to read the input.txt file and split each line into a slice
input := util.ReadFile("../input.txt")
stringSlice := strings.Split(input, "\n")
// split into a 2D grid with each character
gridSlice := make([][]string, len(stringSlice))
for i, str := range stringSlice {
gridSlice[i] = strings.Split(str, "")
}
// fmt.Println(gridSlice, len(gridSlice))
// will be the final result value
var result int
@@ -29,9 +26,7 @@ func main() {
if element == "#" {
// # are "asteroids", . are empty space
// helper function will return how many asteroids are "findable" from the current asteroid
visibleFromElement := visibleFromAsteroid(gridSlice, rowIndex, colIndex)
// fmt.Println("visible:", visibleFromElement)
// take max of return of helper function at end of each loop
if result < visibleFromElement {
@@ -43,53 +38,30 @@ func main() {
}
// print out the max found
fmt.Println("result: ", result)
fmt.Println("best asteroid for the station is at row, col", finalCoords) // [13, 11]
fmt.Println("from 13, 11 (y, x)", visibleFromAsteroid(gridSlice, 13, 11))
fmt.Printf("best asteroid for the station: row[%v] col[%v]\n", finalCoords[0], finalCoords[1]) // [13, 11]
fmt.Println("from 13, 11 (y, x)", result)
}
func readInputFile(path string) []string {
// var pixelString string
pixelSlice := make([]string, 0)
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)
// helper function will take, x and y coordinates, and the 2D slice
// 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
// 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) {
// fmt.Println(grid)
// make the two maps
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
// iterate through every element of the grid slices
for rowIndex, rowSlice := range grid {
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
if element == "#" && !(row == rowIndex && col == colIndex) {
rise := rowIndex - row
run := colIndex - col
// fmt.Println("avoid zero division")
// handle if the found asteroid is directly above the inputted row/col asteroid
if run == 0 {
if rise < 0 {
@@ -107,7 +79,6 @@ func visibleFromAsteroid(grid [][]string, row, col int) (result int) {
}
} else {
slope := float64(rise) / float64(run)
// fmt.Println(slope)
// handle left or right map
if run < 0 {
// leftMap
@@ -127,6 +98,5 @@ func visibleFromAsteroid(grid [][]string, row, col int) (result int) {
}
}
// fmt.Println(leftMap, rightMap, upBool, downBool)
return result
}
+6 -20
View File
@@ -10,7 +10,7 @@ import (
)
/*
Overall approach...
Overall approach:
- need to make a map of some kind
make it a slice where each element is a struct
- each struct will contain:
@@ -36,8 +36,8 @@ type Asteroid struct {
func main() {
// read input.txt file, split it into a slice of lines
contents := util.ReadFile("../input.txt") // test/example case @ "./test.txt"
stringSlice := strings.Split(contents, "\n")
input := util.ReadFile("../input.txt")
stringSlice := strings.Split(input, "\n")
// generate 2D grid of each character from stringSlice
inputGrid := make([][]string, len(stringSlice))
@@ -45,18 +45,7 @@ func main() {
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)
// fmt.Println(allAsteroids)
// need to start this just to the left of zero to get that as the first input
lastDegreeUsed := 359.999999
@@ -105,9 +94,6 @@ func main() {
// if we pass over 360, subtract 360
lastDegreeUsed -= 360
}
// fmt.Println(minDegDiff)
// fmt.Println("lastAsteroid", i, lastAsteroid)
// fmt.Println(indexOfAsteroidToDelete, allAsteroids[indexOfAsteroidToDelete])
}
// print the last used asteroid
@@ -125,13 +111,13 @@ func makeAsteroidsSlice(grid [][]string) []Asteroid {
// if an asteroid is found...
if element == "#" && !(rowIndex == 13 && colIndex == 11) {
// 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
ast := Asteroid{
x: rowIndex,
y: colIndex,
degOffVert: degree,
distance: dist,
degOffVert: trig.AngleOffVertical(13, 11, rowIndex, colIndex),
distance: trig.Distance(13, 11, rowIndex, colIndex),
}
result = append(result, ast)
}
-20
View File
@@ -1,20 +0,0 @@
.#..##.###...#######
##.############..##.
.#.######.########.#
.###.#######.####.#.
#####.##.#.##.###.##
..#####..#.#########
####################
#.####....###.#.#.##
##.#################
#####.##.###..####..
..######..##.#######
####.##.####...##..#
.#####..#.######.###
##...#.##########...
#.##########.#######
.####.#.###.###.#.##
....##.##.###..#####
.#.#.###########.###
#.#.#.#####.####.###
###.##.####.##.#..##
+29 -51
View File
@@ -1,62 +1,40 @@
package trig
import (
"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
}
import "math"
/*
AngleOffVertical takes in two 2D points, it calculates the angle
between the line between then and a vertical line. The angle
returned is to the right of the vertical, i.e. from the vertical
and through the (mathematical) first quadrant
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)
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