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 }