package one import ( "math" ) type computer struct { registers map[string]int instructionMap map[int]instructionFn } func newComputer(registers map[string]int) *computer { c := &computer{ registers: registers, } c.instructionMap = map[int]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) run(program []int) []int { results := []int{} 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, int, bool) { return fn(operand) } func (c *computer) adv(operand operand) (int, bool, int, bool) { c.registers["A"] /= int(math.Pow(2, float64(c.combo(operand)))) return 0, false, 0, false } func (c *computer) bxl(operand operand) (int, bool, int, bool) { c.registers["B"] ^= int(operand) return 0, false, 0, false } func (c *computer) bst(operand operand) (int, bool, int, bool) { c.registers["B"] = c.combo(operand) % 8 return 0, false, 0, false } func (c *computer) jnz(operand operand) (int, bool, int, 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, int, bool) { c.registers["B"] ^= c.registers["C"] return 0, false, 0, false } func (c *computer) out(operand operand) (int, bool, int, bool) { return 0, false, c.combo(operand) % 8, true } func (c *computer) bdv(operand operand) (int, bool, int, bool) { c.registers["B"] = c.registers["A"] / int(math.Pow(2, float64(c.combo(operand)))) return 0, false, 0, false } func (c *computer) cdv(operand operand) (int, bool, int, bool) { c.registers["C"] = c.registers["A"] / int(math.Pow(2, float64(c.combo(operand)))) return 0, false, 0, false } func (c *computer) combo(operand operand) int { switch operand { case 0, 1, 2, 3: return int(operand) case 4: return c.registers["A"] case 5: return c.registers["B"] case 6: return c.registers["C"] default: return 0 } }