package main import ( "bufio" "fmt" "math" "os" "strconv" "strings" "time" ) const FILE_PATH = "./input.txt" //const FILE_PATH = "./sample.txt" func LoadInput(filename string) ([]string, error) { file, err := os.Open(filename) if err != nil { return nil, err } defer file.Close() var lines []string scanner := bufio.NewScanner(file) for scanner.Scan() { lines = append(lines, scanner.Text()) } if err := scanner.Err(); err != nil { return nil, err } return lines, nil } type ComputerParams struct { startA int startB int startC int program []int } type structuredInput = ComputerParams func TransformInput(lines []string) structuredInput { var startA int var startB int var startC int var numb int var numbs []string var program = make([]int, 0) startA, _ = strconv.Atoi(lines[0][len("Register A: "):]) startB, _ = strconv.Atoi(lines[1][len("Register B: "):]) startC, _ = strconv.Atoi(lines[2][len("Register C: "):]) numbs = strings.Split(lines[4][len("Program: "):], ",") for _, temp := range numbs { numb, _ = strconv.Atoi(temp) program = append(program, numb) } return ComputerParams{startA, startB, startC, program} } type Program struct { a int b int c int i int out []int } const ( ADV = iota BXL = iota BST = iota JNZ = iota BXC = iota OUT = iota BDV = iota CDV = iota ) func getCombo(program Program, operand int) int { if operand >= 0 && operand <= 3 { return operand } if operand == 4 { return program.a } if operand == 5 { return program.b } if operand == 6 { return program.c } return 0 } func executeProgram(params ComputerParams) Program { var program = Program{params.startA, params.startB, params.startC, 0, make([]int, 0)} var opcode int var operand int var value int for program.i < len(params.program) { opcode = params.program[program.i] operand = params.program[program.i+1] switch opcode { case ADV: { value = getCombo(program, operand) program.a = int(float64(program.a) / math.Pow(2, float64(value))) program.i += 2 } case BXL: { program.b = program.b ^ operand program.i += 2 } case BST: { value = getCombo(program, operand) program.b = value % 8 program.i += 2 } case JNZ: { if program.a != 0 { program.i = operand } else { program.i += 2 } } case BXC: { program.b = program.b ^ program.c program.i += 2 } case OUT: { program.out = append(program.out, getCombo(program, operand)%8) program.i += 2 } case BDV: { value = getCombo(program, operand) program.b = int(float64(program.a) / math.Pow(2, float64(value))) program.i += 2 } case CDV: { value = getCombo(program, operand) program.c = int(float64(program.a) / math.Pow(2, float64(value))) program.i += 2 } } } return program } func Part1(input structuredInput) int { var result int = 0 input.startA = 265652340990877 var program = executeProgram(input) for i := 0; i < len(program.out); i++ { fmt.Printf("%d,", program.out[i]) } fmt.Println() return result } var numbs = [][]int{ []int{0, 0, 0}, []int{0, 0, 1}, []int{0, 1, 0}, []int{0, 1, 1}, []int{1, 0, 0}, []int{1, 0, 1}, []int{1, 1, 0}, []int{1, 1, 1}, } func clone(input []int) []int { var result = make([]int, len(input)) for i, numb := range input { result[i] = numb } return result } func insert(numbers []int, numb []int, position int) ([]int, bool) { var result = clone(numbers) for i := 0; i < len(numb); i++ { if position+i < 0 && numb[i] == 0 { continue } if numbers[position+i] != -1 && numbers[position+i] != numb[i] { return []int{}, true } result[position+i] = numb[i] } return result, false } func invs(is []int, should []int) []int { var result = []int{0, 0, 0} for i := 0; i < 3; i++ { if should[i] == 1 && is[i] == 0 || should[i] == 0 && is[i] == 1 { result[i] = 1 } } return result } func bToi(numbers []int) int { var result = 0 var pow = math.Pow(2, float64(len(numbers)-1)) for i := 0; i < len(numbers); i++ { result += numbers[i] * int(pow) pow = pow / 2 } return result } func Part2(input structuredInput) int { var result int = 0 var poss [][]int = make([][]int, 1) var next [][]int = make([][]int, 0) var number []int = make([]int, 3*16) var error bool var position int var temp []int var work []int for i := 0; i < len(number); i++ { number[i] = -1 } poss[0] = number for j := 15; j >= 0; j-- { next = make([][]int, 0) for i := 0; i < len(poss); i++ { work = poss[i] position = j * 3 for m := 0; m < len(numbs); m++ { temp, error = insert(work, numbs[m], position) if error { continue } temp, error = insert(temp, invs(numbs[m], numbs[input.program[len(input.program)-j-1]]), position-(7-m)) if error { continue } next = append(next, temp) } } poss = next } var lowest int = -1 var dec int for i := 0; i < len(poss); i++ { dec = bToi(poss[i]) if lowest == -1 || lowest > dec { lowest = dec } } result = lowest return result } func main() { var start time.Time var elapsed time.Duration = 0 input, err := LoadInput(FILE_PATH) if err != nil { fmt.Println("Error loading input:", err) return } structuredInput := TransformInput(input) fmt.Println("Structured Input:", structuredInput) start = time.Now() fmt.Println("Solution Part 1: ", Part1(structuredInput)) elapsed = time.Since(start) fmt.Printf("Part 1 took %s\n", elapsed) start = time.Now() fmt.Println("Solution Part 2: ", Part2(structuredInput)) elapsed = time.Since(start) fmt.Printf("Part 2 took %s\n", elapsed) }