115 lines
2.5 KiB
Go
115 lines
2.5 KiB
Go
|
|
package main
|
||
|
|
|
||
|
|
import (
|
||
|
|
"os"
|
||
|
|
"fmt"
|
||
|
|
"strings"
|
||
|
|
)
|
||
|
|
|
||
|
|
// data types
|
||
|
|
type Point struct {
|
||
|
|
x int16
|
||
|
|
y int16
|
||
|
|
}
|
||
|
|
|
||
|
|
type Antenna struct {
|
||
|
|
point Point
|
||
|
|
freq byte
|
||
|
|
}
|
||
|
|
|
||
|
|
// general util
|
||
|
|
func check(e error) {
|
||
|
|
if e != nil { panic(e) }
|
||
|
|
}
|
||
|
|
|
||
|
|
func (p Point) Mul(scalar int) Point {
|
||
|
|
return Point { x: p.x * int16(scalar), y: p.y * int16(scalar) }
|
||
|
|
}
|
||
|
|
|
||
|
|
func (p Point) Add(other Point) Point {
|
||
|
|
return Point { x: p.x + other.x, y: p.y + other.y }
|
||
|
|
}
|
||
|
|
|
||
|
|
func (p Point) Sub(other Point) Point {
|
||
|
|
return Point { x: p.x - other.x, y: p.y - other.y }
|
||
|
|
}
|
||
|
|
|
||
|
|
func contains(arr []Point, p Point) bool {
|
||
|
|
for _, elem := range arr {
|
||
|
|
if elem == p { return true }
|
||
|
|
}
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
|
||
|
|
func addNonDuplicate(arr []Point, p Point) []Point {
|
||
|
|
if contains(arr, p) { return arr
|
||
|
|
} else { return append(arr, p) }
|
||
|
|
}
|
||
|
|
|
||
|
|
func newAntennas(data string) []Antenna {
|
||
|
|
/* Reads the puzzle input, return a list of antenna structs.
|
||
|
|
*/
|
||
|
|
antennas := make([]Antenna, 0, 100)
|
||
|
|
|
||
|
|
for y, line := range strings.Split(data, "\n") {
|
||
|
|
for x, char := range []byte(line) {
|
||
|
|
if char != '.' {
|
||
|
|
antennas = append(antennas, Antenna{ point: Point{x: int16(x), y: int16(y)}, freq: char })
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return antennas
|
||
|
|
}
|
||
|
|
|
||
|
|
func antinodes(points [2]Point, n int) []Point {
|
||
|
|
/* len(antinodes(..., n)) == 2*n + 2 */
|
||
|
|
nodes := make([]Point, 2*n)
|
||
|
|
|
||
|
|
distance := points[0].Sub(points[1])
|
||
|
|
for i := 0; i < n; i++ {
|
||
|
|
nodes[i] = points[0].Add(distance.Mul(i + 1))
|
||
|
|
nodes[i + n] = points[1].Sub(distance.Mul(i + 1))
|
||
|
|
}
|
||
|
|
|
||
|
|
nodes = append(nodes, points[0])
|
||
|
|
nodes = append(nodes, points[1])
|
||
|
|
|
||
|
|
return nodes
|
||
|
|
}
|
||
|
|
|
||
|
|
// main loop
|
||
|
|
func main() {
|
||
|
|
|
||
|
|
// read in file
|
||
|
|
dat, err := os.ReadFile("data.txt")
|
||
|
|
check(err)
|
||
|
|
dat_str := strings.TrimSpace(string(dat))
|
||
|
|
|
||
|
|
lines := strings.Split(dat_str, "\n")
|
||
|
|
height, width := int16(len(lines)), int16(len(lines[0]))
|
||
|
|
antennas := newAntennas(dat_str)
|
||
|
|
|
||
|
|
pairs := make([][2]Point, 0)
|
||
|
|
for _, ant1 := range antennas {
|
||
|
|
for _, ant2 := range antennas {
|
||
|
|
if ant1.freq == ant2.freq && ant1.point != ant2.point {
|
||
|
|
pairs = append(pairs, [2]Point{ant1.point, ant2.point})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
nodes := make([]Point, 0, len(pairs) * 2)
|
||
|
|
for _, pair := range pairs {
|
||
|
|
ns := antinodes(pair, 100)
|
||
|
|
for _, n := range ns {
|
||
|
|
if n.x >= 0 && n.x < width && n.y >= 0 && n.y < height {
|
||
|
|
nodes = addNonDuplicate(nodes, n)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
fmt.Println(len(nodes))
|
||
|
|
}
|