2017 Day 23 Complete
This commit is contained in:
parent
d16cc22158
commit
6c4e6ec824
@ -3,296 +3,108 @@ package main
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"log"
|
||||
"math"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var allRules []Rule
|
||||
var rules map[string]string
|
||||
|
||||
func main() {
|
||||
rules = make(map[string]string)
|
||||
|
||||
inp := StdinToStrings()
|
||||
for i := range inp {
|
||||
allRules = append(allRules, Rule(inp[i]))
|
||||
pts := strings.Split(inp[i], " ")
|
||||
rules[pts[0]] = pts[2]
|
||||
rules[Flip(pts[0])] = pts[2]
|
||||
rules[Rotate(pts[0], 90)] = pts[2]
|
||||
rules[Rotate(pts[0], 180)] = pts[2]
|
||||
rules[Rotate(pts[0], 270)] = pts[2]
|
||||
}
|
||||
//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)
|
||||
pattern := ".#./..#/###"
|
||||
for i := 0; i < 2; i++ {
|
||||
Tick(pattern)
|
||||
}
|
||||
/*
|
||||
pattern = rules[pattern]
|
||||
pts := SplitBlocks(pattern)
|
||||
for i := range pts {
|
||||
pts[i] = rules[pts[i]]
|
||||
}
|
||||
}
|
||||
var lines []string
|
||||
for i := 0; i < newSize; i++ {
|
||||
lines = append(lines, rows[i])
|
||||
}
|
||||
|
||||
return Pattern(strings.Join(lines, "/"))
|
||||
fmt.Println(pts)
|
||||
fmt.Println(CombineBlocks(pts))
|
||||
*/
|
||||
}
|
||||
|
||||
// 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")
|
||||
}
|
||||
func Tick(pt string) string {
|
||||
fmt.Println(SplitBlocks(pt))
|
||||
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 {
|
||||
ret = append(ret, pts[j][i:i+blkSize]+"/"+pts[j+1][i:i+blkSize])
|
||||
}
|
||||
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)
|
||||
func CombineBlocks(pts []string) string {
|
||||
var ret string
|
||||
sz := int(math.Sqrt(float64(len(pts))))
|
||||
fmt.Println("Combining")
|
||||
fmt.Println(sz)
|
||||
//var j int
|
||||
for i := 0; i < len(pts); i++ {
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// Gets a specific subpattern out of the pattern
|
||||
func (p Pattern) GetSubpattern(i int) Pattern {
|
||||
if i > p.SubpatternCount() {
|
||||
return Pattern("")
|
||||
func Flip(pt string) string {
|
||||
pts := strings.Split(pt, "/")
|
||||
var newPts []string
|
||||
for i := range pts {
|
||||
newPts = append(newPts, RevString(pts[i]))
|
||||
}
|
||||
subSize := 3 // Assume 3x3 subpatterns
|
||||
if p.Size()%2 == 0 {
|
||||
// Subpatterns are actually 2x2
|
||||
subSize = 2
|
||||
return strings.Join(newPts, "/")
|
||||
}
|
||||
|
||||
func Rotate(pt string, deg int) string {
|
||||
if deg == 0 {
|
||||
return pt
|
||||
}
|
||||
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] + "/"
|
||||
if deg%90 != 0 {
|
||||
// We can't do this
|
||||
fmt.Println("Invalid Rotation:", deg)
|
||||
os.Exit(1)
|
||||
}
|
||||
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
|
||||
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)
|
||||
}
|
||||
// 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)
|
||||
// 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 {
|
||||
@ -303,10 +115,6 @@ func RevString(s string) string {
|
||||
return string(runes)
|
||||
}
|
||||
|
||||
func ClearScreen() {
|
||||
fmt.Println("\033[H\033[2J")
|
||||
}
|
||||
|
||||
func StdinToStrings() []string {
|
||||
var input []string
|
||||
scanner := bufio.NewScanner(os.Stdin)
|
||||
|
3
2017/day23/.gitignore
vendored
Normal file
3
2017/day23/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
day23-part2
|
||||
day23-part1
|
||||
test
|
116
2017/day23/day23-part1.go
Normal file
116
2017/day23/day23-part1.go
Normal 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
54
2017/day23/day23-part2.go
Normal 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
32
2017/day23/input
Normal 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
|
52
2017/day23/input-disassemble
Normal file
52
2017/day23/input-disassemble
Normal 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
39
2017/day23/input-loops
Normal 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
15
2017/day23/test.go
Normal 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)
|
||||
}
|
Loading…
Reference in New Issue
Block a user