Completed both parts of Day 13 puzzle with help to debug my code

main
oabrivard 2 years ago
parent 23060cdf49
commit 2e3c9db727

@ -0,0 +1,527 @@
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
}

@ -0,0 +1,294 @@
package day13
import (
"testing"
"gitea.paas.celticinfo.fr/oabrivard/aoc2023/utils"
)
func TestSumMirrorLines(t *testing.T) {
lines := []string{
"#.##..##.",
"..#.##.#.",
"##......#",
"##......#",
"..#.##.#.",
"..##..##.",
"#.#.##.#.",
"",
"#...##..#",
"#....#..#",
"..##..###",
"#####.##.",
"#####.##.",
"..##..###",
"#....#..#",
"",
}
result := SumMirrorLines(lines)
if result != 405 {
t.Fatalf("expected 405, got %v", result)
}
}
func TestSumMirrorLinesDebug(t *testing.T) {
lines := []string{
"#...#..#.",
"#...#..#.",
".####..#.",
"..#..#..#",
"...#....#",
"##..###..",
"#...####.",
"#...####.",
"##..##...",
"...#....#",
"..#..#..#",
".####..#.",
"#...#..#.",
"",
}
result := SumMirrorLines(lines)
if result != 100 {
t.Fatalf("expected 100, got %v", result)
}
}
func TestSumMirrorLinesWithInput1(t *testing.T) {
lines := utils.ReadLines("input.txt")
result := SumMirrorLines(lines)
if result != 43614 {
t.Fatalf("expected 43614 %v", result)
}
}
func TestSumMirrorLinesWithSmudge(t *testing.T) {
lines := []string{
"#.##..##.",
"..#.##.#.",
"##......#",
"##......#",
"..#.##.#.",
"..##..##.",
"#.#.##.#.",
"",
"#...##..#",
"#....#..#",
"..##..###",
"#####.##.",
"#####.##.",
"..##..###",
"#....#..#",
"",
}
result := SumMirrorLinesWithSumdge(lines)
if result != 400 {
t.Fatalf("expected 400, got %v", result)
}
}
func TestSumMirrorLinesWithSmudgeWithInput1(t *testing.T) {
lines := utils.ReadLines("input.txt")
result := SumMirrorLinesWithSumdge(lines)
if result != 43614 {
t.Fatalf("expected 43614 %v", result)
}
}
func TestSumMirrorLines2(t *testing.T) {
lines := []string{
"#.##..##.",
"..#.##.#.",
"##......#",
"##......#",
"..#.##.#.",
"..##..##.",
"#.#.##.#.",
"",
"#...##..#",
"#....#..#",
"..##..###",
"#####.##.",
"#####.##.",
"..##..###",
"#....#..#",
"",
}
result := SumMirrorLines2(lines, 0)
if result != 405 {
t.Fatalf("expected 405, got %v", result)
}
}
func TestSumMirrorLines2WithInput1(t *testing.T) {
lines := utils.ReadLines("input.txt")
result := SumMirrorLines2(lines, 0)
if result != 43614 {
t.Fatalf("expected 43614 %v", result)
}
}
func TestSumMirrorLines2Debug(t *testing.T) {
lines := []string{
"...###...##",
"##....#..#.",
"###.#.#....",
"#..###.##.#",
"#..###.##.#",
"###.#......",
"##....#..#.",
"...###...##",
"...###...##",
"##....#..#.",
"###.#......",
"",
}
result := SumMirrorLines2(lines, 0)
if result != 800 {
t.Fatalf("expected 800, got %v", result)
}
}
func TestSumMirrorLines2WithSmudge(t *testing.T) {
lines := []string{
"#.##..##.",
"..#.##.#.",
"##......#",
"##......#",
"..#.##.#.",
"..##..##.",
"#.#.##.#.",
"",
"#...##..#",
"#....#..#",
"..##..###",
"#####.##.",
"#####.##.",
"..##..###",
"#....#..#",
"",
}
result := SumMirrorLines2(lines, 1)
if result != 405 {
t.Fatalf("expected 405, got %v", result)
}
}
func TestSumMirrorLinesWithSmudge2(t *testing.T) {
lines := []string{
"#.##..##.",
"..#.##.#.",
"##......#",
"##......#",
"..#.##.#.",
"..##..##.",
"#.#.##.#.",
"",
"#...##..#",
"#....#..#",
"..##..###",
"#####.##.",
"#####.##.",
"..##..###",
"#....#..#",
"",
}
result := SumMirrorLinesWithSumdge2(lines)
if result != 400 {
t.Fatalf("expected 400, got %v", result)
}
}
func TestSumMirrorLines3(t *testing.T) {
lines := []string{
"#.##..##.",
"..#.##.#.",
"##......#",
"##......#",
"..#.##.#.",
"..##..##.",
"#.#.##.#.",
"",
"#...##..#",
"#....#..#",
"..##..###",
"#####.##.",
"#####.##.",
"..##..###",
"#....#..#",
"",
}
result := SumMirrorLines3(lines, 0)
if result != 405 {
t.Fatalf("expected 405, got %v", result)
}
}
func TestSumMirrorLines3WithInput1(t *testing.T) {
lines := utils.ReadLines("input.txt")
result := SumMirrorLines3(lines, 0)
if result != 43614 {
t.Fatalf("expected 43614 %v", result)
}
}
func TestSumMirrorLines3WithSmudge(t *testing.T) {
lines := []string{
"#.##..##.",
"..#.##.#.",
"##......#",
"##......#",
"..#.##.#.",
"..##..##.",
"#.#.##.#.",
"",
"#...##..#",
"#....#..#",
"..##..###",
"#####.##.",
"#####.##.",
"..##..###",
"#....#..#",
"",
}
result := SumMirrorLines3(lines, 1)
if result != 400 {
t.Fatalf("expected 400, got %v", result)
}
}
func TestSumMirrorLines3WithSmudgeWithInput1(t *testing.T) {
lines := utils.ReadLines("input.txt")
result := SumMirrorLines3(lines, 1)
if result != 36771 {
t.Fatalf("expected 36771 %v", result)
}
}

File diff suppressed because it is too large Load Diff

@ -84,6 +84,10 @@ func Int64Pow(x int64, y int64) int64 {
return result return result
} }
func Pow2(x int) int {
return 1 << x
}
// greatest common divisor (GCD) via Euclidean algorithm // greatest common divisor (GCD) via Euclidean algorithm
func GCD(a, b int) int { func GCD(a, b int) int {
for b != 0 { for b != 0 {
@ -133,3 +137,18 @@ func SplitNoBlank(s string, sep string) []string {
return result return result
} }
func Transpose[T any](slice [][]T) [][]T {
xl := len(slice[0])
yl := len(slice)
result := make([][]T, xl)
for i := range result {
result[i] = make([]T, yl)
}
for i := 0; i < xl; i++ {
for j := 0; j < yl; j++ {
result[i][j] = slice[j][i]
}
}
return result
}

Loading…
Cancel
Save