diff --git a/16/16.go b/16/16.go new file mode 100644 index 0000000..f5c9478 --- /dev/null +++ b/16/16.go @@ -0,0 +1,141 @@ +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 +} \ No newline at end of file diff --git a/16/16_test.go b/16/16_test.go new file mode 100644 index 0000000..52f860b --- /dev/null +++ b/16/16_test.go @@ -0,0 +1,37 @@ +package main + +import ( + "testing" +) + +var test = []string{"s1", "x3/4", "pe/b"} + +func TestRun16(t *testing.T) { + i := ParseInstr(test) + input := "abcde" + v := Run16(input, i) + if v != "baedc" { + t.Error( + "For", test, + "expected baedc", + "got", v, + ) + } +} + +func TestRun1M(t *testing.T) { + i := ParseInstr(test) + input := "abcdefghijlmnop" + + for x :=0; x<10000000; x++ { + input = Run16(input, i) + } + + if input != "fghdijlmnopabce" { + t.Error( + "For", test, + "expected fghdijlmnopabce", + "got", input, + ) + } +} \ No newline at end of file