adventofcode/2024/day17/main2.bk

79 lines
1.7 KiB
Plaintext

package main
import (
"fmt"
"slices"
"strconv"
)
func main() {
fmt.Println(day17(1))
fmt.Println(day17(2))
}
func day17(part int) string {
a, b, c, program := parseRegisters()
if part == 1 {
// part 1: run program and return comma-separated output
return fmt.Sprintln(runProgram(a, b, c, program))
}
// part 2: find lowest value of register A that makes the program output itself
a = 0 // the initial value of register A doesnt matter here, so we can reset it
for pos := len(program) - 1; pos >= 0; pos-- {
a <<= 3 // shift left by 3 bits
for !slices.Equal(runProgram(a, b, c, program), program[pos:]) {
a++
}
}
return strconv.Itoa(a) // return a string since part 1 needs a string
}
func parseRegisters() (int, int, int, []int) {
return 33940147, 0, 0, []int{2, 4, 1, 5, 7, 5, 1, 6, 4, 2, 5, 5, 0, 3, 3, 0}
}
func runProgram(a, b, c int, program []int) []int {
out := make([]int, 0)
// for each isntruction pointer
for ip := 0; ip < len(program); ip += 2 {
opcode, operand := program[ip], program[ip+1]
// Process combo operand
value := operand
switch operand {
case 4:
value = a
case 5:
value = b
case 6:
value = c
}
// Execute instruction
switch opcode {
case 0: // adv - divide A by 2^value
a >>= value
case 1: // bxl - XOR B with literal
b ^= operand
case 2: // bst - set B to value mod 8
b = value % 8
case 3: // jnz - jump if A is not zero
if a != 0 {
ip = operand - 2
}
case 4: // bxc - XOR B with C
b ^= c
case 5: // out - output value mod 8
out = append(out, value%8)
case 6: // bdv - divide A by 2^value, store in B
b = a >> value
case 7: // cdv - divide A by 2^value, store in C
c = a >> value
}
}
return out
}