From 936489e620d09805dc0f9fc9c39f7365921d15ce Mon Sep 17 00:00:00 2001 From: alexchao26 Date: Mon, 3 Aug 2020 20:04:23 -0400 Subject: [PATCH] day10: some cleanup --- README.md | 1 + day10/part1/main.go | 58 +++++++---------------------- day10/part2/main.go | 26 +++---------- day10/part2/test1.txt | 20 ---------- day10/part2/trig/trig.go | 80 +++++++++++++++------------------------- 5 files changed, 50 insertions(+), 135 deletions(-) delete mode 100644 day10/part2/test1.txt diff --git a/README.md b/README.md index dc4e323..4fb10e5 100644 --- a/README.md +++ b/README.md @@ -15,3 +15,4 @@ Day | Name | Type of Algo & Notes 7 | Amplification Circuit | - More Intcode... Piping together multiple Intcode computers 😳😳😳
- Refactored Intcode computer to an OOP approach so a single computer maintains its data
- Also requires making __permutations generator__
- Some gymnastics to make this circular, but its easier with this OOP approach and the "objects"/instances of a struct maintaining their own data
- 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__ 🙃
- A new parameter mode and opcode.
- __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
Fundamentally it's a geometry problem, angles and trig
- Part 1: Calculated via slopes
- 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 diff --git a/day10/part1/main.go b/day10/part1/main.go index f872ba1..2814bd8 100644 --- a/day10/part1/main.go +++ b/day10/part1/main.go @@ -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 } diff --git a/day10/part2/main.go b/day10/part2/main.go index 7d9af57..428427b 100644 --- a/day10/part2/main.go +++ b/day10/part2/main.go @@ -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) } diff --git a/day10/part2/test1.txt b/day10/part2/test1.txt deleted file mode 100644 index 8380323..0000000 --- a/day10/part2/test1.txt +++ /dev/null @@ -1,20 +0,0 @@ -.#..##.###...####### -##.############..##. -.#.######.########.# -.###.#######.####.#. -#####.##.#.##.###.## -..#####..#.######### -#################### -#.####....###.#.#.## -##.################# -#####.##.###..####.. -..######..##.####### -####.##.####...##..# -.#####..#.######.### -##...#.##########... -#.##########.####### -.####.#.###.###.#.## -....##.##.###..##### -.#.#.###########.### -#.#.#.#####.####.### -###.##.####.##.#..## \ No newline at end of file diff --git a/day10/part2/trig/trig.go b/day10/part2/trig/trig.go index 7a3aa6d..6c9a739 100644 --- a/day10/part2/trig/trig.go +++ b/day10/part2/trig/trig.go @@ -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