From 0fc0c493871f519c24ef681800c3586ec8e300e4 Mon Sep 17 00:00:00 2001 From: onyx-and-iris Date: Thu, 14 Dec 2023 03:44:14 +0000 Subject: [PATCH] day-13 --- day-13/go.mod | 3 +++ day-13/image.go | 33 ++++++++++++++++++++++++ day-13/makefile | 10 ++++++++ day-13/one.go | 62 ++++++++++++++++++++++++++++++++++++++++++++++ day-13/one_test.go | 19 ++++++++++++++ day-13/solution.go | 21 ++++++++++++++++ day-13/two.go | 48 +++++++++++++++++++++++++++++++++++ day-13/util.go | 57 ++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 253 insertions(+) create mode 100644 day-13/go.mod create mode 100644 day-13/image.go create mode 100644 day-13/makefile create mode 100644 day-13/one.go create mode 100644 day-13/one_test.go create mode 100644 day-13/solution.go create mode 100644 day-13/two.go create mode 100644 day-13/util.go diff --git a/day-13/go.mod b/day-13/go.mod new file mode 100644 index 0000000..cf6e310 --- /dev/null +++ b/day-13/go.mod @@ -0,0 +1,3 @@ +module github.com/onyx-and-iris/aoc2023/day-13 + +go 1.21.5 diff --git a/day-13/image.go b/day-13/image.go new file mode 100644 index 0000000..aef4bf3 --- /dev/null +++ b/day-13/image.go @@ -0,0 +1,33 @@ +package main + +type imgs struct { + img []img +} + +func newImages() imgs { + return imgs{img: make([]img, 0)} +} + +type img struct { + raw []string +} + +func newImg() img { + return img{raw: make([]string, 0)} +} + +func (i img) transposed() []string { + transposed := []string{} + + for x := 0; x < len(i.raw[0]); x++ { + buf := "" + for j := len(i.raw) - 1; j >= 0; j-- { + buf += string(i.raw[j][x]) + } + transposed = append(transposed, buf) + } + + return transposed +} + +var images imgs diff --git a/day-13/makefile b/day-13/makefile new file mode 100644 index 0000000..680ef75 --- /dev/null +++ b/day-13/makefile @@ -0,0 +1,10 @@ +TEST="test.txt" +INPUT="input.txt" + +test: + cat $(TEST) | go run . + +run: + cat $(INPUT) | go run . + +all: test \ No newline at end of file diff --git a/day-13/one.go b/day-13/one.go new file mode 100644 index 0000000..1da0339 --- /dev/null +++ b/day-13/one.go @@ -0,0 +1,62 @@ +package main + +import ( + "strings" + + log "github.com/sirupsen/logrus" +) + +// findReflection returns the reflection point for an image +func findReflection(image []string) (int, bool) { + walkToEdge := func(lower, upper int) bool { + for lower >= 0 && upper < len(image) && strings.Compare(image[lower], image[upper]) == 0 { + lower-- + upper++ + } + lower++ + return (lower == 0 || upper == len(image)) + } + + for i := 0; i < len(image)-1; i++ { + if strings.Compare(image[i], image[i+1]) == 0 { + log.Debug("start point: ", image[i], " vs ", image[i+1]) + if walkToEdge(i, i+1) { + return i, true + } + } + } + return 0, false +} + +// horizontalReflection returns the reflection point of a horizontal mirror +func horizontalReflection(image img, fn func(image []string) (int, bool)) (int, bool) { + n, ok := fn(image.raw) + return n, ok +} + +// verticalReflection returns the reflection point of a vertical mirror +func verticalReflection(image img, fn func(image []string) (int, bool)) (int, bool) { + n, ok := fn(image.transposed()) + return n, ok +} + +// one returns a calculation based on reflection points for all images. +func one(lines []string) int { + parselines(lines) + + sum := 0 + for _, image := range images.img { + log.Debug("checking for horizontal reflection") + n, ok := horizontalReflection(image, findReflection) + if ok { + sum += 100 * (n + 1) + } + log.Debug("checking for vertical reflection") + n, ok = verticalReflection(image, findReflection) + if ok { + sum += (n + 1) + } + } + + return sum +} diff --git a/day-13/one_test.go b/day-13/one_test.go new file mode 100644 index 0000000..2c4bb40 --- /dev/null +++ b/day-13/one_test.go @@ -0,0 +1,19 @@ +package main + +import ( + "testing" + + "github.com/go-playground/assert" +) + +func TestCompare(t *testing.T) { + //t.Skip("skipping test") + + img := newImg() + img.raw = []string{"#.##", "..#.", "##.."} + expected := []string{"#.#", "#..", ".##", "..#"} + + t.Run("Should flip the image ninety degrees rightwards", func(t *testing.T) { + assert.Equal(t, expected, img.transposed()) + }) +} diff --git a/day-13/solution.go b/day-13/solution.go new file mode 100644 index 0000000..926f1d4 --- /dev/null +++ b/day-13/solution.go @@ -0,0 +1,21 @@ +package main + +import ( + "fmt" + + log "github.com/sirupsen/logrus" +) + +func init() { + log.SetLevel(log.InfoLevel) +} + +func main() { + lines := readlines() + + ans := one(lines) + fmt.Printf("solution one: %d\n", ans) + + ans = two(lines) + fmt.Printf("solution two: %d\n", ans) +} diff --git a/day-13/two.go b/day-13/two.go new file mode 100644 index 0000000..828280f --- /dev/null +++ b/day-13/two.go @@ -0,0 +1,48 @@ +package main + +import ( + log "github.com/sirupsen/logrus" +) + +// findReflectionWithDifference returns the reflection point for an image with one smudge +func findReflectionWithDifference(image []string) (int, bool) { + walkToEdge := func(lower, upper int) bool { + diffs := 0 + for lower >= 0 && upper < len(image) { + n := numDiffs(image[lower], image[upper]) + log.Debug(n, " difference(s) found at line ", lower) + diffs += n + lower-- + upper++ + } + lower++ + return diffs == 1 + } + + for i := 0; i < len(image)-1; i++ { + log.Debug("start point: ", image[i], " vs ", image[i+1]) + if walkToEdge(i, i+1) { + return i, true + } + } + return 0, false +} + +// two returns a calculation based on reflection points for all images with one smudge +func two(lines []string) int { + sum := 0 + for _, image := range images.img { + log.Debug("checking for horizontal reflection") + n, ok := horizontalReflection(image, findReflectionWithDifference) + if ok { + sum += 100 * (n + 1) + } + log.Debug("checking for vertical reflection") + n, ok = verticalReflection(image, findReflectionWithDifference) + if ok { + sum += (n + 1) + } + } + + return sum +} diff --git a/day-13/util.go b/day-13/util.go new file mode 100644 index 0000000..3a287c2 --- /dev/null +++ b/day-13/util.go @@ -0,0 +1,57 @@ +package main + +import ( + "bufio" + "log" + "os" +) + +// readlines reads lines from stdin. +// it returns them as an array of strings +func readlines() []string { + lines := []string{} + + scanner := bufio.NewScanner(os.Stdin) + for scanner.Scan() { + lines = append(lines, scanner.Text()) + } + + if err := scanner.Err(); err != nil { + log.Fatal(err) + } + + return lines +} + +// parselines stores each image into an images struct +func parselines(lines []string) { + addImage := func(i int) int { + image := newImg() + for ; i < len(lines); i++ { + if len(lines[i]) == 0 { + break + } + image.raw = append(image.raw, lines[i]) + } + images.img = append(images.img, image) + return i + } + + images = newImages() + + for i := 0; i < len(lines); i++ { + next := addImage(i) + i = next + } +} + +// numDiffs returns the number of difference between two strings +func numDiffs(a, b string) int { + diff := 0 + for i := range a { + if a[i] != b[i] { + diff++ + } + } + return diff +}