mirror of
https://github.com/Threnklyn/advent-of-code-go.git
synced 2026-05-18 19:13:27 +02:00
2017-day21: sudoku-style grid plus game of life...
This commit is contained in:
@@ -0,0 +1,147 @@
|
||||
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
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/alexchao26/advent-of-code-go/util"
|
||||
)
|
||||
|
||||
var example = `../.# => ##./#../...
|
||||
.#./..#/### => #..#/..../..../#..#`
|
||||
|
||||
func Test_fractalArt(t *testing.T) {
|
||||
type args struct {
|
||||
input string
|
||||
rounds int
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want int
|
||||
}{
|
||||
{"example", args{example, 2}, 12},
|
||||
{"actual_part1", args{util.ReadFile("input.txt"), 5}, 194},
|
||||
{"actual_part2", args{util.ReadFile("input.txt"), 18}, 2536879},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := fractalArt(tt.args.input, tt.args.rounds); got != tt.want {
|
||||
t.Logf("Ruleset: %s", tt.args.input)
|
||||
t.Logf("Rounds: %d", tt.args.rounds)
|
||||
t.Errorf("fractalArt() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user