adventofcode2017/16/16.go
2017-12-16 14:05:04 +00:00

141 lines
No EOL
2.5 KiB
Go

package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
type instruction struct {
instr byte
arg1 int
arg2 int
n1 byte
n2 byte
}
// cat input | go run 16.go
func main() {
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
instr := ParseInstr(strings.Split(scanner.Text(), ","))
input := "abcdefghijklmnop"
seen := make(map[string]string)
fmt.Println(string(Run16(input, instr)))
rounds := 1000000000
for i := 1; i <= rounds; i++ {
if i % (rounds/10) == 0 {
fmt.Print("/")
} else if i % (rounds/100) == 0 {
fmt.Print(".")
}
// Cache known results. Suspect we could cache repeating patterns, but this is fast enough.
cache, exists := seen[input]
if exists {
input = cache
} else {
pre := input
input = Run16(input,instr)
seen[pre] = input
}
}
fmt.Println()
fmt.Println(input)
}
}
func Run16(i string, instr []instruction) string {
input := []byte(i)
//fmt.Println(i)
for i := range instr {
if instr[i].instr == 's' {
input = Spin(input, instr[i].arg1)
}
if instr[i].instr == 'x' {
input = SwapPos(input, instr[i].arg1, instr[i].arg2)
}
if instr[i].instr == 'p' {
input = SwapName(input, instr[i].n1, instr[i].n2)
}
}
return string(input)
}
func Spin(input []byte, pos int) []byte {
//fmt.Println("Spin", input, pos)
t := make([]byte, len(input))
p := 0
for i := len(input)-pos; i < len(input); i++ {
t[p] = input[i]
p++
}
for i := 0; i < len(input)-pos; i++ {
t[p] = input[i]
p++
}
return t
}
func SwapPos(ia []byte, a int, b int) []byte {
//fmt.Println("SwapPos", input, args)
ia[a],ia[b] = ia[b],ia[a]
return ia
}
func SwapName(ia []byte, s1 byte, s2 byte) []byte {
//fmt.Println("SwapName", ia, s1, s2)
a:= -1
b:= -1
for i := 0; i < len(ia); i++ {
if ia[i] == s1 {
a = i
}
if ia[i] == s2 {
b = i
}
if a != -1 && b != -1 {
break
}
}
ia[a],ia[b] = ia[b],ia[a]
return ia
}
func ParseInstr(l []string) []instruction {
var instructions []instruction
for i := range l {
var res = instruction{0, 0, 0, 0, 0}
res.instr = l[i][0]
if l[i][0] == 's' {
res.arg1,_ = strconv.Atoi( l[i][1:len(l[i])] )
}
if l[i][0] == 'x' {
s := strings.Split(l[i][1:len(l[i])], "/")
res.arg1,_ = strconv.Atoi(s[0])
res.arg2,_ = strconv.Atoi(s[1])
}
if l[i][0] == 'p' {
s := strings.Split(l[i][1:len(l[i])], "/")
res.n1 = s[0][0]
res.n2 = s[1][0]
}
instructions = append(instructions, res)
}
return instructions
}