adventofcode/2021/day24/main.go

221 lines
4.1 KiB
Go

package main
import (
"bufio"
"fmt"
"math"
"os"
"strconv"
"strings"
h "git.bullercodeworks.com/brian/adventofcode/helpers"
)
func main() {
fmt.Println("ALU")
if len(os.Args) < 2 {
fmt.Println("Must pass filename as argument")
os.Exit(1)
}
test(os.Args[1])
//part1(os.Args[1])
}
func test(fn string) {
fmt.Println("# Test")
num := "15"
alu := NewALU()
alu.ReadProgram(fn)
var done bool
for !done {
fmt.Println("Converting", num)
alu.BufferInput(strings.Split(num, ""))
alu.run()
if num == "0" {
done = true
}
num = decNum(num, len(num)-1)
}
}
func decNum(num string, idx int) string {
if idx < 0 {
return num
}
if len(num) < idx {
return num
}
if num[idx] == '0' && idx > 0 {
num = num[:idx] + "9" + num[idx+1:]
return decNum(num, idx-1)
}
num = num[:idx] + string(num[idx]-1) + num[idx+1:]
return num
}
func part1(fn string) {
fmt.Println("# Part 1")
var done bool
num := "99999999999999"
alu := NewALU()
alu.ReadProgram(fn)
for !done {
fmt.Println("Checking Model No.", num)
alu.BufferInput(strings.Split(num, ""))
alu.run()
if alu.registers["z"] == 0 {
fmt.Println("-> It's good.")
done = true
}
num = decModelNum(num, len(num)-1)
}
}
func decModelNum(num string, idx int) string {
if len(num) < idx {
return num
}
if num[idx] == '1' {
num = num[:idx] + "9" + num[idx+1:]
return decModelNum(num, idx-1)
}
num = num[:idx] + string(num[idx]-1) + num[idx+1:]
return num
}
const (
INPUT_MODE_USER = iota
INPUT_MODE_CHAN
)
type ALU struct {
program []string
registers map[string]int
ptr int
inputMode int
inputChan chan string
}
func NewALU() *ALU {
return &ALU{
registers: map[string]int{"w": 0, "x": 0, "y": 0, "z": 0},
ptr: 0,
inputChan: make(chan string, 14),
}
}
func (alu *ALU) BufferInput(inp []string) {
alu.inputMode = INPUT_MODE_CHAN
for i := range inp {
alu.inputChan <- inp[i]
}
}
func (alu *ALU) ReadProgram(fn string) error {
file, err := os.Open(fn)
if err != nil {
return err
}
defer file.Close()
var lines []string
scanner := bufio.NewScanner(file)
for scanner.Scan() {
lines = append(lines, scanner.Text())
}
alu.program = lines
return scanner.Err()
}
func (alu *ALU) printRegisters() {
fmt.Printf("Registers:\nw: %d\nx: %d\ny: %d\nz: %d\n", alu.registers["w"], alu.registers["x"], alu.registers["y"], alu.registers["z"])
}
func (alu *ALU) run() {
for alu.ptr = 0; alu.ptr < len(alu.program); alu.ptr++ {
pts := strings.Split(alu.program[alu.ptr], " ")
switch pts[0] {
case "inp":
alu.registers[pts[1]] = alu.inp()
case "add":
alu.registers[pts[1]] = alu.add(alu.value(pts[1]), alu.value(pts[2]))
case "mul":
alu.registers[pts[1]] = alu.mul(alu.value(pts[1]), alu.value(pts[2]))
case "div":
alu.registers[pts[1]] = alu.div(alu.value(pts[1]), alu.value(pts[2]))
case "mod":
alu.registers[pts[1]] = alu.mod(alu.value(pts[1]), alu.value(pts[2]))
case "eql":
alu.registers[pts[1]] = alu.eql(alu.value(pts[1]), alu.value(pts[2]))
}
}
}
func (alu *ALU) inp() int {
if alu.inputMode == INPUT_MODE_USER {
var inp string
var err error
var v int
for inp == "" || err != nil {
fmt.Println("Input value:")
reader := bufio.NewReader(os.Stdin)
inp, _ = reader.ReadString('\n')
inp = strings.TrimSpace(inp)
v, err = strconv.Atoi(inp)
if err != nil {
fmt.Println("Must be an integer.")
}
}
return v
} else if alu.inputMode == INPUT_MODE_CHAN {
v, err := strconv.Atoi(<-alu.inputChan)
if err == nil {
return v
}
}
return 0
}
func (alu *ALU) value(a string) int {
switch a {
case "w", "x", "y", "z":
return alu.registers[a]
default:
return h.Atoi(a)
}
}
func (alu *ALU) add(a, b int) int {
return a + b
}
func (alu *ALU) mul(a, b int) int {
return a * b
}
func (alu *ALU) div(a, b int) int {
if b == 0 {
return 0
}
aD, bD := float64(a), float64(b)
d := aD / bD
if d > 0 {
return int(math.Floor(d))
}
return int(math.Ceil(d))
}
func (alu *ALU) mod(a, b int) int {
if a < 0 || b <= 0 {
return 0
}
return a % b
}
func (alu *ALU) eql(a, b int) int {
if a == b {
return 1
}
return 0
}