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 }