adventofcode/2018/day21/day21.go

227 lines
4.1 KiB
Go

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
}