228 lines
4.6 KiB
Go
228 lines
4.6 KiB
Go
package nineteen
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"math"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
type offset struct {
|
|
label string
|
|
x int
|
|
y int
|
|
z int
|
|
}
|
|
|
|
type point struct {
|
|
x int
|
|
y int
|
|
z int
|
|
}
|
|
|
|
type distance struct {
|
|
first string
|
|
second string
|
|
magnitude float64
|
|
}
|
|
|
|
type pair struct {
|
|
aIndex int
|
|
a distance
|
|
|
|
bIndex int
|
|
b distance
|
|
}
|
|
|
|
type beacon struct {
|
|
references map[int]string
|
|
}
|
|
|
|
type scanner struct {
|
|
id int
|
|
location point
|
|
distances []distance
|
|
beacons []offset
|
|
}
|
|
|
|
type mapping struct {
|
|
scanners []*scanner
|
|
beacons []beacon
|
|
}
|
|
|
|
func (m *mapping) load(filename string) error {
|
|
file, err := os.Open(filename)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer file.Close()
|
|
s := bufio.NewScanner(file)
|
|
|
|
m.scanners = []*scanner{}
|
|
newScanner := true
|
|
var scan *scanner
|
|
|
|
for s.Scan() {
|
|
if s.Text() == "" {
|
|
newScanner = true
|
|
m.scanners = append(m.scanners, scan)
|
|
continue
|
|
}
|
|
|
|
if newScanner {
|
|
scan = &scanner{}
|
|
header := strings.Split(s.Text(), " ")
|
|
newScannerID, _ := strconv.Atoi(header[2])
|
|
scan.id = newScannerID
|
|
newScanner = false
|
|
continue
|
|
}
|
|
|
|
coords := strings.Split(s.Text(), ",")
|
|
xVal, _ := strconv.Atoi(coords[0])
|
|
yVal, _ := strconv.Atoi(coords[1])
|
|
zVal, _ := strconv.Atoi(coords[2])
|
|
scan.beacons = append(scan.beacons, offset{
|
|
label: s.Text(),
|
|
x: xVal,
|
|
y: yVal,
|
|
z: zVal,
|
|
})
|
|
}
|
|
|
|
m.scanners = append(m.scanners, scan)
|
|
return nil
|
|
}
|
|
|
|
func (m *mapping) initialize() {
|
|
// For each scanner initialize the distances between points
|
|
for _, s := range m.scanners {
|
|
// For each beacon in the scanner find its distance to all others
|
|
for i := 0; i < len(s.beacons)-1; i++ {
|
|
// We don't need to check i == j ever and don't need to do a full double loop
|
|
for j := i + 1; j < len(s.beacons); j++ {
|
|
s.distances = append(s.distances, distance{
|
|
first: s.beacons[i].label,
|
|
second: s.beacons[j].label,
|
|
magnitude: distanceMagnitude(s.beacons[i], s.beacons[j]),
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check each scanner for overlap
|
|
for i := 0; i < len(m.scanners)-1; i++ {
|
|
for j := i + 1; j < len(m.scanners); j++ {
|
|
overlapMagnitudes := []pair{}
|
|
for _, iDist := range m.scanners[i].distances {
|
|
for _, jDist := range m.scanners[j].distances {
|
|
if iDist.magnitude == jDist.magnitude {
|
|
overlapMagnitudes = append(overlapMagnitudes, pair{
|
|
aIndex: i,
|
|
a: iDist,
|
|
bIndex: j,
|
|
b: jDist,
|
|
})
|
|
}
|
|
}
|
|
}
|
|
if len(overlapMagnitudes) >= 6 {
|
|
fmt.Println("Overlap between scanners", i, "and", j)
|
|
}
|
|
|
|
if len(overlapMagnitudes) >= 6 {
|
|
for _, p := range overlapMagnitudes {
|
|
// Check if we have seen this on another scanner
|
|
found := false
|
|
var newBeacon *beacon
|
|
for _, b := range m.beacons {
|
|
if b.references[p.aIndex] == p.a.first {
|
|
b.references[p.bIndex] = p.b.first
|
|
newBeacon = &beacon{
|
|
references: map[int]string{
|
|
p.aIndex: p.a.second,
|
|
p.bIndex: p.b.second,
|
|
},
|
|
}
|
|
found = true
|
|
} else if b.references[p.aIndex] == p.a.second {
|
|
b.references[p.bIndex] = p.b.second
|
|
newBeacon = &beacon{
|
|
references: map[int]string{
|
|
p.aIndex: p.a.first,
|
|
p.bIndex: p.b.first,
|
|
},
|
|
}
|
|
|
|
found = true
|
|
}
|
|
|
|
if b.references[p.bIndex] == p.b.first {
|
|
b.references[p.aIndex] = p.a.first
|
|
|
|
if found {
|
|
newBeacon = nil
|
|
} else {
|
|
newBeacon = &beacon{
|
|
references: map[int]string{
|
|
p.aIndex: p.a.second,
|
|
p.bIndex: p.b.second,
|
|
},
|
|
}
|
|
}
|
|
|
|
found = true
|
|
} else if b.references[p.bIndex] == p.b.second {
|
|
b.references[p.bIndex] = p.b.second
|
|
if found {
|
|
newBeacon = nil
|
|
} else {
|
|
newBeacon = &beacon{
|
|
references: map[int]string{
|
|
p.aIndex: p.a.first,
|
|
p.bIndex: p.b.first,
|
|
},
|
|
}
|
|
}
|
|
found = true
|
|
}
|
|
if found {
|
|
break
|
|
}
|
|
}
|
|
|
|
if found {
|
|
if newBeacon != nil {
|
|
m.beacons = append(m.beacons, *newBeacon)
|
|
}
|
|
continue
|
|
}
|
|
|
|
b1 := beacon{
|
|
references: map[int]string{
|
|
p.aIndex: p.a.first,
|
|
p.bIndex: p.b.first,
|
|
},
|
|
}
|
|
|
|
b2 := beacon{
|
|
references: map[int]string{
|
|
p.aIndex: p.a.second,
|
|
p.bIndex: p.b.second,
|
|
},
|
|
}
|
|
|
|
m.beacons = append(m.beacons, b1, b2)
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
func distanceMagnitude(a offset, b offset) float64 {
|
|
return math.Sqrt(float64(((b.x - a.x) * (b.x - a.x)) + ((b.y - a.y) * (b.y - a.y)) + ((b.z - a.z) * (b.z - a.z))))
|
|
}
|