mirror of
https://github.com/Threnklyn/advent-of-code-go.git
synced 2026-05-19 03:23:27 +02:00
148 lines
3.6 KiB
Go
148 lines
3.6 KiB
Go
package main
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/alexchao26/advent-of-code-go/mathutil"
|
|
|
|
"github.com/alexchao26/advent-of-code-go/algos"
|
|
|
|
"github.com/alexchao26/advent-of-code-go/util"
|
|
)
|
|
|
|
func main() {
|
|
var part int
|
|
flag.IntVar(&part, "part", 1, "part 1 or 2")
|
|
flag.Parse()
|
|
fmt.Println("Running part", part)
|
|
|
|
var ans int
|
|
if part == 1 {
|
|
ans = fractalArt(util.ReadFile("./input.txt"), 5)
|
|
} else {
|
|
ans = fractalArt(util.ReadFile("./input.txt"), 18)
|
|
}
|
|
fmt.Println("Output:", ans)
|
|
}
|
|
|
|
var startingPattern = `.#.
|
|
..#
|
|
###`
|
|
|
|
func fractalArt(input string, rounds int) int {
|
|
var state [][]string
|
|
for _, line := range strings.Split(startingPattern, "\n") {
|
|
state = append(state, strings.Split(line, ""))
|
|
}
|
|
|
|
rules := parseInput(input)
|
|
|
|
for i := 0; i < rounds; i++ {
|
|
state = tick(state, rules)
|
|
}
|
|
|
|
var count int
|
|
for _, row := range state {
|
|
for _, v := range row {
|
|
if v == "#" {
|
|
count++
|
|
}
|
|
}
|
|
}
|
|
return count
|
|
}
|
|
|
|
func parseInput(input string) map[string][][]string {
|
|
// some helper functions for generating the rules map
|
|
// need to parse the left sides of the enhancement rules
|
|
// then helper functions that rotate them (util.RotateStringGrid()) and
|
|
// one to mirror image it
|
|
makeGridFromString := func(str string) [][]string {
|
|
var grid [][]string
|
|
for _, line := range strings.Split(str, "/") {
|
|
grid = append(grid, strings.Split(line, ""))
|
|
}
|
|
return grid
|
|
}
|
|
stringifyGrid := func(grid [][]string) (str string) {
|
|
for _, row := range grid {
|
|
for _, v := range row {
|
|
str += v
|
|
}
|
|
}
|
|
return str
|
|
}
|
|
mirrorImageGrid := func(grid [][]string) (flipped [][]string) {
|
|
for i := range grid {
|
|
flipped = append(flipped, []string{})
|
|
for j := len(grid[i]) - 1; j >= 0; j-- {
|
|
flipped[i] = append(flipped[i], grid[i][j])
|
|
}
|
|
}
|
|
return flipped
|
|
}
|
|
rules := map[string][][]string{}
|
|
for _, line := range strings.Split(input, "\n") {
|
|
parts := strings.Split(line, " => ")
|
|
keyGrid := makeGridFromString(parts[0])
|
|
resultGrid := makeGridFromString(parts[1])
|
|
|
|
for i := 0; i < 4; i++ {
|
|
keyGrid = algos.RotateStringGrid(keyGrid)
|
|
rules[stringifyGrid(keyGrid)] = resultGrid
|
|
rules[stringifyGrid((mirrorImageGrid(keyGrid)))] = resultGrid
|
|
}
|
|
}
|
|
return rules
|
|
}
|
|
|
|
func tick(grid [][]string, rules map[string][][]string) [][]string {
|
|
var nextState [][]string
|
|
|
|
// determine the size of break up the grid by. prioritize 2x2 grids
|
|
var edgeSize int
|
|
if len(grid)%2 == 0 {
|
|
edgeSize = 2
|
|
} else if len(grid)%3 == 0 {
|
|
edgeSize = 3
|
|
} else {
|
|
panic("grid is not evenly divisible by 2 or 3, got " + mathutil.IntToStr(len(grid)))
|
|
}
|
|
|
|
// iterate over like a sudoku grid, r and c iterate over the top left corner
|
|
// of each sub-square
|
|
for r := 0; r < len(grid); r += edgeSize {
|
|
// a new row of sub-squares is being iterated over, add edgeSize+1 number
|
|
// of empty slices onto the nextState grid
|
|
for i := 0; i < edgeSize+1; i++ {
|
|
nextState = append(nextState, []string{})
|
|
}
|
|
for c := 0; c < len(grid[0]); c += edgeSize {
|
|
// generate the string to match a key in the rules map
|
|
var strToMatch string
|
|
for i := 0; i < edgeSize; i++ {
|
|
for j := 0; j < edgeSize; j++ {
|
|
// r+i and c+j point at coords within the original grid
|
|
strToMatch += grid[r+i][c+j]
|
|
}
|
|
}
|
|
|
|
// finding the result of the enhancement rule for the string to match
|
|
resulting, ok := rules[strToMatch]
|
|
if !ok {
|
|
panic("No matching pattern found for " + strToMatch)
|
|
}
|
|
|
|
// append the values from the result onto the appropriate nextState row
|
|
for i, vals := range resulting {
|
|
nextStateIndex := len(nextState) - edgeSize - 1 + i
|
|
nextState[nextStateIndex] = append(nextState[nextStateIndex], vals...)
|
|
}
|
|
}
|
|
}
|
|
|
|
return nextState
|
|
}
|