230 lines
5.3 KiB
Go
230 lines
5.3 KiB
Go
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
|
|
}
|