127 lines
2.9 KiB
Go
127 lines
2.9 KiB
Go
package main
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
|
|
h "git.bullercodeworks.com/brian/adventofcode/helpers"
|
|
)
|
|
|
|
type scanner struct {
|
|
number int
|
|
region map[h.Coordinate]bool
|
|
beacons []beacon
|
|
}
|
|
|
|
func NewScanner(b []beacon) scanner {
|
|
return scanner{beacons: b}
|
|
}
|
|
|
|
func NewScannerFromInput(inp []string) (scanner, error) {
|
|
s := scanner{}
|
|
r := strings.NewReader(inp[0])
|
|
_, err := fmt.Fscanf(r, "--- scanner %d ---", &s.number)
|
|
if err != nil {
|
|
return s, errors.New("No Scanner ID")
|
|
}
|
|
for _, v := range inp[1:] {
|
|
r = strings.NewReader(v)
|
|
b := beacon{}
|
|
_, err := fmt.Fscanf(r, "%d,%d,%d", &b.x, &b.y, &b.z)
|
|
if err == nil {
|
|
s.beacons = append(s.beacons, b)
|
|
}
|
|
}
|
|
return s, nil
|
|
}
|
|
|
|
func (s scanner) allRotations() []scanner {
|
|
var ret []scanner
|
|
var beacons [][]beacon
|
|
for i := range s.beacons {
|
|
beacons = append(beacons, s.beacons[i].allRotations())
|
|
}
|
|
for i := range beacons {
|
|
ret = append(ret, NewScanner(beacons[i]))
|
|
}
|
|
return ret
|
|
}
|
|
|
|
func (s scanner) getTransformedIfOverlap(w scanner) (transformedScanner, error) {
|
|
for _, otherReoriented := range w.allRotations() {
|
|
for _, first := range s.beacons {
|
|
for _, second := range otherReoriented.beacons {
|
|
otherPosition := first.sub(second)
|
|
var otherTransformed []beacon
|
|
for _, it := range otherReoriented.beacons {
|
|
otherTransformed = append(otherTransformed, otherPosition.add(it))
|
|
}
|
|
// Check if otherTransformed has at least 12 beacons in common with s
|
|
var count int
|
|
for _, chkI := range otherTransformed {
|
|
for _, chkJ := range s.beacons {
|
|
if chkI.equals(chkJ) {
|
|
count++
|
|
if count >= 12 {
|
|
return transformedScanner{
|
|
beacons: otherTransformed,
|
|
position: otherPosition,
|
|
}, nil
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return transformedScanner{}, errors.New("Scanners don't overlap")
|
|
}
|
|
|
|
func (s scanner) String() string {
|
|
return fmt.Sprintf("-- Scanner %d (%d beacons) ---", s.number, len(s.beacons))
|
|
}
|
|
|
|
type beacon struct {
|
|
x, y, z int
|
|
}
|
|
|
|
func (b beacon) sub(c beacon) beacon {
|
|
return beacon{
|
|
x: b.x - c.x,
|
|
y: b.y - c.y,
|
|
z: b.z - c.z,
|
|
}
|
|
}
|
|
|
|
func (b beacon) add(c beacon) beacon {
|
|
return beacon{
|
|
x: b.x + c.x,
|
|
y: b.y + c.y,
|
|
z: b.z + c.z,
|
|
}
|
|
}
|
|
|
|
func (b beacon) equals(c beacon) bool {
|
|
return b.x == c.x && b.y == c.y && b.z == c.z
|
|
}
|
|
|
|
func (b beacon) allRotations() []beacon {
|
|
return []beacon{
|
|
{b.x, b.y, b.z}, {b.x, -b.z, b.y}, {b.x, -b.y, -b.z}, {b.x, b.z, -b.y}, {-b.x, -b.y, b.z},
|
|
{-b.x, -b.z, -b.y}, {-b.x, b.y, -b.z}, {-b.x, b.z, b.y}, {-b.z, b.x, -b.y}, {b.y, b.x, -b.z},
|
|
{b.z, b.x, b.y}, {-b.y, b.x, b.z}, {b.z, -b.x, -b.y}, {b.y, -b.x, b.z}, {-b.z, -b.x, b.y},
|
|
{-b.y, -b.x, -b.z}, {-b.y, -b.z, b.x}, {b.z, -b.y, b.x}, {b.y, b.z, b.x}, {-b.z, b.y, b.x},
|
|
{b.z, b.y, -b.x}, {-b.y, b.z, -b.x}, {-b.z, -b.y, -b.x}, {b.y, -b.z, -b.x},
|
|
}
|
|
}
|
|
|
|
func (b beacon) String() string {
|
|
return fmt.Sprintf("{%d,%d,%d}", b.x, b.y, b.z)
|
|
}
|
|
|
|
type transformedScanner struct {
|
|
beacons []beacon
|
|
position beacon
|
|
}
|