code.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. package main
  2. import (
  3. "bufio"
  4. "fmt"
  5. "log"
  6. "os"
  7. "slices"
  8. "strconv"
  9. "strings"
  10. )
  11. const (
  12. AND = iota
  13. OR
  14. XOR
  15. )
  16. type Gate struct {
  17. id string
  18. left, right string
  19. op int
  20. value int
  21. }
  22. func readInput(file *os.File) (map[string]Gate, map[string]Gate) {
  23. scanner := bufio.NewScanner(file)
  24. zs := make(map[string]Gate)
  25. gates := make(map[string]Gate)
  26. readingRegisters := true
  27. for scanner.Scan() {
  28. line := scanner.Text()
  29. if line == "" {
  30. if readingRegisters {
  31. readingRegisters = false
  32. continue
  33. }
  34. break
  35. }
  36. var gate Gate
  37. if readingRegisters {
  38. parts := strings.Split(line, ": ")
  39. if len(parts) != 2 {
  40. log.Fatalf("Bad register line: %s", line)
  41. }
  42. gate.id = parts[0]
  43. n, err := fmt.Sscanf(parts[1], "%d", &gate.value)
  44. if n != 1 || err != nil {
  45. log.Fatalf("Bad input %s: %s", parts[1], err)
  46. }
  47. } else {
  48. var op string
  49. n, err := fmt.Sscanf(line, "%s %s %s -> %s", &gate.left, &op, &gate.right, &gate.id)
  50. if n != 4 || err != nil {
  51. log.Fatalf("Bad input %s: %s", line, err)
  52. }
  53. switch op {
  54. case "AND":
  55. gate.op = AND
  56. case "OR":
  57. gate.op = OR
  58. case "XOR":
  59. gate.op = XOR
  60. }
  61. gate.value = -1
  62. }
  63. if gate.id[0] == 'z' {
  64. zs[gate.id] = gate
  65. } else {
  66. gates[gate.id] = gate
  67. }
  68. }
  69. return gates, zs
  70. }
  71. func calculate(gate Gate, gates map[string]Gate) int {
  72. if gate.value != -1 {
  73. return gate.value
  74. }
  75. left := calculate(gates[gate.left], gates)
  76. right := calculate(gates[gate.right], gates)
  77. switch gate.op {
  78. case AND:
  79. gate.value = left & right
  80. case OR:
  81. gate.value = left | right
  82. case XOR:
  83. gate.value = left ^ right
  84. }
  85. return gate.value
  86. }
  87. func zsToNumber(zs map[string]Gate) int64 {
  88. arr := make([]byte, len(zs))
  89. keys := make([]string, len(zs))
  90. var index int
  91. for key, _ := range zs {
  92. keys[index] = key
  93. index++
  94. }
  95. slices.Sort(keys)
  96. slices.Reverse(keys)
  97. for i := range keys {
  98. value := zs[keys[i]].value
  99. switch value {
  100. case 0:
  101. arr[i] = '0'
  102. case 1:
  103. arr[i] = '1'
  104. }
  105. }
  106. result, err := strconv.ParseInt(string(arr), 2, 64)
  107. if err != nil {
  108. log.Fatalf("Can't convert binary %s: %s", arr, err)
  109. }
  110. return result
  111. }
  112. func calculateZs(zs, gates map[string]Gate) {
  113. for key, value := range zs {
  114. value.value = calculate(value, gates)
  115. zs[key] = value
  116. }
  117. }
  118. func main() {
  119. if len(os.Args) < 2 {
  120. log.Fatal("You need to specify a file!")
  121. }
  122. filePath := os.Args[1]
  123. file, err := os.Open(filePath)
  124. if err != nil {
  125. log.Fatalf("Failed to open %s!\n", filePath)
  126. }
  127. gates, zs := readInput(file)
  128. calculateZs(zs, gates)
  129. fmt.Println("Part1:", zsToNumber(zs))
  130. }