134 lines
2.2 KiB
Go
134 lines
2.2 KiB
Go
|
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
|
||
|
}
|