aoc24/day8/main.go

123 lines
3.3 KiB
Go
Raw Normal View History

2024-12-08 08:02:38 +00:00
package main
import (
"fmt"
"git.mstar.dev/mstar/aoc24/util"
"git.mstar.dev/mstar/goutils/sliceutils"
)
type Vec struct {
X, Y int
}
type Sender struct {
Pos Vec
Type rune
}
// Vec from v to o
func (v Vec) Diff(o Vec) Vec {
return Vec{o.X - v.X, o.Y - v.Y}
}
func (v Vec) Add(o Vec) Vec {
return Vec{v.X + o.X, v.Y + o.Y}
}
func (v Vec) Invert() Vec {
return Vec{v.X * -1, v.Y * -1}
}
func getSendersFromLines(lines []string) (senderMap map[rune][]Sender) {
senderMap = map[rune][]Sender{}
for iy, line := range lines {
for ix, char := range line {
if char != '.' {
senderMap[char] = append(senderMap[char], Sender{Vec{ix, iy}, char})
}
}
}
return
}
func visualise(allSenders map[rune][]Sender, signals []Vec, size Vec) string {
area := [][]rune{}
for range size.Y {
axis := []rune{}
for range size.X {
axis = append(axis, '.')
}
area = append(area, axis)
}
for _, senders := range allSenders {
for _, sender := range senders {
area[sender.Pos.Y][sender.Pos.X] = sender.Type
}
}
for _, signal := range signals {
area[signal.Y][signal.X] = '#'
}
lines := sliceutils.Map(area, func(t []rune) string { return string(t) })
return sliceutils.Compact(lines, func(acc, next string) string { return acc + "\n" + next })
}
func posInBounds(pos, bounds Vec) bool {
return pos.X < bounds.X && pos.X >= 0 && pos.Y < bounds.Y && pos.Y >= 0
}
func generateSignalPositions2(sender1, sender2 Sender, size Vec) (positions []Vec) {
diff := sender1.Pos.Diff(sender2.Pos)
invertedDiff := diff.Invert()
positions = append(positions, sender1.Pos, sender2.Pos)
for nextPost := sender1.Pos.Add(diff); posInBounds(nextPost, size); nextPost = nextPost.Add(diff) {
positions = append(positions, nextPost)
}
for nextPost := sender1.Pos.Add(invertedDiff); posInBounds(nextPost, size); nextPost = nextPost.Add(invertedDiff) {
positions = append(positions, nextPost)
}
return
}
func main() {
inputLines := util.FileContentToNonEmptyLines(util.LoadFileFromArgs())
allSenders := getSendersFromLines(inputLines)
size := Vec{len(inputLines[0]), len(inputLines)}
signalPositions := []Vec{}
for _, senders := range allSenders {
passedSenders := []Sender{senders[0]}
for _, sender := range senders[1:] {
for _, checked := range passedSenders {
diff := sender.Pos.Diff(checked.Pos)
signalPositions = append(signalPositions, sender.Pos.Add(diff.Invert()))
signalPositions = append(signalPositions, checked.Pos.Add(diff))
}
passedSenders = append(passedSenders, sender)
}
}
signalPositions = sliceutils.Filter(signalPositions, func(t Vec) bool {
return t.X < size.X && t.X >= 0 && t.Y < size.Y && t.Y >= 0
})
signalPositions = sliceutils.RemoveDuplicate(signalPositions)
// fmt.Printf("Size: %v\n", size)
fmt.Printf("Task 1: %d\n", len(signalPositions))
signals2 := []Vec{}
for _, senders := range allSenders {
passedSenders := []Sender{senders[0]}
for _, sender := range senders[1:] {
for _, checked := range passedSenders {
signals2 = append(signals2, generateSignalPositions2(sender, checked, size)...)
}
passedSenders = append(passedSenders, sender)
}
}
signals2 = sliceutils.Filter(signals2, func(t Vec) bool {
return t.X < size.X && t.X >= 0 && t.Y < size.Y && t.Y >= 0
})
signals2 = sliceutils.RemoveDuplicate(signals2)
fmt.Printf("Task 2: %d\n", len(signals2))
}