package main import ( "bufio" "fmt" "log" "os" "slices" "strconv" "strings" ) const ( AND = iota OR XOR ) type Gate struct { id string left, right string op int value int } func readInput(file *os.File) (map[string]Gate, map[string]Gate) { scanner := bufio.NewScanner(file) zs := make(map[string]Gate) gates := make(map[string]Gate) readingRegisters := true for scanner.Scan() { line := scanner.Text() if line == "" { if readingRegisters { readingRegisters = false continue } break } var gate Gate if readingRegisters { parts := strings.Split(line, ": ") if len(parts) != 2 { log.Fatalf("Bad register line: %s", line) } gate.id = parts[0] n, err := fmt.Sscanf(parts[1], "%d", &gate.value) if n != 1 || err != nil { log.Fatalf("Bad input %s: %s", parts[1], err) } } else { var op string n, err := fmt.Sscanf(line, "%s %s %s -> %s", &gate.left, &op, &gate.right, &gate.id) if n != 4 || err != nil { log.Fatalf("Bad input %s: %s", line, err) } switch op { case "AND": gate.op = AND case "OR": gate.op = OR case "XOR": gate.op = XOR } gate.value = -1 } if gate.id[0] == 'z' { zs[gate.id] = gate } else { gates[gate.id] = gate } } return gates, zs } func calculate(gate Gate, gates map[string]Gate) int { if gate.value != -1 { return gate.value } left := calculate(gates[gate.left], gates) right := calculate(gates[gate.right], gates) switch gate.op { case AND: gate.value = left & right case OR: gate.value = left | right case XOR: gate.value = left ^ right } return gate.value } func zsToNumber(zs map[string]Gate) int64 { arr := make([]byte, len(zs)) keys := make([]string, len(zs)) var index int for key, _ := range zs { keys[index] = key index++ } slices.Sort(keys) slices.Reverse(keys) for i := range keys { value := zs[keys[i]].value switch value { case 0: arr[i] = '0' case 1: arr[i] = '1' } } result, err := strconv.ParseInt(string(arr), 2, 64) if err != nil { log.Fatalf("Can't convert binary %s: %s", arr, err) } return result } func calculateZs(zs, gates map[string]Gate) { for key, value := range zs { value.value = calculate(value, gates) zs[key] = value } } func main() { if len(os.Args) < 2 { log.Fatal("You need to specify a file!") } filePath := os.Args[1] file, err := os.Open(filePath) if err != nil { log.Fatalf("Failed to open %s!\n", filePath) } gates, zs := readInput(file) calculateZs(zs, gates) fmt.Println("Part1:", zsToNumber(zs)) }