main.go 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. package main
  2. import (
  3. "bufio"
  4. "errors"
  5. "fmt"
  6. "io"
  7. "log"
  8. "os"
  9. )
  10. func trim(s string) string {
  11. if len(s) > 0 && s[len(s)-1] == '\n' {
  12. return s[:len(s)-1]
  13. }
  14. return s
  15. }
  16. func main() {
  17. r := bufio.NewReader(os.Stdin)
  18. width := 0
  19. height := 0
  20. antennae := make(map[byte][]Coord)
  21. positions := make(map[Coord]struct{})
  22. line := make([]byte, 0, 4096)
  23. // Read map
  24. x, y := 0, 0
  25. for {
  26. b, err := r.ReadByte()
  27. if errors.Is(err, io.EOF) {
  28. break
  29. }
  30. if err != nil {
  31. log.Fatalf("While reading input: %v", err)
  32. }
  33. if b == '\n' {
  34. x = 0
  35. y++
  36. if width == 0 {
  37. width = len(line)
  38. }
  39. continue
  40. }
  41. if width == 0 {
  42. line = append(line, b)
  43. }
  44. switch {
  45. case b == '.':
  46. case '0' <= b || b <= '9' ||
  47. 'a' <= b || b <= 'z' ||
  48. 'A' <= b || b <= 'Z':
  49. if _, ok := antennae[b]; !ok {
  50. antennae[b] = make([]Coord, 0, 8)
  51. }
  52. coord := Coord{x, y}
  53. antennae[b] = append(antennae[b], coord)
  54. default:
  55. log.Fatalf("Unrecognized map input %q", b)
  56. }
  57. x++
  58. }
  59. height = y
  60. if x > 0 {
  61. height++
  62. }
  63. // Calculate antinodes
  64. for k, as := range antennae {
  65. if len(as) < 2 {
  66. continue
  67. }
  68. fmt.Fprintf(os.Stderr, "debug: frequency %q: %#v\n", k, as)
  69. is := [2]int{0, 1}
  70. for is[0]+is[1] <= 2*len(as)-3 {
  71. p1 := as[is[0]]
  72. p2 := as[is[1]]
  73. d := Coord{p1.X - p2.X, p1.Y - p2.Y}
  74. a1 := Coord{p1.X + d.X, p1.Y + d.Y}
  75. a2 := Coord{p2.X - d.X, p2.Y - d.Y}
  76. if inBounds(a1, 0, width-1, 0, height-1) {
  77. positions[a1] = struct{}{}
  78. }
  79. if inBounds(a2, 0, width-1, 0, height-1) {
  80. positions[a2] = struct{}{}
  81. }
  82. if is[1]+1 == len(as) {
  83. is[0]++
  84. is[1] = is[0] + 1
  85. continue
  86. }
  87. is[1]++
  88. }
  89. }
  90. fmt.Fprintf(os.Stderr, "positions: %#v\n", positions)
  91. fmt.Printf("%d\n", len(positions))
  92. }
  93. func inBounds(c Coord, x0, x1, y0, y1 int) bool {
  94. if x0 <= c.X && c.X <= x1 &&
  95. y0 <= c.Y && c.Y <= y1 {
  96. return true
  97. }
  98. return false
  99. }
  100. type Coord struct {
  101. X, Y int
  102. }
  103. func IndexOf(c Coord, width int) int {
  104. return c.X + c.Y*width
  105. }
  106. func CoordOf(idx, width int) Coord {
  107. if width == 0 {
  108. return Coord{idx, 0}
  109. }
  110. x := idx % width
  111. y := idx / width
  112. return Coord{x, y}
  113. }