package main import ( "bufio" "fmt" "math" "os" "strings" "time" ) var rules map[string]string func main() { numIters := 18 rules = make(map[string]string) inp := StdinToStrings() for i := range inp { pts := strings.Split(inp[i], " ") rules[pts[0]] = pts[2] rules[Flip(pts[0])] = pts[2] rules[Rotate(pts[0], 90)] = pts[2] rules[Flip(Rotate(pts[0], 90))] = pts[2] rules[Rotate(pts[0], 180)] = pts[2] rules[Flip(Rotate(pts[0], 180))] = pts[2] rules[Rotate(pts[0], 270)] = pts[2] rules[Flip(Rotate(pts[0], 270))] = pts[2] } pattern := ".#./..#/###" PrettyPrint(pattern) for i := 0; i < numIters; i++ { ClearScreen() PrettyPrint(pattern) time.Sleep(time.Second / 2) pattern = Tick(pattern) } fmt.Println("Bits On", strings.Count(pattern, "#")) } func PrettyPrint(inp string) { for _, v := range strings.Split(inp, "/") { fmt.Println(v) } } func Tick(pt string) string { subPatterns := SplitBlocks(pt) var tickSubs []string for i := range subPatterns { tickSubs = append(tickSubs, ApplyRule(subPatterns[i])) } return CombineBlocks(tickSubs) } func ApplyRule(inp string) string { if v, ok := rules[inp]; ok { return v } // This is an error. fmt.Println("No rule for", inp) os.Exit(1) return "" } func SplitBlocks(pt string) []string { var ret []string pts := strings.Split(pt, "/") if len(pts[0]) <= 3 { return []string{pt} } // Assume 3x3 blkSize := 3 if len(pts[0])%2 == 0 { // 2x2 blocks blkSize = 2 } for j := 0; j < len(pts); j += blkSize { for i := 0; i < len(pts[j]); i += blkSize { if blkSize == 2 { ret = append(ret, pts[j][i:i+blkSize]+"/"+pts[j+1][i:i+blkSize]) } else { ret = append(ret, pts[j][i:i+blkSize]+"/"+pts[j+1][i:i+blkSize]+"/"+pts[j+2][i:i+blkSize]) } } } return ret } func CombineBlocks(pts []string) string { var ret []string if len(pts) == 1 { return pts[0] } var subPts [][]string for i := range pts { subPts = append(subPts, strings.Split(pts[i], "/")) } subPtSz := len(subPts[0]) ptSize := int(math.Sqrt(float64(len(subPts) * subPtSz * subPtSz))) w, h := (ptSize / subPtSz), (ptSize / subPtSz) for i := 0; i < h; i++ { st := i * w for j := 0; j < subPtSz; j++ { var bld string for k := 0; k < w; k++ { bld += subPts[st+k][j] } ret = append(ret, bld) } } return strings.Join(ret, "/") } func Flip(pt string) string { pts := strings.Split(pt, "/") var newPts []string for i := range pts { newPts = append(newPts, RevString(pts[i])) } return strings.Join(newPts, "/") } func Rotate(pt string, deg int) string { if deg == 0 { return pt } if deg%90 != 0 { // We can't do this fmt.Println("Invalid Rotation:", deg) os.Exit(1) } pts := strings.Split(pt, "/") var tst string if len(pts[0])%2 == 0 { // 2x2 pattern tst = string(pts[1][0]) + string(pts[0][0]) + "/" tst += string(pts[1][1]) + string(pts[0][1]) return Rotate(tst, deg-90) } // 3x3 pattern tst = string(pts[2][0]) + string(pts[1][0]) + string(pts[0][0]) + "/" tst += string(pts[2][1]) + string(pts[1][1]) + string(pts[0][1]) + "/" tst += string(pts[2][2]) + string(pts[1][2]) + string(pts[0][2]) return Rotate(tst, deg-90) } 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 }