More work on 2021 day 19

This commit is contained in:
Brian Buller 2021-12-30 06:13:31 -06:00
parent 3bf29e69ae
commit 586ec1330e
3 changed files with 440 additions and 0 deletions

122
2021/day19/main.go.old.2 Normal file
View File

@ -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
}

126
2021/day19/structs.go Normal file
View File

@ -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
}

192
2021/day19/structs.go.old.2 Normal file
View File

@ -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,
}
}