package common import ( "bufio" "fmt" "strconv" "strings" ) type Tile byte const ( Sensor Tile = iota Beacon Covered Free ) type Map struct { sensors []SensorPosition minX int maxX int minY int maxY int } func NewMap() *Map { tileMap := Map{} tileMap.sensors = []SensorPosition{} tileMap.minX = 0 tileMap.maxX = 0 tileMap.minY = 0 tileMap.maxY = 0 return &tileMap } func (tileMap *Map) GetTile(x, y int) Tile { for _, sensor := range tileMap.sensors { if sensor.x == x && sensor.y == y { return Sensor } else if sensor.xBeacon == x && sensor.yBeacon == y { return Beacon } } for _, sensor := range tileMap.sensors { coverageX := sensor.x - sensor.xBeacon if coverageX < 0 { coverageX *= -1 } coverageY := sensor.y - sensor.yBeacon if coverageY < 0 { coverageY *= -1 } coverage := coverageX + coverageY distanceX := sensor.x - x if distanceX < 0 { distanceX *= -1 } distanceY := sensor.y - y if distanceY < 0 { distanceY *= -1 } distance := distanceX + distanceY if distance <= coverage { return Covered } } return Free } func (tileMap *Map) SetSensor(sensor SensorPosition) { tileMap.sensors = append(tileMap.sensors, sensor) coverageX := sensor.x - sensor.xBeacon if coverageX < 0 { coverageX *= -1 } coverageY := sensor.y - sensor.yBeacon if coverageY < 0 { coverageY *= -1 } coverage := coverageX + coverageY if sensor.x - coverage < tileMap.minX { tileMap.minX = sensor.x - coverage } if sensor.x + coverage > tileMap.maxX { tileMap.maxX = sensor.x + coverage } if sensor.y - coverage < tileMap.minY { tileMap.minY = sensor.y - coverage } if sensor.y + coverage > tileMap.maxY { tileMap.maxY = sensor.y + coverage } } func (tileMap *Map) GetCoverageY(y int) int { return tileMap.GetCoverageYInXInterval(tileMap.minX, tileMap.maxX, y) } func (tileMap *Map) GetCoverageYInXInterval(xMin, xMax, y int) int { coverages := []struct{min int; max int}{} nCovered := 0 foundBeacons := make(map[int]struct{}) for _, sensor := range tileMap.sensors { if _, ok := foundBeacons[sensor.xBeacon]; !ok && sensor.yBeacon == y && sensor.xBeacon >= xMin && sensor.xBeacon <= xMax { foundBeacons[sensor.xBeacon] = struct{}{} nCovered-- } coverageX := sensor.x - sensor.xBeacon if coverageX < 0 { coverageX *= -1 } coverageY := sensor.y - sensor.yBeacon if coverageY < 0 { coverageY *= -1 } coverage := coverageX + coverageY if y >= sensor.y - coverage && y <= sensor.y + coverage { distanceY := sensor.y - y if distanceY < 0 { distanceY *= -1 } distanceX := coverage - distanceY coverageXMin := sensor.x - distanceX if coverageXMin < xMin { coverageXMin = xMin } coverageXMax := sensor.x + distanceX if coverageXMax > xMax { coverageXMax = xMax } coverages = append(coverages, struct{min int; max int}{coverageXMin, coverageXMax}) } } for i := 0; i < len(coverages); i++ { for j := 0; j < len(coverages); j++ { if j != i { found := false if coverages[j].min >= coverages[i].min && coverages[j].min <= coverages[i].max && coverages[j].max >= coverages[i].max { coverages[i].max = coverages[j].max found = true } else if coverages[j].min <= coverages[i].min && coverages[j].max >= coverages[i].min && coverages[j].max <= coverages[i].max { coverages[i].min = coverages[j].min found = true } else if coverages[j].min < coverages[i].min && coverages[j].max > coverages[i].max { coverages[i].min = coverages[j].min coverages[i].max = coverages[j].max found = true } else if coverages[j].min >= coverages[i].min && coverages[j].max <= coverages[i].max { found = true } if found { if j == 0 { coverages = coverages[1:] } else if j == len(coverages) - 1 { coverages = coverages[:len(coverages)-1] } else { coverages = append(coverages[0:j], coverages[j+1:]...) } j = 0 } } } } for _, coverage := range(coverages) { nCovered += coverage.max - coverage.min + 1 } return nCovered } func (tileMap *Map) Print(xMin, xMax, yMin, yMax int) { for i := yMin; i <= yMax; i++ { for j := xMin; j <= xMax; j++ { switch tileMap.GetTile(j, i) { case Beacon: fmt.Print("B") case Sensor: fmt.Print("S") case Covered: fmt.Print("#") case Free: fmt.Print(".") } } fmt.Println() } } type SensorPosition struct { x int y int xBeacon int yBeacon int } func Parse(scanner bufio.Scanner) []SensorPosition { sensors := []SensorPosition{} for scanner.Scan() { line := scanner.Text() splittedLine := strings.Split(line, " ") x, _ := strconv.Atoi(splittedLine[2][2:len(splittedLine[2])-1]) y, _ := strconv.Atoi(splittedLine[3][2:len(splittedLine[3])-1]) xBeacon, _ := strconv.Atoi(splittedLine[8][2:len(splittedLine[8])-1]) yBeacon, _ := strconv.Atoi(splittedLine[9][2:]) sensors = append(sensors, SensorPosition{x, y, xBeacon, yBeacon}) } return sensors }