adventofcode/2020/day08/program.go

134 lines
2.2 KiB
Go
Raw Normal View History

2020-12-08 15:52:49 +00:00
package main
import (
"fmt"
"strings"
h "git.bullercodeworks.com/brian/adventofcode/helpers"
)
const (
NOP = iota
ACC
JMP
)
type Instruction struct {
OpCode int
Operand int
}
func CompileLine(inp string) Instruction {
var ret Instruction
pts := strings.Split(inp, " ")
switch pts[0] {
case "nop":
ret.OpCode = NOP
case "acc":
ret.OpCode = ACC
case "jmp":
ret.OpCode = JMP
}
ret.Operand = h.Atoi(pts[1])
return ret
}
type Program struct {
Pointer int
Accumulator int
Instructions []Instruction
Code []string
History map[int]int
BreakOnLoop bool
Verbose bool
}
func NewProgram(inp []string) *Program {
p := &Program{
Pointer: 0,
Accumulator: 0,
Code: inp,
History: make(map[int]int),
BreakOnLoop: true,
Verbose: true,
}
p.Compile()
return p
}
func (p *Program) Copy() *Program {
cp := Program{
Pointer: p.Pointer,
Accumulator: p.Accumulator,
Code: p.Code,
History: make(map[int]int),
BreakOnLoop: p.BreakOnLoop,
Verbose: p.Verbose,
}
for k, v := range p.History {
cp.History[k] = v
}
cp.Compile()
return &cp
}
func (p *Program) Compile() {
for k := range p.Code {
p.Instructions = append(p.Instructions, CompileLine(p.Code[k]))
}
}
func (p *Program) Run() int {
for p.Pointer < len(p.Instructions) {
if p.BreakOnLoop {
if _, ok := p.History[p.Pointer]; ok {
if p.Verbose {
fmt.Printf("Instruction %d repeated. Acc: %d\n", p.Pointer, p.Accumulator)
}
return 1
}
}
p.History[p.Pointer] = p.Accumulator
switch p.Instructions[p.Pointer].OpCode {
case NOP:
p.Pointer++
case ACC:
p.Accumulator = p.Accumulator + p.Instructions[p.Pointer].Operand
p.Pointer++
case JMP:
p.Pointer = p.Pointer + p.Instructions[p.Pointer].Operand
}
}
if p.Verbose {
fmt.Println("Done")
}
return 0
}
func (p *Program) CountOpCodes(tp ...int) int {
var ret int
for tpk := range tp {
for k := range p.Instructions {
if p.Instructions[k].OpCode == tp[tpk] {
ret++
}
}
}
return ret
}
func (p *Program) FindNthOp(n int, tp ...int) int {
for i := 0; i < len(p.Instructions); i++ {
for _, tpv := range tp {
if p.Instructions[i].OpCode == tpv {
n--
}
if n == 0 {
return i
}
}
}
return -1
}