Files
2022-12-15 14:56:28 +01:00

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
}