aoc2024/day-17/internal/two/computer.go

115 lines
2.4 KiB
Go

package two
import (
"math"
)
type computer struct {
registers map[string]int64
instructionMap map[int64]instructionFn
}
func newComputer(registers map[string]int64) *computer {
c := &computer{
registers: registers,
}
c.instructionMap = map[int64]instructionFn{
0: c.adv,
1: c.bxl,
2: c.bst,
3: c.jnz,
4: c.bxc,
5: c.out,
6: c.bdv,
7: c.cdv,
}
return c
}
func (c *computer) bumpRegisters(next int64) {
c.registers["A"] = next
c.registers["B"] = 0
c.registers["C"] = 0
}
func (c *computer) run(program []int64) []int64 {
results := []int64{}
var ptr int
for ptr < len(program) {
opcode := program[ptr]
jump, doJump, out, doStore := c.performOperation(c.instructionMap[opcode], operand(program[ptr+1]))
if doJump {
ptr = jump
} else {
ptr += 2
}
if doStore {
results = append(results, out)
}
}
return results
}
func (c *computer) performOperation(fn instructionFn, operand operand) (int, bool, int64, bool) {
return fn(operand)
}
func (c *computer) adv(operand operand) (int, bool, int64, bool) {
c.registers["A"] /= int64(math.Pow(2, float64(c.combo(operand))))
return 0, false, 0, false
}
func (c *computer) bxl(operand operand) (int, bool, int64, bool) {
c.registers["B"] ^= int64(operand)
return 0, false, 0, false
}
func (c *computer) bst(operand operand) (int, bool, int64, bool) {
c.registers["B"] = c.combo(operand) % 8
return 0, false, 0, false
}
func (c *computer) jnz(operand operand) (int, bool, int64, bool) {
if c.registers["A"] == 0 {
return 0, false, 0, false
}
return int(operand), true, 0, false
}
func (c *computer) bxc(operand operand) (int, bool, int64, bool) {
c.registers["B"] ^= c.registers["C"]
return 0, false, 0, false
}
func (c *computer) out(operand operand) (int, bool, int64, bool) {
return 0, false, c.combo(operand) % 8, true
}
func (c *computer) bdv(operand operand) (int, bool, int64, bool) {
c.registers["B"] = c.registers["A"] / int64(math.Pow(2, float64(c.combo(operand))))
return 0, false, 0, false
}
func (c *computer) cdv(operand operand) (int, bool, int64, bool) {
c.registers["C"] = c.registers["A"] / int64(math.Pow(2, float64(c.combo(operand))))
return 0, false, 0, false
}
func (c *computer) combo(operand operand) int64 {
switch operand {
case 0, 1, 2, 3:
return int64(operand)
case 4:
return int64(c.registers["A"])
case 5:
return int64(c.registers["B"])
case 6:
return int64(c.registers["C"])
default:
return 0
}
}