package day13 import ( "fmt" "gitea.paas.celticinfo.fr/oabrivard/aoc2023/utils" ) func isMirror(vector []int) bool { if len(vector) == 0 { return true } if len(vector) == 1 { return false } return vector[0] == vector[len(vector)-1] && isMirror(vector[1:len(vector)-1]) } func findMirrorPos(vector []int) int { for i := range vector { if isMirror(vector[i:]) { return i + (len(vector)-i)/2 } } for j := len(vector); j > 0; j-- { if isMirror(vector[:j]) { return j / 2 } } return -1 } /* func findMirror2(vector []int, start int, end int, skipFirst bool) int { if start > end { if start < len(vector) && vector[start] == vector[end] { return end } else { return -1 } } if vector[start] == vector[end] { result := -1 for i := start + 1; i < end+1; i++ { result = findMirror2(vector, i, end-1, skipFirst) if result != -1 { break } } return result } else { if skipFirst { return findMirror2(vector, start+1, end, skipFirst) } else { return findMirror2(vector, start, end-1, skipFirst) } // skipFirstResult := findMirror(vector, start+1, end) // if skipFirstResult > 0 { // return skipFirstResult // } else { // skipLastResult := findMirror(vector, start, end+1) // if skipLastResult > 0 { // return skipLastResult // } // } } } */ func sumPatternLines(lines [][]byte) int { result := 0 height := len(lines) width := len(lines[0]) matrix := make([][]byte, height) vector := make([]int, width) for row, line := range lines { matrix[row] = make([]byte, len(line)) for col, r := range line { matrix[row][col] = r if r == '#' { vector[col] += utils.Pow2(row) } } } /* colCount := findMirror(vector, 0, width-1, true) + 1 if colCount > 0 { //fmt.Println(vector) fmt.Println("found vertical at", colCount) } else { colCount = findMirror(vector, 0, width-1, false) + 1 if colCount > 0 { //fmt.Println(vector) fmt.Println("found vertical at", colCount) } } */ colCount := findMirrorPos(vector) if colCount > 0 { result = colCount fmt.Println("found vertical at", colCount) /* for _, l := range lines { fmt.Println(string(l)) } */ } vector = make([]int, height) for col := 0; col < width; col++ { for row := 0; row < height; row++ { if matrix[row][col] == '#' { vector[row] += utils.Pow2(col) } } } /* rowCount := findMirror(vector, 0, height-1, true) + 1 if rowCount > 0 { //fmt.Println(vector) fmt.Println("found horizontal at", rowCount) } else { rowCount = findMirror(vector, 0, height-1, false) + 1 if rowCount > 0 { //fmt.Println(vector) fmt.Println("found horizontal at", rowCount) } } */ rowCount := findMirrorPos(vector) if rowCount > 0 { result += rowCount * 100 fmt.Println("found horizontal at", rowCount) /* for _, l := range lines { fmt.Println(string(l)) } */ } return result } func SumMirrorLines(lines []string) int { result := 0 pattern := [][]byte{} count := 0 for _, line := range lines { if line == "" { fmt.Println("Analyzing pattern", count) result += sumPatternLines(pattern) pattern = [][]byte{} count++ } else { pattern = append(pattern, []byte(line)) } } return result } func SumMirrorLinesWithSumdge(lines []string) int { result := 0 pattern := [][]byte{} count := 0 for _, line := range lines { if line == "" { fmt.Println("Analyzing pattern", count) sum := 0 OuterLoop: for row := range pattern { for col := range pattern[row] { saved := pattern[row][col] if saved == '.' { pattern[row][col] = '#' } else { pattern[row][col] = '.' } sum = sumPatternLines(pattern) pattern[row][col] = saved if sum > 0 { break OuterLoop } } } result += sum pattern = [][]byte{} count++ } else { pattern = append(pattern, []byte(line)) } } return result } func findNextReflectionPoint(vector []int, first int, vector2 []int, smudge int) (bool, int) { width := len(vector) found := false start := first end := 0 result := -1 smudgeCount := 0 for i := first; i < width-1; i++ { if vector[i] == vector[i+1] { found = true result = i start = i end = i + 1 break } if smudgeCount < smudge && (vector2[i]+smudge == vector2[i+1] || vector2[i] == vector2[i+1]+smudge) { smudgeCount++ found = true result = i start = i end = i + 1 break } } if !found { return false, result } for { if vector[start] != vector[end] { if smudgeCount >= smudge { return false, result } else { if vector2[start]+smudge == vector2[end] || vector2[start] == vector2[end]+smudge { smudgeCount++ } else { return false, result } } } if start == 0 { if smudgeCount < smudge { return false, result } else { return true, result } } if end == width-1 { if smudgeCount < smudge { return false, result } else { return true, result } } start-- end++ } } func getPatternSum(lines [][]byte, smudge int) (int, int) { height := len(lines) width := len(lines[0]) matrix := make([][]byte, height) vector := make([]int, width) vector2 := make([]int, width) for row, line := range lines { matrix[row] = make([]byte, len(line)) for col, r := range line { matrix[row][col] = r if r == '#' { vector[col] += utils.Pow2(row) vector2[col] += 1 } } } success, colCount := findNextReflectionPoint(vector, 0, vector2, smudge) colCount++ for { if success { fmt.Println("found vertical at", colCount) /* for _, l := range lines { fmt.Println(string(l)) } */ break } if colCount >= len(vector)-1 || colCount == 0 { break } success, colCount = findNextReflectionPoint(vector, colCount, vector2, smudge) colCount++ } vector = make([]int, height) vector2 = make([]int, height) for col := 0; col < width; col++ { for row := 0; row < height; row++ { if matrix[row][col] == '#' { vector[row] += utils.Pow2(col) vector2[row] += 1 } } } success, rowCount := findNextReflectionPoint(vector, 0, vector2, smudge) rowCount++ for { if success { fmt.Println("found horizontal at", rowCount) /* for _, l := range lines { fmt.Println(string(l)) } */ break } if rowCount >= len(vector)-1 || rowCount == 0 { break } success, rowCount = findNextReflectionPoint(vector, rowCount, vector2, smudge) rowCount++ } return rowCount, colCount } func SumMirrorLines2(lines []string, smudge int) int { result := 0 pattern := [][]byte{} count := 0 for _, line := range lines { if line == "" { fmt.Println("Analyzing pattern", count) rowCount, colCount := getPatternSum(pattern, smudge) result += rowCount*100 + colCount pattern = [][]byte{} count++ } else { pattern = append(pattern, []byte(line)) } } return result } func SumMirrorLinesWithSumdge2(lines []string) int { result := 0 pattern := [][]byte{} count := 0 for _, line := range lines { if line == "" { fmt.Println("Analyzing pattern", count) rowBase, colBase := getPatternSum(pattern, 0) sum := 0 OuterLoop: for row := range pattern { for col := range pattern[row] { saved := pattern[row][col] if saved == '.' { pattern[row][col] = '#' } else { pattern[row][col] = '.' } rowCount, colCount := getPatternSum(pattern, 1) if rowCount != rowBase && colBase != colCount { for _, l := range pattern { fmt.Println(string(l)) } fmt.Println(row, col) sum += rowCount*100 + colCount } pattern[row][col] = saved if sum > 0 { break OuterLoop } } } result += sum pattern = [][]byte{} count++ } else { pattern = append(pattern, []byte(line)) } } return result } func vectorDiff(v1 []int, v2 []int) int { sum := 0 for i, v := range v1 { sum += utils.AbsInt(v - v2[i]) } return sum } // Only valid solution for both parts func findReflectionPoint(matrix [][]int, smudge int) int { width := len(matrix) // trouver la premiere paire de layouts a partir de 'first' for first := 0; first < width-1; { smudgeCount := smudge start := -1 end := -1 for i := first; i < width-1; i++ { diff := vectorDiff(matrix[i], matrix[i+1]) if smudgeCount >= diff { smudgeCount -= diff start = i end = i + 1 break } } if start == -1 { return -1 } result := start for { if start == 0 || end == width-1 { if smudgeCount == 0 { return result } else { first = result + 1 break } } start-- end++ diff := vectorDiff(matrix[start], matrix[end]) smudgeCount -= diff if smudgeCount < 0 { first = result + 1 break } } } return -1 } // Only valid solution for both parts func SumMirrorLines3(lines []string, smudge int) int { result := 0 matrix := [][]int{} count := 0 for _, line := range lines { if line == "" { fmt.Println("Analyzing pattern", count) rowCount := findReflectionPoint(matrix, smudge) + 1 matrix2 := utils.Transpose[int](matrix) colCount := findReflectionPoint(matrix2, smudge) + 1 fmt.Println("found horizontal at ", rowCount, "and vertical at ", colCount) result += rowCount*100 + colCount matrix = [][]int{} count++ } else { vector := make([]int, len(line)) for j, b := range line { if b == '.' { vector[j] = 0 } else { vector[j] = 1 } } matrix = append(matrix, vector) } } return result }