package main import ( "bufio" "errors" "fmt" "log" "os" "strconv" "strings" ) func main() { input := stdinToStringSlice() part1(input) } func part1(input []string) { vpc := NewState() if strings.HasPrefix(input[0], "#ip") { // Binding the ip to a register... pts := strings.Split(input[0], " ") vpc.ipReg = Atoi(pts[1]) input = input[1:] } // vpc.reg[0] = 7967233 // Part 1 loop := make(map[int]bool) var prev int for { if vpc.ip >= len(input) { break } inp := input[vpc.ip] if op, cmd, err := vpc.parseCommand(inp); err == nil { if vpc.ipReg > -1 { vpc.reg[vpc.ipReg] = vpc.ip } vpc.run(op, cmd) if vpc.ip == 28 { if _, ok := loop[vpc.reg[3]]; ok { fmt.Println(prev) break } loop[vpc.reg[3]] = true prev = vpc.reg[3] } vpc.ip = vpc.reg[vpc.ipReg] } vpc.ip++ } fmt.Println(vpc.string()) } type State struct { ip, ipReg int reg [6]int OpCodes map[string]func(a, b, c int) } func NewState() *State { s := &State{ ip: 0, ipReg: -1, } s.OpCodes = make(map[string]func(a, b, c int)) s.OpCodes["addr"] = s.addr s.OpCodes["addi"] = s.addi s.OpCodes["mulr"] = s.mulr s.OpCodes["muli"] = s.muli s.OpCodes["banr"] = s.banr s.OpCodes["bani"] = s.bani s.OpCodes["borr"] = s.borr s.OpCodes["bori"] = s.bori s.OpCodes["setr"] = s.setr s.OpCodes["seti"] = s.seti s.OpCodes["gtir"] = s.gtir s.OpCodes["gtri"] = s.gtri s.OpCodes["gtrr"] = s.gtrr s.OpCodes["eqir"] = s.eqir s.OpCodes["eqri"] = s.eqri s.OpCodes["eqrr"] = s.eqrr return s } func (s *State) parseCommand(inp string) (string, []int, error) { var retOp string var retCmd []int pts := strings.Split(inp, " ") if len(pts) != 4 { return retOp, retCmd, errors.New("Invalid Command") } retOp = pts[0] for _, v := range pts[1:] { retCmd = append(retCmd, Atoi(v)) } return retOp, retCmd, nil } func (s *State) string() string { ret := fmt.Sprintf("ip=%d ", s.ip) for i := 0; i < len(s.reg); i++ { if i == s.ipReg { ret = fmt.Sprintf("%s <%d> ", ret, s.reg[i]) } else { ret = fmt.Sprintf("%s %d ", ret, s.reg[i]) } } return ret } func (s *State) run(op string, cmd []int) error { if fn, ok := s.OpCodes[op]; !ok { return errors.New(fmt.Sprintf("Invalid OpCode: %d", cmd[0])) } else { fn(cmd[0], cmd[1], cmd[2]) } return nil } func (s *State) addr(r1, r2, r3 int) { s.reg[r3] = s.reg[r1] + s.reg[r2] } func (s *State) addi(r1, v2, r3 int) { s.reg[r3] = s.reg[r1] + v2 } func (s *State) mulr(r1, r2, r3 int) { s.reg[r3] = s.reg[r1] * s.reg[r2] } func (s *State) muli(r1, v2, r3 int) { s.reg[r3] = s.reg[r1] * v2 } func (s *State) banr(r1, r2, r3 int) { s.reg[r3] = s.reg[r1] & s.reg[r2] } func (s *State) bani(r1, v2, r3 int) { s.reg[r3] = s.reg[r1] & v2 } func (s *State) borr(r1, r2, r3 int) { s.reg[r3] = s.reg[r1] | s.reg[r2] } func (s *State) bori(r1, v2, r3 int) { s.reg[r3] = s.reg[r1] | v2 } func (s *State) setr(r1, r2, r3 int) { s.reg[r3] = s.reg[r1] } func (s *State) seti(v1, v2, r3 int) { s.reg[r3] = v1 } func (s *State) gtir(v1, r2, r3 int) { s.reg[r3] = boolToInt(v1 > s.reg[r2]) } func (s *State) gtri(r1, v2, r3 int) { s.reg[r3] = boolToInt(s.reg[r1] > v2) } func (s *State) gtrr(r1, r2, r3 int) { s.reg[r3] = boolToInt(s.reg[r1] > s.reg[r2]) } func (s *State) eqir(v1, r2, r3 int) { s.reg[r3] = boolToInt(v1 == s.reg[r2]) } func (s *State) eqri(r1, v2, r3 int) { s.reg[r3] = boolToInt(s.reg[r1] == v2) } func (s *State) eqrr(r1, r2, r3 int) { s.reg[r3] = boolToInt(s.reg[r1] == s.reg[r2]) } func boolToInt(v bool) int { if v { return 1 } return 0 } func getDivisors(n int) []int { ret := []int{n} for i := 1; i < (n / 2); i++ { if n%i == 0 { ret = append(ret, i) } } return ret } func sum(vals []int) int { var ret int for _, v := range vals { ret += v } return ret } func stdinToStringSlice() []string { var input []string scanner := bufio.NewScanner(os.Stdin) for scanner.Scan() { input = append(input, scanner.Text()) } return input } func Atoi(i string) int { var ret int var err error if ret, err = strconv.Atoi(i); err != nil { log.Fatal("Invalid Atoi: " + i) } return ret }