package main
import (
"fmt"
"io/ioutil"
"log"
"os"
"strconv"
"strings"
)
type OpType int
const (
OpAdd OpType = 1
OpMul = 2
OpEnd = 99
)
func ExecuteProgram(ops []int) ([]int, error) {
for i := 0; i < len(ops); i += 4 {
op := OpType(ops[i])
if op == OpEnd {
break
}
if i+3 >= len(ops) {
return nil, fmt.Errorf("broken input, could not index: %d", i+3)
}
a := ops[i+1]
b := ops[i+2]
out := ops[i+3]
if a >= len(ops) {
return nil, fmt.Errorf("attempt to index invalid out position: %d", a)
}
if b >= len(ops) {
return nil, fmt.Errorf("attempt to index invalid out position: %d", b)
}
if out >= len(ops) {
return nil, fmt.Errorf("attempt to index invalid out position: %d", out)
}
switch op {
case OpAdd:
ops[out] = ops[a] + ops[b]
case OpMul:
ops[out] = ops[a] * ops[b]
default:
return nil, fmt.Errorf("invalid op: %d", op)
}
}
return ops, nil
}
func Run(ops []int, noun, verb int) (int, error) {
cOps := make([]int, len(ops))
copy(cOps, ops)
cOps[1] = noun
cOps[2] = verb
result, err := ExecuteProgram(cOps)
if err != nil {
return 0, fmt.Errorf("could not execute program: %w", err)
}
return result[0], nil
}
func main() {
input, err := os.Open("input.txt")
if err != nil {
log.Fatal(fmt.Errorf("could not open input file: %w", err))
}
defer input.Close()
raw, err := ioutil.ReadAll(input)
if err != nil {
log.Fatal(fmt.Errorf("error while reading input: %w", err))
}
ops, err := func(val []byte) ([]int, error) {
vals := strings.Split(strings.TrimSpace(string(val)), ",")
result := make([]int, len(vals))
for i := range vals {
result[i], err = strconv.Atoi(vals[i])
if err != nil {
return nil, fmt.Errorf("could not convert to int: %w", err)
}
}
return result, nil
}(raw)
if err != nil {
log.Fatal(fmt.Errorf("could not read ops: %w", err))
}
// Part 1
result, err := Run(ops, 12, 2)
if err != nil {
log.Fatal(fmt.Errorf("could not run part 1: %w", err))
}
fmt.Printf("Part 1, %d\n", result)
// Part 2
for noun := 0; noun < 100; noun++ {
for verb := 0; verb < 100; verb++ {
result, err := Run(ops, noun, verb)
if err != nil {
log.Fatal(fmt.Errorf("could not run part 2: %w", err))
}
if result == 19690720 {
fmt.Printf("Part 2, %d\n", (noun*100)+verb)
return
}
}
}
}