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 } }