I've gotta stop for now.
This commit is contained in:
317
2017/day21/day21.go
Normal file
317
2017/day21/day21.go
Normal file
@@ -0,0 +1,317 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"log"
|
||||
"math"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var allRules []Rule
|
||||
|
||||
func main() {
|
||||
inp := StdinToStrings()
|
||||
for i := range inp {
|
||||
allRules = append(allRules, Rule(inp[i]))
|
||||
}
|
||||
//pattern := Pattern(".#./..#/###")
|
||||
pattern := Pattern("../##")
|
||||
fmt.Println(pattern)
|
||||
if !pattern.IsValid() {
|
||||
fmt.Println("Invalid Pattern Given. Must be square.")
|
||||
}
|
||||
ClearScreen()
|
||||
pattern.PrettyPrint()
|
||||
time.Sleep(time.Second)
|
||||
for iters := 0; iters < 5; iters++ {
|
||||
ClearScreen()
|
||||
pattern = Tick(pattern)
|
||||
pattern.PrettyPrint()
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
fmt.Println("On:", pattern.GetOnCount())
|
||||
}
|
||||
|
||||
// Stitch takes a slice of patterns and turns them into one large (square) pattern
|
||||
func Stitch(inp []Pattern) Pattern {
|
||||
ppr := int(math.Sqrt(float64(len(inp))))
|
||||
newSize := ppr * inp[0].Size()
|
||||
var currRow int
|
||||
rows := make(map[int]string)
|
||||
for i := 0; i < len(inp); i++ {
|
||||
currRow = (i / ppr) * 2
|
||||
for j := 0; j < len(inp[0]); j++ {
|
||||
if len(rows[currRow+j]) == newSize {
|
||||
rows[currRow+j] += "/"
|
||||
}
|
||||
rows[currRow+j] += inp[i].GetRow(j)
|
||||
}
|
||||
}
|
||||
var lines []string
|
||||
for i := 0; i < newSize; i++ {
|
||||
lines = append(lines, rows[i])
|
||||
}
|
||||
|
||||
return Pattern(strings.Join(lines, "/"))
|
||||
}
|
||||
|
||||
// Run the pattern, or all of it's subpatterns
|
||||
// through the rules and return the new pattern
|
||||
func Tick(inp Pattern) Pattern {
|
||||
if inp.SubpatternCount() > 1 {
|
||||
var subs []Pattern
|
||||
// Tick each subpattern
|
||||
for i := 0; i < inp.SubpatternCount(); i++ {
|
||||
if s := inp.GetSubpattern(i); s.IsValid() {
|
||||
subs = append(subs, Tick(s))
|
||||
} else {
|
||||
log.Fatal("Error ticking pattern")
|
||||
}
|
||||
}
|
||||
return Stitch(subs)
|
||||
}
|
||||
|
||||
var foundMatch bool
|
||||
for i := range allRules {
|
||||
if allRules[i].Matches(inp) {
|
||||
inp = allRules[i].Output()
|
||||
foundMatch = true
|
||||
}
|
||||
}
|
||||
if !foundMatch {
|
||||
fmt.Println("~ ERROR TICKING ~")
|
||||
inp.PrettyPrint()
|
||||
fmt.Println("~ ERROR TICKING ~")
|
||||
os.Exit(1)
|
||||
}
|
||||
return inp
|
||||
}
|
||||
|
||||
/**
|
||||
* A pattern is a string with some special methods
|
||||
*/
|
||||
type Pattern string
|
||||
|
||||
// Print a pattern prettily. (in a square)
|
||||
func (p Pattern) PrettyPrint() {
|
||||
pts := strings.Split(string(p), "/")
|
||||
for i := range pts {
|
||||
fmt.Println(pts[i])
|
||||
}
|
||||
}
|
||||
|
||||
func (p Pattern) GetOnCount() int {
|
||||
return strings.Count(string(p), "#")
|
||||
}
|
||||
|
||||
// Returns if a pattern is valid.
|
||||
// A pattern is valid if it has more than 0 rows
|
||||
// and every row is the same length as the number
|
||||
// of columns
|
||||
func (p Pattern) IsValid() bool {
|
||||
pts := strings.Split(string(p), "/")
|
||||
if len(pts) == 0 {
|
||||
return false
|
||||
}
|
||||
for i := range pts {
|
||||
if len(pts[i]) != len(pts) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Returns the "size" of the pattern
|
||||
// That is, how many rows/columns it has
|
||||
func (p Pattern) Size() int {
|
||||
return len(strings.Split(string(p), "/"))
|
||||
}
|
||||
|
||||
// Flip returns a new pattern that has been flipped horizontally
|
||||
func (p Pattern) Flip() Pattern {
|
||||
// We can only flip the smallest patterns (2x2 or 3x3)
|
||||
if p.SubpatternCount() != 1 {
|
||||
return p
|
||||
}
|
||||
pts := strings.Split(string(p), "/")
|
||||
for i := range pts {
|
||||
pts[i] = RevString(pts[i])
|
||||
}
|
||||
return Pattern(strings.Join(pts, "/"))
|
||||
}
|
||||
|
||||
// Rotate returns a new pattern that has been rotated deg degrees
|
||||
// Only right-angles
|
||||
func (p Pattern) Rotate(deg int) Pattern {
|
||||
// We can only rotate the smallest patterns (2x2 or 3x3)
|
||||
if p.SubpatternCount() != 1 {
|
||||
return p
|
||||
}
|
||||
|
||||
if deg < 0 {
|
||||
deg += 360
|
||||
} else if deg == 0 {
|
||||
return p
|
||||
}
|
||||
|
||||
pts := strings.Split(string(p), "/")
|
||||
ret := make([]string, len(pts))
|
||||
use := p
|
||||
switch deg {
|
||||
case 90:
|
||||
if p.Size()%3 == 0 {
|
||||
ret[0] = RevString(use.GetCol(2))
|
||||
ret[1] = RevString(use.GetCol(1))
|
||||
ret[2] = RevString(use.GetCol(0))
|
||||
} else {
|
||||
ret[0] = RevString(use.GetCol(1))
|
||||
ret[1] = RevString(use.GetCol(0))
|
||||
}
|
||||
case 180:
|
||||
if p.Size()%3 == 0 {
|
||||
ret[0] = RevString(use.GetRow(2))
|
||||
ret[1] = RevString(use.GetRow(1))
|
||||
ret[2] = RevString(use.GetRow(0))
|
||||
} else {
|
||||
ret[0] = RevString(use.GetRow(1))
|
||||
ret[1] = RevString(use.GetRow(0))
|
||||
}
|
||||
case 270:
|
||||
if p.Size()%3 == 0 {
|
||||
ret[0] = use.GetCol(2)
|
||||
ret[1] = use.GetCol(1)
|
||||
ret[2] = use.GetCol(0)
|
||||
} else {
|
||||
ret[0] = use.GetCol(1)
|
||||
ret[1] = use.GetCol(0)
|
||||
}
|
||||
|
||||
}
|
||||
use = Pattern(strings.Join(ret, "/"))
|
||||
return Pattern(strings.Join(ret, "/"))
|
||||
}
|
||||
|
||||
// GetRow returns a row as a string
|
||||
func (p Pattern) GetRow(row int) string {
|
||||
pts := strings.Split(string(p), "/")
|
||||
if row >= len(pts) {
|
||||
return ""
|
||||
}
|
||||
return pts[row]
|
||||
}
|
||||
|
||||
// GetCol returns a column as a string
|
||||
func (p Pattern) GetCol(col int) string {
|
||||
var ret string
|
||||
pts := strings.Split(string(p), "/")
|
||||
if col >= len(pts[0]) {
|
||||
return ""
|
||||
}
|
||||
for i := 0; i < len(pts); i++ {
|
||||
ret = ret + string(pts[i][col])
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// Counts the number of subpatterns in the pattern
|
||||
func (p Pattern) SubpatternCount() int {
|
||||
if p.Size()%2 == 0 {
|
||||
return (p.Size() / 2) * (p.Size() / 2)
|
||||
} else {
|
||||
return (p.Size() / 3) * (p.Size() / 3)
|
||||
}
|
||||
}
|
||||
|
||||
// Gets a specific subpattern out of the pattern
|
||||
func (p Pattern) GetSubpattern(i int) Pattern {
|
||||
if i > p.SubpatternCount() {
|
||||
return Pattern("")
|
||||
}
|
||||
subSize := 3 // Assume 3x3 subpatterns
|
||||
if p.Size()%2 == 0 {
|
||||
// Subpatterns are actually 2x2
|
||||
subSize = 2
|
||||
}
|
||||
ppr := p.Size() / subSize
|
||||
col := i % (p.Size() / subSize)
|
||||
row := i / ppr
|
||||
ptString := ""
|
||||
for j := 0; j < subSize; j++ {
|
||||
ptString += p.GetRow((row * 2) + j)[(col*subSize):(col*subSize)+subSize] + "/"
|
||||
}
|
||||
return Pattern(ptString[:len(ptString)-1])
|
||||
}
|
||||
|
||||
/**
|
||||
* Rule is an interface that can take a pattern and return if it matches,
|
||||
* report on it's size, or return the resulting pattern from applying itself
|
||||
* to a pattern
|
||||
*/
|
||||
type RuleFace interface {
|
||||
Matches(inp Pattern) bool
|
||||
InputSize() int
|
||||
Apply(inp Pattern) Pattern
|
||||
}
|
||||
|
||||
/**
|
||||
* Rule implements the RuleFace interface
|
||||
* for 2x2 => 3x3 transitions
|
||||
* or 3x3 => 4x4 transitions
|
||||
*/
|
||||
type Rule string
|
||||
|
||||
func (r Rule) Input() Pattern {
|
||||
pts := strings.Split(string(r), " ")
|
||||
return Pattern(pts[0])
|
||||
}
|
||||
|
||||
func (r Rule) Output() Pattern {
|
||||
pts := strings.Split(string(r), " ")
|
||||
return Pattern(pts[2])
|
||||
}
|
||||
|
||||
func (r Rule) Matches(inp Pattern) bool {
|
||||
if inp.Size() != r.InputSize() {
|
||||
return false
|
||||
}
|
||||
// Try it rotated 90,180,270
|
||||
for i := 0; i < 360; i += 90 {
|
||||
if r.Equals(inp.Rotate(i)) || r.Equals(inp.Flip().Rotate(i)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (r Rule) InputSize() int {
|
||||
return len(strings.Split(string(r.Input()), "/"))
|
||||
}
|
||||
|
||||
// Equals is a direct string comparison
|
||||
func (r Rule) Equals(inp Pattern) bool {
|
||||
return string(r.Input()) == string(inp)
|
||||
}
|
||||
|
||||
func RevString(s string) string {
|
||||
runes := []rune(s)
|
||||
for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
|
||||
runes[i], runes[j] = runes[j], runes[i]
|
||||
}
|
||||
return string(runes)
|
||||
}
|
||||
|
||||
func ClearScreen() {
|
||||
fmt.Println("\033[H\033[2J")
|
||||
}
|
||||
|
||||
func StdinToStrings() []string {
|
||||
var input []string
|
||||
scanner := bufio.NewScanner(os.Stdin)
|
||||
for scanner.Scan() {
|
||||
input = append(input, scanner.Text())
|
||||
}
|
||||
return input
|
||||
}
|
108
2017/day21/input
Normal file
108
2017/day21/input
Normal file
@@ -0,0 +1,108 @@
|
||||
../.. => .../.../..#
|
||||
#./.. => #.#/..#/...
|
||||
##/.. => #.#/..#/#.#
|
||||
.#/#. => #../.../.##
|
||||
##/#. => ###/#.#/..#
|
||||
##/## => #.#/.../#..
|
||||
.../.../... => #..#/..../.##./....
|
||||
#../.../... => ..../.##./#.../.##.
|
||||
.#./.../... => .#../####/..##/#...
|
||||
##./.../... => ##.#/..#./####/...#
|
||||
#.#/.../... => ##.#/##../#.#./.#..
|
||||
###/.../... => #..#/#..#/##../##.#
|
||||
.#./#../... => #.##/##../.#.#/..##
|
||||
##./#../... => #.#./..../.###/.#.#
|
||||
..#/#../... => ..##/####/..##/....
|
||||
#.#/#../... => ..##/###./..##/#...
|
||||
.##/#../... => #.../####/#..#/##..
|
||||
###/#../... => ...#/..../..##/#...
|
||||
.../.#./... => ##../##../..##/....
|
||||
#../.#./... => #.../.#.#/.##./#..#
|
||||
.#./.#./... => ..##/#.../...#/###.
|
||||
##./.#./... => ####/.#.#/..##/####
|
||||
#.#/.#./... => ####/.#../#.##/#..#
|
||||
###/.#./... => ..#./#..#/.#.#/###.
|
||||
.#./##./... => ##../.#.#/#..#/#..#
|
||||
##./##./... => .###/####/#..#/..##
|
||||
..#/##./... => ###./.#../..#./#.##
|
||||
#.#/##./... => ##../#.#./#.../.#.#
|
||||
.##/##./... => #.../#.../.#.#/####
|
||||
###/##./... => .#../####/#.../#.#.
|
||||
.../#.#/... => .#../..../##../.###
|
||||
#../#.#/... => .##./...#/.###/...#
|
||||
.#./#.#/... => ...#/#.../...#/####
|
||||
##./#.#/... => #.##/..#./#..#/.#.#
|
||||
#.#/#.#/... => #..#/..../..##/..#.
|
||||
###/#.#/... => .#.#/#.#./##.#/#.#.
|
||||
.../###/... => ##../.##./###./###.
|
||||
#../###/... => ###./..##/.#../##.#
|
||||
.#./###/... => .#../##../..../..##
|
||||
##./###/... => #.#./...#/...#/##..
|
||||
#.#/###/... => ..../.#../#.../.#..
|
||||
###/###/... => ..#./.###/..../##.#
|
||||
..#/.../#.. => #.#./.#../...#/##.#
|
||||
#.#/.../#.. => ...#/##.#/#.#./#...
|
||||
.##/.../#.. => ...#/..##/#.##/##.#
|
||||
###/.../#.. => #..#/.#.#/.##./..#.
|
||||
.##/#../#.. => ##../..#./#.##/##..
|
||||
###/#../#.. => ..../###./#.#./##..
|
||||
..#/.#./#.. => #.#./.##./.##./#...
|
||||
#.#/.#./#.. => .#../#..#/#.#./#...
|
||||
.##/.#./#.. => .#.#/#..#/..#./....
|
||||
###/.#./#.. => #.##/####/#.../..#.
|
||||
.##/##./#.. => #.##/.#.#/..../.#..
|
||||
###/##./#.. => #.##/####/.###/##..
|
||||
#../..#/#.. => ###./#.##/..#./..##
|
||||
.#./..#/#.. => ##../.#../..#./..##
|
||||
##./..#/#.. => #..#/.#../..../##.#
|
||||
#.#/..#/#.. => .###/.##./..#./#.#.
|
||||
.##/..#/#.. => .#.#/..../####/.#..
|
||||
###/..#/#.. => .##./##../...#/.#..
|
||||
#../#.#/#.. => #.#./#.##/..../.###
|
||||
.#./#.#/#.. => ####/#.#./.#../#.##
|
||||
##./#.#/#.. => ..##/.###/###./..#.
|
||||
..#/#.#/#.. => .##./..#./..../#.#.
|
||||
#.#/#.#/#.. => .###/..../..../##..
|
||||
.##/#.#/#.. => #.#./#.../####/.###
|
||||
###/#.#/#.. => #.../..##/###./#..#
|
||||
#../.##/#.. => ..../#.#./..##/.#.#
|
||||
.#./.##/#.. => ..##/..##/#..#/###.
|
||||
##./.##/#.. => #.../.#../#.#./#.##
|
||||
#.#/.##/#.. => ...#/#.../...#/###.
|
||||
.##/.##/#.. => ###./..../..##/#..#
|
||||
###/.##/#.. => #.#./##.#/####/#.#.
|
||||
#../###/#.. => ##../##../###./#..#
|
||||
.#./###/#.. => #.##/###./####/..##
|
||||
##./###/#.. => ..../.###/###./.#..
|
||||
..#/###/#.. => .###/..../..#./....
|
||||
#.#/###/#.. => ####/#..#/.#.#/..##
|
||||
.##/###/#.. => ..../##.#/####/##.#
|
||||
###/###/#.. => #..#/.#.#/###./.##.
|
||||
.#./#.#/.#. => #.##/...#/###./....
|
||||
##./#.#/.#. => #..#/.#../..../#.#.
|
||||
#.#/#.#/.#. => .#.#/####/..../.#.#
|
||||
###/#.#/.#. => #.#./#.##/##.#/##..
|
||||
.#./###/.#. => ..#./..../##../####
|
||||
##./###/.#. => #.##/##.#/#.##/.#..
|
||||
#.#/###/.#. => .#.#/..##/##.#/####
|
||||
###/###/.#. => .#../...#/#..#/#.#.
|
||||
#.#/..#/##. => .##./..#./...#/##.#
|
||||
###/..#/##. => ..#./##.#/#..#/#..#
|
||||
.##/#.#/##. => ##.#/#.../#..#/...#
|
||||
###/#.#/##. => ##../.#../..../.##.
|
||||
#.#/.##/##. => #.##/##.#/.#../.###
|
||||
###/.##/##. => ..../#.#./##../##.#
|
||||
.##/###/##. => ###./.#.#/.##./.###
|
||||
###/###/##. => #..#/.###/#.../#...
|
||||
#.#/.../#.# => .###/#.##/.#.#/#.#.
|
||||
###/.../#.# => ...#/##../...#/##.#
|
||||
###/#../#.# => ..../..#./..#./####
|
||||
#.#/.#./#.# => ##../#.##/...#/#...
|
||||
###/.#./#.# => #.#./...#/.#../#...
|
||||
###/##./#.# => .#../..#./...#/##..
|
||||
#.#/#.#/#.# => ####/#.##/.#../##..
|
||||
###/#.#/#.# => #.../#.../###./.#..
|
||||
#.#/###/#.# => ####/.#.#/.##./.#.#
|
||||
###/###/#.# => #.##/.#.#/##.#/..##
|
||||
###/#.#/### => .###/#.##/..../..#.
|
||||
###/###/### => .###/#..#/##../.##.
|
2
2017/day21/testinput
Normal file
2
2017/day21/testinput
Normal file
@@ -0,0 +1,2 @@
|
||||
../.# => ##./#../...
|
||||
.#./..#/### => #..#/..../..../#..#
|
Reference in New Issue
Block a user