Finally solved 2021 day 19
This commit is contained in:
parent
586ec1330e
commit
ca626cc0f2
@ -1,6 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
@ -10,44 +11,75 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
inp := h.StdinToStringSlice()
|
inp := h.StdinToStringSlice()
|
||||||
scanners := parseScanners(inp)
|
|
||||||
part1(scanners)
|
|
||||||
}
|
|
||||||
|
|
||||||
func part1(scanners []scanner) {
|
ans1, ans2 := solve(inp)
|
||||||
foundBeacons := scanners[0].beacons
|
|
||||||
foundScannerPositions := []beacon{{0, 0, 0}}
|
|
||||||
|
|
||||||
remaining := scanners[1:]
|
|
||||||
for len(remaining) > 0 {
|
|
||||||
fmt.Println(len(remaining), "Remaining")
|
|
||||||
var wrk scanner
|
|
||||||
wrk, remaining = remaining[0], remaining[1:]
|
|
||||||
s, err := NewScanner(foundBeacons).getTransformedIfOverlap(wrk)
|
|
||||||
if err != nil {
|
|
||||||
remaining = append(remaining, wrk)
|
|
||||||
} else {
|
|
||||||
foundBeacons = append(foundBeacons, s.beacons...)
|
|
||||||
foundScannerPositions = append(foundScannerPositions, s.position)
|
|
||||||
}
|
|
||||||
fmt.Println(" ", foundBeacons)
|
|
||||||
}
|
|
||||||
fmt.Println("# Part 1")
|
fmt.Println("# Part 1")
|
||||||
fmt.Println(len(foundScannerPositions))
|
fmt.Println(ans1)
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Println("# Part 2")
|
||||||
|
fmt.Println(ans2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseScanners(inp []string) []scanner {
|
func solve(input []string) (int, int) {
|
||||||
var scanners []scanner
|
scanners := parseScanners(input)
|
||||||
|
|
||||||
|
solved := []Scanner{scanners[0]}
|
||||||
|
solved[0].absoluteCoords = solved[0].relativeCoords
|
||||||
|
solved[0].fillAbsMap()
|
||||||
|
|
||||||
|
// Scanners with a position we don't know yet
|
||||||
|
unk := scanners[1:]
|
||||||
|
// loop until we know them all
|
||||||
|
for len(unk) > 0 {
|
||||||
|
fmt.Print(h.CLEAR_SCREEN, "Processing...\n")
|
||||||
|
c, t := len(solved), len(scanners)
|
||||||
|
h.PrintProgress(c, t)
|
||||||
|
fmt.Printf(" %d/%d %d%%\n", c, t, int(float64(c)/float64(t)*100))
|
||||||
|
|
||||||
|
for i, undet := range unk {
|
||||||
|
ok := undet.findCoords(solved)
|
||||||
|
if ok {
|
||||||
|
solved = append(solved, undet)
|
||||||
|
// remove the determined scanner from the unknown list
|
||||||
|
copy(unk[i:], unk[i+1:])
|
||||||
|
unk = unk[:len(unk)-1]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allBeacons := map[[3]int]bool{}
|
||||||
|
for _, s := range solved {
|
||||||
|
for c := range s.absoluteCoordsMap {
|
||||||
|
allBeacons[c] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var furthest int
|
||||||
|
for i, s1 := range solved {
|
||||||
|
for j, s2 := range solved {
|
||||||
|
if i == j {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
dist := h.Abs(s1.x-s2.x) + h.Abs(s1.y-s2.y) + h.Abs(s1.z-s2.z)
|
||||||
|
if dist > furthest {
|
||||||
|
furthest = dist
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len(allBeacons), furthest
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseScanners(inp []string) []Scanner {
|
||||||
|
var scanners []Scanner
|
||||||
for i := range inp {
|
for i := range inp {
|
||||||
if strings.HasPrefix(inp[i], "---") {
|
if strings.HasPrefix(inp[i], "---") {
|
||||||
// Find the next empty line
|
|
||||||
end := i
|
end := i
|
||||||
for ; end < len(inp); end++ {
|
for ; end < len(inp); end++ {
|
||||||
if inp[end] == "" {
|
if inp[end] == "" {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// a new scanner
|
|
||||||
wrk, err := NewScannerFromInput(inp[i:end])
|
wrk, err := NewScannerFromInput(inp[i:end])
|
||||||
if err == nil {
|
if err == nil {
|
||||||
scanners = append(scanners, wrk)
|
scanners = append(scanners, wrk)
|
||||||
@ -59,3 +91,127 @@ func parseScanners(inp []string) []scanner {
|
|||||||
}
|
}
|
||||||
return scanners
|
return scanners
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Scanner struct {
|
||||||
|
number int
|
||||||
|
x, y, z int
|
||||||
|
relativeCoords [][3]int
|
||||||
|
rotations [][][3]int
|
||||||
|
absoluteCoords [][3]int
|
||||||
|
absoluteCoordsMap map[[3]int]bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewScannerFromInput(inp []string) (Scanner, error) {
|
||||||
|
s := Scanner{
|
||||||
|
absoluteCoordsMap: make(map[[3]int]bool),
|
||||||
|
}
|
||||||
|
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:] {
|
||||||
|
var x, y, z int
|
||||||
|
r = strings.NewReader(v)
|
||||||
|
_, err := fmt.Fscanf(r, "%d,%d,%d", &x, &y, &z)
|
||||||
|
if err != nil {
|
||||||
|
return s, err
|
||||||
|
}
|
||||||
|
s.relativeCoords = append(s.relativeCoords, [3]int{x, y, z})
|
||||||
|
}
|
||||||
|
s.fillRotations()
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Scanner) fillAbsMap() {
|
||||||
|
s.absoluteCoordsMap = map[[3]int]bool{}
|
||||||
|
if len(s.absoluteCoords) == 0 {
|
||||||
|
panic(fmt.Sprintf("absolute coords not set for scanner %d", s.number))
|
||||||
|
}
|
||||||
|
for _, ac := range s.absoluteCoords {
|
||||||
|
s.absoluteCoordsMap[ac] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill in all coordinates for all beacon rotations
|
||||||
|
func (s *Scanner) fillRotations() {
|
||||||
|
dir1 := s.relativeCoords
|
||||||
|
var dir2, dir3, dir4, dir5, dir6 [][3]int
|
||||||
|
for _, c := range dir1 {
|
||||||
|
x, y, z := c[0], c[1], c[2]
|
||||||
|
dir2 = append(dir2, [3]int{x, -y, -z})
|
||||||
|
dir3 = append(dir3, [3]int{x, -z, y})
|
||||||
|
dir4 = append(dir4, [3]int{-y, -z, x})
|
||||||
|
dir5 = append(dir5, [3]int{-x, -z, -y})
|
||||||
|
dir6 = append(dir6, [3]int{y, -z, -x})
|
||||||
|
}
|
||||||
|
sixRotations := [][][3]int{
|
||||||
|
dir1, dir2,
|
||||||
|
dir3, dir4,
|
||||||
|
dir5, dir6,
|
||||||
|
}
|
||||||
|
|
||||||
|
var finalRotations [][][3]int
|
||||||
|
for _, rotation := range sixRotations {
|
||||||
|
var r2, r3, r4 [][3]int
|
||||||
|
for _, c := range rotation {
|
||||||
|
x, y, z := c[0], c[1], c[2]
|
||||||
|
r2 = append(r2, [3]int{-y, x, z})
|
||||||
|
r3 = append(r3, [3]int{-x, -y, z})
|
||||||
|
r4 = append(r4, [3]int{y, -x, z})
|
||||||
|
}
|
||||||
|
finalRotations = append(finalRotations, rotation, r2, r3, r4)
|
||||||
|
}
|
||||||
|
s.rotations = finalRotations
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the absolute coordinates for this scanner, if we can.
|
||||||
|
func (s *Scanner) findCoords(solved []Scanner) bool {
|
||||||
|
for _, rotatedCoords := range s.rotations {
|
||||||
|
for _, set := range solved {
|
||||||
|
for _, absCoord := range set.absoluteCoords {
|
||||||
|
for _, relativeCoord := range rotatedCoords {
|
||||||
|
unsolvedAbsoluteCoords := fillAbsCoords(absCoord, relativeCoord, rotatedCoords)
|
||||||
|
|
||||||
|
var matchingCount int
|
||||||
|
for _, ac := range unsolvedAbsoluteCoords {
|
||||||
|
if set.absoluteCoordsMap[ac] {
|
||||||
|
matchingCount++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if matchingCount >= 12 {
|
||||||
|
s.relativeCoords = rotatedCoords
|
||||||
|
s.absoluteCoords = unsolvedAbsoluteCoords
|
||||||
|
s.fillAbsMap()
|
||||||
|
s.x = absCoord[0] - relativeCoord[0]
|
||||||
|
s.y = absCoord[1] - relativeCoord[1]
|
||||||
|
s.z = absCoord[2] - relativeCoord[2]
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assume that absolute and relative are actually the same coordinate, calc the diff of all relative Coords
|
||||||
|
func fillAbsCoords(absolute, relative [3]int, relativeCoords [][3]int) [][3]int {
|
||||||
|
diff := [3]int{
|
||||||
|
absolute[0] - relative[0],
|
||||||
|
absolute[1] - relative[1],
|
||||||
|
absolute[2] - relative[2],
|
||||||
|
}
|
||||||
|
|
||||||
|
var absCoords [][3]int
|
||||||
|
for _, c := range relativeCoords {
|
||||||
|
absCoords = append(absCoords, [3]int{
|
||||||
|
diff[0] + c[0],
|
||||||
|
diff[1] + c[1],
|
||||||
|
diff[2] + c[2],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return absCoords
|
||||||
|
}
|
||||||
|
@ -1,122 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
@ -1,126 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
@ -1,192 +0,0 @@
|
|||||||
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,
|
|
||||||
}
|
|
||||||
}
|
|
@ -182,12 +182,16 @@ func FileToBytes(fn string) []byte {
|
|||||||
|
|
||||||
// PrintProgress is for outputting a progress bar
|
// PrintProgress is for outputting a progress bar
|
||||||
func PrintProgress(curr, total int) {
|
func PrintProgress(curr, total int) {
|
||||||
pct := int(float64(curr)/float64(total)) * 100
|
pct := int(float64(curr) / float64(total) * 100)
|
||||||
|
fmt.Print("[")
|
||||||
for i := 0; i < 100; i += 10 {
|
for i := 0; i < 100; i += 10 {
|
||||||
if pct > i {
|
if pct > i {
|
||||||
fmt.Print(FILL_CHAR)
|
fmt.Print(FILL_CHAR)
|
||||||
|
} else {
|
||||||
|
fmt.Print(" ")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fmt.Print("]")
|
||||||
}
|
}
|
||||||
|
|
||||||
// StringPermutations takes a string and returns all permutations of it
|
// StringPermutations takes a string and returns all permutations of it
|
||||||
|
Loading…
Reference in New Issue
Block a user