package main import ( "errors" "fmt" "sort" "strings" h "git.bullercodeworks.com/brian/adventofcode/helpers" ) type Pair struct { a int b int } type Translation struct { orig, foreign, rotID int } type Triangle struct { a, b, c Beacon circumference, area int } func NewTriangle(a, b, c Beacon) Triangle { t := Triangle{a: a, b: b, c: c} t.circumference = findCircumference(a, b, c) t.area = findArea(a, b, c) return t } type Scanner struct { number int beacons []Beacon prints []Triangle } 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) } } prints := make([]Triangle, 0, len(s.beacons)) dupes := make(map[Pair]struct{}) for _, b := range s.beacons { c1, c2 := b.findNearestTwo(s.beacons) t := NewTriangle(b, c1, c2) p := Pair{t.area, t.circumference} if _, ok := dupes[p]; !ok { prints = append(prints, t) } dupes[p] = struct{}{} } return s, nil } type Beacon struct { x, y, z int } 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) Sub(c Beacon) Beacon { return Beacon{ x: b.x - c.x, y: b.y - c.y, z: b.z - c.z, } } func (b Beacon) Negate() Beacon { return Beacon{ x: -b.x, y: -b.y, z: -b.z, } } func (b Beacon) Equals(c Beacon) bool { return b.x == c.x && b.y == c.y && b.z == c.z } func (b Beacon) RotateX90() Beacon { return Beacon{ x: b.x, y: -b.z, z: b.y, } } func (b Beacon) RotateY90() Beacon { return Beacon{ x: -b.z, y: b.y, z: b.x, } } func (b Beacon) RotateZ90() Beacon { return Beacon{ x: b.y, y: -b.x, z: b.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) Rotate(rid int) Beacon { l := b.AllRotations() if rid < len(l) { return l[rid] } return b } func (b Beacon) Distance(c Beacon) int { return h.Abs(b.x-c.x) + h.Abs(b.y-c.y) + h.Abs(b.z-c.z) } func (b Beacon) findNearestTwo(list []Beacon) (Beacon, Beacon) { var distances []Pair for k, v := range list { if !b.Equals(v) { distances = append(distances, Pair{a: b.Distance(v), b: k}) } } sort.Slice(distances, func(i, j int) bool { return distances[i].a < distances[j].a }) return list[distances[0].b], list[distances[1].b] } func findCircumference(a, b, c Beacon) int { return a.Distance(b) + b.Distance(c) + c.Distance(a) } func findArea(a, b, c Beacon) int { wrk := crossProduct(b.Sub(a), c.Sub(a)) return h.Abs(wrk.x) + h.Abs(wrk.y) + h.Abs(wrk.z) } func crossProduct(a, b Beacon) Beacon { return Beacon{ x: a.y*b.z - a.z*b.y, y: a.z*b.x - a.x*b.z, z: a.x*b.y - a.y*b.x, } }