2017 Day 23 Complete

This commit is contained in:
Brian Buller 2017-12-23 09:01:32 -06:00
parent d16cc22158
commit 6c4e6ec824
8 changed files with 387 additions and 268 deletions

View File

@ -3,296 +3,108 @@ package main
import ( import (
"bufio" "bufio"
"fmt" "fmt"
"log"
"math" "math"
"os" "os"
"strings" "strings"
"time"
) )
var allRules []Rule var rules map[string]string
func main() { func main() {
rules = make(map[string]string)
inp := StdinToStrings() inp := StdinToStrings()
for i := range inp { for i := range inp {
allRules = append(allRules, Rule(inp[i])) pts := strings.Split(inp[i], " ")
} rules[pts[0]] = pts[2]
//pattern := Pattern(".#./..#/###") rules[Flip(pts[0])] = pts[2]
pattern := Pattern("../##") rules[Rotate(pts[0], 90)] = pts[2]
fmt.Println(pattern) rules[Rotate(pts[0], 180)] = pts[2]
if !pattern.IsValid() { rules[Rotate(pts[0], 270)] = pts[2]
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 pattern := ".#./..#/###"
func Stitch(inp []Pattern) Pattern { for i := 0; i < 2; i++ {
ppr := int(math.Sqrt(float64(len(inp)))) Tick(pattern)
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) /*
pattern = rules[pattern]
pts := SplitBlocks(pattern)
for i := range pts {
pts[i] = rules[pts[i]]
} }
} fmt.Println(pts)
var lines []string fmt.Println(CombineBlocks(pts))
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 { func Tick(pt string) string {
return strings.Count(string(p), "#") fmt.Println(SplitBlocks(pt))
}
// 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 ""
} }
return pts[row]
}
// GetCol returns a column as a string func SplitBlocks(pt string) []string {
func (p Pattern) GetCol(col int) string { var ret []string
var ret string pts := strings.Split(pt, "/")
pts := strings.Split(string(p), "/") if len(pts[0]) <= 3 {
if col >= len(pts[0]) { return []string{pt}
return "" }
// 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 {
ret = append(ret, pts[j][i:i+blkSize]+"/"+pts[j+1][i:i+blkSize])
} }
for i := 0; i < len(pts); i++ {
ret = ret + string(pts[i][col])
} }
return ret return ret
} }
// Counts the number of subpatterns in the pattern func CombineBlocks(pts []string) string {
func (p Pattern) SubpatternCount() int { var ret string
if p.Size()%2 == 0 { sz := int(math.Sqrt(float64(len(pts))))
return (p.Size() / 2) * (p.Size() / 2) fmt.Println("Combining")
} else { fmt.Println(sz)
return (p.Size() / 3) * (p.Size() / 3) //var j int
for i := 0; i < len(pts); i++ {
} }
return ret
} }
// Gets a specific subpattern out of the pattern func Flip(pt string) string {
func (p Pattern) GetSubpattern(i int) Pattern { pts := strings.Split(pt, "/")
if i > p.SubpatternCount() { var newPts []string
return Pattern("") for i := range pts {
newPts = append(newPts, RevString(pts[i]))
} }
subSize := 3 // Assume 3x3 subpatterns return strings.Join(newPts, "/")
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])
} }
/** func Rotate(pt string, deg int) string {
* Rule is an interface that can take a pattern and return if it matches, if deg == 0 {
* report on it's size, or return the resulting pattern from applying itself return pt
* to a pattern
*/
type RuleFace interface {
Matches(inp Pattern) bool
InputSize() int
Apply(inp Pattern) Pattern
} }
if deg%90 != 0 {
/** // We can't do this
* Rule implements the RuleFace interface fmt.Println("Invalid Rotation:", deg)
* for 2x2 => 3x3 transitions os.Exit(1)
* or 3x3 => 4x4 transitions
*/
type Rule string
func (r Rule) Input() Pattern {
pts := strings.Split(string(r), " ")
return Pattern(pts[0])
} }
pts := strings.Split(pt, "/")
func (r Rule) Output() Pattern { var tst string
pts := strings.Split(string(r), " ") if len(pts[0])%2 == 0 {
return Pattern(pts[2]) // 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
func (r Rule) Matches(inp Pattern) bool { tst = string(pts[2][0]) + string(pts[1][0]) + string(pts[0][0]) + "/"
if inp.Size() != r.InputSize() { tst += string(pts[2][1]) + string(pts[1][1]) + string(pts[0][1]) + "/"
return false tst += string(pts[2][2]) + string(pts[1][2]) + string(pts[0][2])
} return Rotate(tst, deg-90)
// 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 { func RevString(s string) string {
@ -303,10 +115,6 @@ func RevString(s string) string {
return string(runes) return string(runes)
} }
func ClearScreen() {
fmt.Println("\033[H\033[2J")
}
func StdinToStrings() []string { func StdinToStrings() []string {
var input []string var input []string
scanner := bufio.NewScanner(os.Stdin) scanner := bufio.NewScanner(os.Stdin)

3
2017/day23/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
day23-part2
day23-part1
test

116
2017/day23/day23-part1.go Normal file
View File

@ -0,0 +1,116 @@
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
inp := StdinToStrings()
run(inp)
}
var reg map[string]int
func run(inp []string) {
reg = make(map[string]int)
reg["a"] = 1
var mulCount int
var instCnt int
for i := 0; i >= 0 && i < len(inp); i++ {
instCnt++
if instCnt%10 == 0 {
ClearScreen()
printInstructions(inp, i)
}
pts := strings.Split(inp[i], " ")
if pts[1] == "h" || pts[2] == "h" {
fmt.Println("Hit h")
}
switch pts[0] {
case "set":
setReg(pts[1], pts[2])
case "sub":
subReg(pts[1], pts[2])
case "mul":
mulCount++
mulReg(pts[1], pts[2])
case "jnz":
i += jumpNotZero(pts[1], pts[2])
}
}
fmt.Println("Result (H):", reg["h"])
}
func setReg(key string, val string) {
reg[key] = getValue(val)
}
func subReg(key string, val string) {
reg[key] = getValue(key) - getValue(val)
}
func mulReg(key string, val string) {
reg[key] = getValue(key) * getValue(val)
}
func jumpNotZero(test string, jump string) int {
var ret int
if getValue(test) != 0 {
ret = getValue(jump) - 1
}
return ret
}
func getValue(key string) int {
var ret int
var ok bool
var err error
if ret, err = strconv.Atoi(key); err != nil {
// It's not a number
if ret, ok = reg[key]; !ok {
// The register is empty
reg[key] = 0
ret = 0
}
}
return ret
}
func PrintRegisters() {
fmt.Print("[ ")
for i := 0; i < 26; i++ {
getReg := string('a' + i)
fmt.Printf("%s:%d ", getReg, getValue(getReg))
}
fmt.Print("]\n")
}
func printInstructions(inp []string, pos int) {
PrintRegisters()
for i := range inp {
if i == pos {
fmt.Print("> ", inp[i], "\n")
} else {
fmt.Print(" ", inp[i], "\n")
}
}
}
func ClearScreen() {
fmt.Print("\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
}

54
2017/day23/day23-part2.go Normal file
View File

@ -0,0 +1,54 @@
package main
import (
"fmt"
"math"
)
func main() {
var a, b, c, d, e, f, g, h int
// Suppress go warnings
_, _, _, _, _, _, _, _ = a, b, c, d, e, f, g, h
// Derived from test.go
b = 109900
c = 126900
// Unoptimized:
/*
for ; b < c+1; b += 17 {
f = 1
for d = 2; d < b+1; d++ {
for e = 2; e < b+1; e++ {
if d*e == b {
f = 0
}
}
}
// When is f 0?
// when d*e == b for "certain values" of b
fmt.Println(d, e, b)
if f == 0 {
h++
}
// b = 109900
}
*/
// Optimized
for ; b < c+1; b += 17 {
if !IsPrime(b) {
h++
}
}
fmt.Println(h)
}
func IsPrime(value int) bool {
for i := 2; i <= int(math.Floor(float64(value)/2)); i++ {
if value%i == 0 {
return false
}
}
return value > 1
}

32
2017/day23/input Normal file
View File

@ -0,0 +1,32 @@
set b 99
set c b
jnz a 2
jnz 1 5
mul b 100
sub b -100000
set c b
sub c -17000
set f 1
set d 2
set e 2
set g d
mul g e
sub g b
jnz g 2
set f 0
sub e -1
set g e
sub g b
jnz g -8
sub d -1
set g d
sub g b
jnz g -13
jnz f 2
sub h -1
set g b
sub g c
jnz g 0
jnz 1 3
sub b -17
jnz 1 -23

View File

@ -0,0 +1,52 @@
b = 99
c = b
if a != 0 {
b = b * 100
b = b + 100000
c = b
c = c + 17000
}
// b = 109900
// c = 126900
for {
f = 1
d = 2
for {
e = 2
g = d
for {
g = g * e
g = g - b
if g == 0 {
f = 0
}
e = e + 1
g = e
g = g - b
if g != 0 {
break
}
}
d = d + 1
g = d
g = g - b
if g != 0 {
break
}
}
if f == 0 {
h = h + 1
}
g = b
g = g - c
if g == 0 {
break
}
b = b + 17
}

39
2017/day23/input-loops Normal file
View File

@ -0,0 +1,39 @@
set b 99
set c b
jnz a 2
jnz 1 5
mul b 100
sub b -100000
set c b
sub c -17000
set f 1
set d 2
set e 2
set g d
mul g e
sub g b
jnz g 2
set f 0
sub e -1
set g e
sub g b
jnz g -8
sub d -1
set g d
sub g b
jnz g -13
jnz f 2
sub h -1
set g b
sub g c
jnz g 0
jnz 1 3
sub b -17
jnz 1 -23

15
2017/day23/test.go Normal file
View File

@ -0,0 +1,15 @@
package main
import "fmt"
// Logic before any loops (starting values)
func main() {
var a, b, c int
b = 99
c = b
b = b * 100
b = b + 100000
c = b
c = c + 17000
fmt.Println(a, b, c)
}