diff --git a/2021/day19/main.go.old.2 b/2021/day19/main.go.old.2 new file mode 100644 index 0000000..933ef37 --- /dev/null +++ b/2021/day19/main.go.old.2 @@ -0,0 +1,122 @@ +package main + +import ( + "fmt" + "os" + "strings" + + h "git.bullercodeworks.com/brian/adventofcode/helpers" +) + +func main() { + fmt.Println("vim-go") + inp := h.StdinToStringSlice() + part1(inp) +} + +func part1(inp []string) { + scanners := parseScanners(inp) + m, l := matchScanners(scanners) + fmt.Println(m) + fmt.Println(l) +} + +func parseScanners(inp []string) []Scanner { + var scanners []Scanner + for i := range inp { + if strings.HasPrefix(inp[i], "---") { + // Find the next empty line + end := i + for ; end < len(inp); end++ { + if inp[end] == "" { + break + } + } + // a new scanner + wrk, err := NewScannerFromInput(inp[i:end]) + if err == nil { + scanners = append(scanners, wrk) + } else { + fmt.Println("Error parsing scanners") + os.Exit(1) + } + } + } + return scanners +} + +type Match struct { + beacon Beacon + rotation int +} + +func matchScanners(scanners []Scanner) (map[Pair]Match, []int) { + matched := make(map[Pair]Match) + newMatch := []int{0} + remaining := make(map[int]bool) + for i := 1; i < len(scanners); i++ { + remaining[i] = true + } + prev := make([]int, len(scanners)) + for len(remaining) > 0 { + fmt.Println("Remaining:", len(remaining)) + next := []int{} + for _, mID := range newMatch { + fmt.Println(" Working", mID) + for uID := range remaining { + fmt.Println(" ->", uID) + if _, ok := matched[Pair{mID, uID}]; ok { + continue + } + for _, finger := range scanners[mID].prints { + for _, fWrk := range scanners[uID].prints { + if finger.area == fWrk.area && finger.circumference == fWrk.circumference { + // Found a matching print in both scanners, figure out orientation + tx := findTranslations(finger, fWrk) + fmt.Println("Translations:", tx) + //fb, fRotID := findTranslation(finger, fWrk) + for k, v := range tx { + if len(v) >= 3 { + fmt.Println("Found:", v) + prev[uID] = mID + matched[Pair{mID, uID}] = Match{k, v[0].rotID} + next = append(next, uID) + delete(remaining, uID) + break + } + } + } + } + } + } + } + newMatch = next + } + return matched, prev +} + +func findTranslations(f1, f2 Triangle) map[Beacon][]Translation { + //func findTranslation(f1, f2 Triangle) (Beacon, int) { + tx := make(map[Beacon][]Translation) + for rID := 0; rID < 24; rID++ { + for oIdx, orig := range []Beacon{f1.a, f1.b, f1.c} { + for fIdx, foreign := range []Beacon{f2.a, f2.b, f2.c} { + diff := foreign.Rotate(rID).Sub(orig) + t := Translation{oIdx, fIdx, rID} + if v, ok := tx[diff]; ok { + v = append(v, t) + tx[diff] = v + } else { + tx[diff] = []Translation{t} + } + } + } + for _, v := range tx { + // If we find 3, we have a match + if len(v) >= 3 { + return tx + } + } + } + return tx +} diff --git a/2021/day19/structs.go b/2021/day19/structs.go new file mode 100644 index 0000000..cc8521e --- /dev/null +++ b/2021/day19/structs.go @@ -0,0 +1,126 @@ +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 +} diff --git a/2021/day19/structs.go.old.2 b/2021/day19/structs.go.old.2 new file mode 100644 index 0000000..a77b1e5 --- /dev/null +++ b/2021/day19/structs.go.old.2 @@ -0,0 +1,192 @@ +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, + } +}