package main import ( "AOC2021/src/helper" "fmt" "math" "os" "strings" ) type scanner struct { points [][3]int position [3]int } func main() { args := os.Args[1:] input, err := helper.GetInput(args[0]) if err != nil { fmt.Println(err) } var scanners []scanner for _, row := range input { if row[1] == '-' { scanners = append(scanners, scanner{[][3]int{}, [3]int{}}) } else { tmpPoint, _ := helper.MapToNumber(strings.Split(row, ",")) scanners[len(scanners)-1].points = append(scanners[len(scanners)-1].points, [3]int{tmpPoint[0], tmpPoint[1], tmpPoint[2]}) } } hitScanners := []int{0} run := true for run { run = runUntilFirstHit(&scanners, &hitScanners) } inputTestResult, _ := helper.GetInput("day19TestResultPoints.txt") resultPoints := [][3]int{} for _, row := range inputTestResult { tmpPoint, _ := helper.MapToNumber(strings.Split(row, ",")) resultPoints = append(resultPoints, [3]int{tmpPoint[0], tmpPoint[1], tmpPoint[2]}) } var max float64 for i, _ := range scanners { for j, _ := range scanners { if i != j { diff := diffBetweenVectors(scanners[i].position, scanners[j].position) manhattan := math.Abs(float64(diff[0])) + math.Abs(float64(diff[1])) + math.Abs(float64(diff[2])) if manhattan > max { max = manhattan } } } } fmt.Println(len(scanners[0].points)) fmt.Println(max) } func runUntilFirstHit(scanners *[]scanner, hitScanners *[]int) bool { for i := 0; i < len(*scanners); i++ { if !helper.Contains(i, *hitScanners) && runFor(scanners, 0, i) { *hitScanners = append(*hitScanners, i) return true } } return false } func runFor(scanners *[]scanner, i int, j int) bool { returnBool := checkIfScannersHaveMatchingBeacons(scanners, 0, j) if returnBool { pointSet := make(map[[3]int]struct{}) for _, point := range (*scanners)[0].points { pointSet[point] = struct{}{} } (*scanners)[0].points = [][3]int{} for key, _ := range pointSet { (*scanners)[0].points = append((*scanners)[0].points, key) } } return returnBool } func checkIfScannersHaveMatchingBeacons(scanners *[]scanner, i int, j int) bool { scanner1 := &(*scanners)[i] scanner2 := &(*scanners)[j] pointMapper := getOverlappingPoints(*scanner1, *scanner2) if len(pointMapper) >= 12 { rotationsForScanner := getAllPossibleRotationsForScanner(*scanner2) i, diff := getRightRotation(scanner1, pointMapper, rotationsForScanner) scanner2.position = diff var pointsOfScanner2inRelationToScanner1 [][3]int for x := 0; x < len(rotationsForScanner); x++ { point := rotationsForScanner[x][i] pointWithDiff := [3]int{point[0] + diff[0], point[1] + diff[1], point[2] + diff[2]} pointsOfScanner2inRelationToScanner1 = append(pointsOfScanner2inRelationToScanner1, pointWithDiff) } scanner1.points = append(scanner1.points, pointsOfScanner2inRelationToScanner1...) return true } return false } func getRightRotation(scanner1 *scanner, pointMapper [][2]int, rotationsForScanner [][][3]int) (int, [3]int) { for i := 0; i < 24; i++ { firstDiff := diffBetweenVectors(rotationsForScanner[pointMapper[0][1]][i], scanner1.points[pointMapper[0][0]]) different := false for n := 1; n < len(pointMapper); n++ { rotation := rotationsForScanner[pointMapper[n][1]][i] diff := diffBetweenVectors(rotation, scanner1.points[pointMapper[n][0]]) if firstDiff != diff { different = true } } if different == false { return i, firstDiff } } return -1, [3]int{0, 0, 0} } func getOverlappingPoints(sc1 scanner, sc2 scanner) (pointPairs [][2]int) { distances0 := getallDistancesBetweenPointsForScanner(sc1) distances1 := getallDistancesBetweenPointsForScanner(sc2) for i, _ := range distances0 { for j, _ := range distances1 { if len(helper.OverlapFloatArray(distances0[i], distances1[j])) >= 11 { pointPairs = append(pointPairs, [2]int{i, j}) } } } return } func turn(point *[3]int) { *point = [3]int{-point[1], point[0], point[2]} } func roll(point *[3]int) { *point = [3]int{point[0], point[2], -point[1]} } func getAllPossibleRotationsForPoint(point *[3]int) (points [][3]int) { rotationOrder := "RTTTRTTTRTTT" switchRotationOrder := "RTR" executeRotationOrder(point, rotationOrder, &points) executeRotationOrder(point, switchRotationOrder, &[][3]int{}) executeRotationOrder(point, rotationOrder, &points) return } func executeRotationOrder(point *[3]int, order string, points *[][3]int) { for _, char := range order { switch char { case 'R': roll(point) case 'T': turn(point) } *points = append(*points, *point) } return } func getAllPossibleRotationsForScanner(scanner scanner) [][][3]int { permutations := [][][3]int{} for _, point := range scanner.points { permutations = append(permutations, getAllPossibleRotationsForPoint(&point)) } return permutations } func getallDistancesBetweenPointsForScanner(scanner scanner) [][]float64 { var distances [][]float64 for i, point1 := range scanner.points { var distancesForPoint []float64 for j, point2 := range scanner.points { if i != j { distancesForPoint = append(distancesForPoint, distanceBetweenVectors(point1, point2)) } } distances = append(distances, distancesForPoint) } return distances } func distanceBetweenVectors(v1 [3]int, v2 [3]int) float64 { var diffs [3]float64 for i, _ := range v1 { diffs[i] = float64(v2[i] - v1[i]) } return math.Sqrt(math.Pow(diffs[0], 2) + math.Pow(diffs[1], 2) + math.Pow(diffs[2], 2)) } func diffBetweenVectors(v1 [3]int, v2 [3]int) [3]int { var diff [3]int for i, _ := range v1 { diff[i] = v2[i] - v1[i] } return diff }