Finally solved 2021 day 19
This commit is contained in:
		| @@ -1,6 +1,7 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"strings" | ||||
| @@ -10,44 +11,75 @@ import ( | ||||
|  | ||||
| func main() { | ||||
| 	inp := h.StdinToStringSlice() | ||||
| 	scanners := parseScanners(inp) | ||||
| 	part1(scanners) | ||||
| } | ||||
|  | ||||
| func part1(scanners []scanner) { | ||||
| 	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) | ||||
| 	} | ||||
| 	ans1, ans2 := solve(inp) | ||||
| 	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 { | ||||
| 	var scanners []scanner | ||||
| func solve(input []string) (int, int) { | ||||
| 	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 { | ||||
| 		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) | ||||
| @@ -59,3 +91,127 @@ func parseScanners(inp []string) []scanner { | ||||
| 	} | ||||
| 	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 | ||||
| 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 { | ||||
| 		if pct > i { | ||||
| 			fmt.Print(FILL_CHAR) | ||||
| 		} else { | ||||
| 			fmt.Print(" ") | ||||
| 		} | ||||
| 	} | ||||
| 	fmt.Print("]") | ||||
| } | ||||
|  | ||||
| // StringPermutations takes a string and returns all permutations of it | ||||
|   | ||||
		Reference in New Issue
	
	Block a user