package day15 import ( "bufio" "fmt" "os" "strconv" ) type Point struct { x int y int } func pointDistance(a Point, b Point) int { return diff(a.x, b.x) + diff(a.y, b.y) } func diff(a int, b int) int { if a > b { return a - b } else { return b - a } } type Sensor struct { location Point distance int } func parseLine(line string) (sensor Sensor, beacon Point) { var sensorX int var sensorY int var beaconX int var beaconY int fmt.Sscanf(line, "Sensor at x=%d, y=%d: closest beacon is at x=%d, y=%d", &sensorX, &sensorY, &beaconX, &beaconY) sensorLoc := Point{sensorX, sensorY} beacon = Point{beaconX, beaconY} distance := pointDistance(sensorLoc, beacon) sensor = Sensor{sensorLoc, distance} return } func isBeacon(x int, y int, beacons []Point) bool { for _, beacon := range beacons { if beacon.x == x && beacon.y == y { return true } } return false } func inSensorRange(x int, y int, sensors []Sensor) *Sensor { point := Point{x, y} for _, sensor := range sensors { distance := pointDistance(point, sensor.location) if distance <= sensor.distance { return &sensor } } return nil } func leftmostPoint(sensors []Sensor) int { leftmost := 0 for _, sensor := range sensors { candidate := sensor.location.x - sensor.distance if candidate < leftmost { leftmost = candidate } } return leftmost } func rightmostPoint(sensors []Sensor) int { rightmost := 0 for _, sensor := range sensors { candidate := sensor.location.x + sensor.distance if candidate > rightmost { rightmost = candidate } } return rightmost } func addLinePoints(pointSet *[]Point, start Point, end Point) { offsetX := 1 offsetY := 1 if end.x < start.x { offsetX = -1 } if end.y < start.y { offsetY = -1 } for x, y := start.x, start.y; y != end.y; x, y = x+offsetX, y+offsetY { *pointSet = append(*pointSet, Point{x, y}) } } func addEdgePoints(pointSet *[]Point, sensor Sensor) { distance := sensor.distance + 1 top := Point{sensor.location.x, sensor.location.y - distance} right := Point{sensor.location.x + distance, sensor.location.y} bottom := Point{sensor.location.x, sensor.location.y + distance} left := Point{sensor.location.x - distance, sensor.location.y} addLinePoints(pointSet, top, right) addLinePoints(pointSet, right, bottom) addLinePoints(pointSet, bottom, left) addLinePoints(pointSet, left, top) } func Run(filename string, yStr string, maxCoordStr string) { y, err := strconv.Atoi(yStr) if err != nil { fmt.Println("PANIC: bad y argument", yStr) return } maxCoord, err := strconv.Atoi(maxCoordStr) if err != nil { fmt.Println("PANIC: bad y argument", maxCoordStr) return } file, err := os.Open(filename) if err != nil { fmt.Println("Error opening file:", err) return } scanner := bufio.NewScanner(file) scanner.Split(bufio.ScanLines) sensors := []Sensor{} beacons := []Point{} for scanner.Scan() { line := scanner.Text() sensor, beacon := parseLine(line) sensors = append(sensors, sensor) beacons = append(beacons, beacon) } file.Close() fmt.Println(sensors) count := 0 for x := leftmostPoint(sensors); x <= rightmostPoint(sensors); x++ { if isBeacon(x, y, beacons) { continue } if inSensorRange(x, y, sensors) != nil { count += 1 } } fmt.Println("Beacons couldn't be in", count, "places on line", y) candidates := []Point{} for _, sensor := range sensors { addEdgePoints(&candidates, sensor) } for _, candidate := range candidates { if candidate.x >= 0 && candidate.y >= 0 && candidate.x <= maxCoord && candidate.y <= maxCoord { closestSensor := inSensorRange(candidate.x, candidate.y, sensors) if closestSensor == nil { fmt.Printf("Found possible beacon location at (%d, %d). Frequency value is %d\n", candidate.x, candidate.y, candidate.x*4000000+candidate.y) } } } }