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)) }