package main import ( "bufio" "fmt" "os" "strconv" "strings" "time" ) func mustAtoi(line string) int { i, _ := strconv.Atoi(line) return i } func main() { start := time.Now() partOne() duration := time.Since(start) partTwo() duration2 := time.Since(start) fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration) } func makeScanner(test bool) *bufio.Scanner { var f *os.File if test { f, _ = os.Open("inputs/testinput") } else { f, _ = os.Open("inputs/input") } reader := bufio.NewReader(f) return bufio.NewScanner(reader) } type coord struct { x int y int } func abs(i, j int) int { if i < j { return j - i } return i - j } func getCoords(x, y string, _ bool) coord { return coord{x: mustAtoi(x), y: mustAtoi(y)} } func distance(sensor, beacon coord) int { return abs(sensor.x, beacon.x) + abs(sensor.y, beacon.y) } func partOne() { test := false scanner := makeScanner(test) row := 2000000 if test { row = 10 } cave := map[coord]int{} // 0 for unknown space, 1 for sensor, 2 for beacon, 3 for known empty for scanner.Scan() { line := scanner.Text() s, b, _ := strings.Cut(line, ": ") sensor := getCoords(strings.Cut(strings.Trim(s, "Sensor at x="), ", y=")) beacon := getCoords(strings.Cut(strings.Trim(b, "closest beacon is at x="), ", y=")) dist := distance(sensor, beacon) cave[sensor] = 1 cave[beacon] = 2 rel := distance(sensor, coord{x: sensor.x, y: row}) if rel <= dist { c := dist - rel for i := sensor.x - c; i <= sensor.x+c; i++ { if _, ok := cave[coord{x: i, y: row}]; !ok { cave[coord{x: i, y: row}] = 3 } } } } sum := 0 for _, i := range cave { if i == 3 { sum++ } } fmt.Println(sum) } func sensorHalo(sensor coord, distance int) []coord { halo := []coord{} corners := []coord{ {x: sensor.x, y: sensor.y + distance + 1}, {x: sensor.x + distance + 1, y: sensor.y}, {x: sensor.x, y: sensor.y - distance - 1}, {x: sensor.x - distance - 1, y: sensor.y}, } y := corners[0].y for i := corners[0].x; i < corners[1].x; i++ { halo = append(halo, coord{i, y}) y-- } for i := corners[1].x; i > corners[2].x; i-- { halo = append(halo, coord{i, y}) y-- } for i := corners[2].x; i > corners[3].x; i-- { halo = append(halo, coord{i, y}) y++ } for i := corners[3].x; i > corners[0].x; i++ { halo = append(halo, coord{i, y}) y++ } halo = append(halo, corners[3]) return halo } func partTwo() { test := false scanner := makeScanner(test) max := 4000000 if test { max = 20 } cave := map[coord]int{} // sensor: distance to beacon for scanner.Scan() { line := scanner.Text() s, b, _ := strings.Cut(line, ": ") sensor := getCoords(strings.Cut(strings.Trim(s, "Sensor at x="), ", y=")) beacon := getCoords(strings.Cut(strings.Trim(b, "closest beacon is at x="), ", y=")) dist := distance(sensor, beacon) cave[sensor] = dist } // since there's only one of these holes in the search space, // it must be just outside the maximum distance from a sensor // it'll take far too long to search the entire cavern, after all possibleCoords := []coord{} for sensor, dist := range cave { possibleCoords = append(possibleCoords, sensorHalo(sensor, dist)...) } for _, poss := range possibleCoords { if poss.x < 0 || poss.y < 0 || poss.x > max || poss.y > max { continue } hit := false for sensor, dist := range cave { if distance(sensor, poss) < dist { hit = true } } if !hit { fmt.Println(poss.x*4000000 + poss.y) return } } }