From c1c4dcd7cf4cbb3d47a7c59bfc0ada6f2e09e276 Mon Sep 17 00:00:00 2001 From: Dreaded_X Date: Mon, 20 Dec 2021 19:16:06 +0100 Subject: [PATCH] 2021 - Day 20 --- 2021/20/go.mod | 9 +++ 2021/20/go.sum | 2 + 2021/20/main.go | 160 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 171 insertions(+) create mode 100644 2021/20/go.mod create mode 100644 2021/20/go.sum create mode 100644 2021/20/main.go diff --git a/2021/20/go.mod b/2021/20/go.mod new file mode 100644 index 0000000..7c70587 --- /dev/null +++ b/2021/20/go.mod @@ -0,0 +1,9 @@ +module AoC/2021/20 + +require AoC/2021/common v0.0.0 + +require github.com/joho/godotenv v1.4.0 // indirect + +replace AoC/2021/common v0.0.0 => ../common + +go 1.17 diff --git a/2021/20/go.sum b/2021/20/go.sum new file mode 100644 index 0000000..8c9f290 --- /dev/null +++ b/2021/20/go.sum @@ -0,0 +1,2 @@ +github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= +github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= diff --git a/2021/20/main.go b/2021/20/main.go new file mode 100644 index 0000000..b825ae1 --- /dev/null +++ b/2021/20/main.go @@ -0,0 +1,160 @@ +package main + +import ( + aoc "AoC/2021/common" + "bufio" + "fmt" +) + +type Vec struct { + x int + y int +} + +func (a Vec) Add(b Vec) Vec { + return Vec{a.x+b.x, a.y+b.y} +} + +type Image struct { + data map[Vec]bool + min Vec + max Vec +} + +func NewImage() Image { + var image Image + image.data = make(map[Vec]bool) + + return image +} + +func processInput(input *bufio.Scanner) (Image, string) { + image := NewImage() + + input.Scan() + algorithm := input.Text() + + input.Scan() + for y := 0; input.Scan(); y++ { + if y > image.max.y { + image.max.y = y + } + line := input.Text() + for x, c := range line { + if x > image.max.x { + image.max.x = x + } + + // Only store non-zero values + if c == '#' { + image.data[Vec{x,y}] = true + } + } + } + + return image, algorithm +} + +func (image *Image) Print() { + for y := image.min.y; y <= image.max.y; y++ { + for x := image.min.x; x <= image.max.x; x++ { + if image.Get(x, y, false) { + fmt.Print("#") + } else { + fmt.Print(".") + } + } + fmt.Print("\n") + } + fmt.Print("\n") +} + +func (image *Image) Get(x int, y int, outside bool) bool { + if x < image.min.x || x > image.max.x || y < image.min.y || y > image.max.y { + return outside + } + return image.data[Vec{x, y}] +} + +func (image *Image) Kernel(x int, y int, algorithm string, outside bool) bool { + index := 0 + for dy := -1; dy <= 1; dy++ { + for dx := -1; dx <= 1; dx++ { + index <<= 1 + if image.Get(x+dx, y+dy, outside) { + index += 1 + } + } + } + + if algorithm[index] == '#' { + return true + } + + return false +} + +func (image *Image) Enhance(algorithm string, outside bool) Image { + newImage := NewImage() + newImage.min = image.min.Add(Vec{-1, -1}) + newImage.max = image.max.Add(Vec{1, 1}) + + for y := newImage.min.y; y <= newImage.max.y; y++ { + for x := newImage.min.x; x <= newImage.max.x; x++ { + if image.Kernel(x, y, algorithm, outside) { + newImage.data[Vec{x,y}] = true + } + } + } + + return newImage +} + +func (image *Image) Count() int { + return len(image.data) +} + +func main() { + challenge := aoc.New(2021, 20) + + challenge.Test(`..#.#..#####.#.#.#.###.##.....###.##.#..###.####..#####..#....#..#..##..###..######.###...####..#..#####..##..#.#####...##.#.#..#.##..#.#......#.###.######.###.####...#.##.##..#..#..#####.....#.#....###..#.##......#.....#..#..#..##..#...##.######.####.####.#.#...#.......#..#.#.#...####.##.#......#..#...##.#.##..#...##.#.##..###.#......#.#.......#.#.#.####.###.##...#.....####.#..#..#.##.#....##..#.####....##...##..#...#......#.#.......#.......##..####..#...#.#.#...##..#.#..###..#####........#..####......#..# + +#..#. +#.... +##..# +..#.. +..###`, []int{35, 3351}) + + challenge.Solution(1, func (input *bufio.Scanner) int { + image, algorithm := processInput(input) + + round1 := image.Enhance(algorithm, false) + + alternate := false + if algorithm[0] == '#' { + alternate = true + } + + round2 := round1.Enhance(algorithm, alternate) + + return round2.Count() + }) + + // @NOTE This solution does not actually properly handle the algorithm[0] == '#' edge case + // Here we assume that the last char in the algorithm is '.' and therefore alternate betwee # and . outside + // However if the last char is # we keep # outside after the first round + // For my input this was not the case, but it is an oversight + challenge.Solution(2, func (input *bufio.Scanner) int { + image, algorithm := processInput(input) + + alternate := false + for round := 0; round < 50; round++ { + image = image.Enhance(algorithm, alternate) + if algorithm[0] == '#' { + alternate = !alternate + } + } + + return image.Count() + }) +}