Tapping out on Day 19
This commit is contained in:
227
nineteen/mapping.go
Normal file
227
nineteen/mapping.go
Normal file
@@ -0,0 +1,227 @@
|
||||
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))))
|
||||
}
|
||||
Reference in New Issue
Block a user