question 8 (question 8B does not work but I am tired)

This commit is contained in:
didier committed 2024-12-09 15:14:29 -05:00
1 parent bea4f844a8
commit 8198014f66
6 files changed
+312 -4

No files matched your search

+9
View File
@@ -0,0 +1,9 @@
package main
const mockInput = "............\n........0...\n.....0......\n.......0....\n....0.......\n......A.....\n............\n............\n........A...\n.........A..\n............\n............"
const mockInput2 = `.....
.....
....d
.....
....d`
const realInput = "....................8.D.........Y...........c.....\n....f.............D......O...........Y............\n.......z..........7.N..........g..................\n..........h...........9g.7....................Y...\n.............8...............................c....\n...9..8...............L........D....O.....l.......\n..........f.9.......h.........................l...\n...z...B..........................................\n.................M.....C.....OR7.Y..g..........l..\n........................M.......N.................\n...............h..................TD....H.........\n......z......M........C8.......N.......m.T........\n......O.......................................A...\n...........a...........h..........................\n................B..................j..............\n..............v..f..........g.....................\n.......N..........s.M.........n..............Q....\n...............s.........j.......................A\n......................a......................T...b\n........s....v......H..c..............j..i....m...\n.......................a........2H.......m..V.....\n................n.B..........o.....H......2.......\n.....3.......s.B..............x......S..K.........\n.3.G..................J................V...l.x..T.\n....3.......................E..................V..\n3..........................E..........V...i.......\n...............v.......n.E...................2.i..\n..F.........r.e......n....E...........A..Q.....K..\n..z................................A....Q.........\n.................................b..Q...d.Sw......\n..G...0..e............v.......Z...j.....m...b.....\n..y.............0.a.............................K.\n.............Gp....Z.................4......S.....\n....oJ....G........e.........Z............b.X.....\nC........o.r........WL..1.......X........K.....d..\n..................Z1.....r...............F........\n............L.4................1.6..............tF\n...y...............L......1............26.t.......\n......e.k......y........I......x......d........t.R\n.......0.........k...............d.........tWR..x.\n..........q.....r......J..................F..P..w.\n..........................5..........XwW..........\n...........0....y.............J.............6p....\n..q...k.......................I.....4........SR...\n.........q..o.......P................W............\n.............q.IP..............................p..\n.....k...................w.............X.......f..\n.............P...............4..................p.\n.................I..........5.....................\n.C.................................5...6.........."
+299
View File
@@ -0,0 +1,299 @@
package main
import (
"fmt"
"math/big"
"strings"
)
type Map struct {
data []rune
width int
height int
}
type Point struct {
x, y int
}
func (p *Point) String() string {
return fmt.Sprintf("(%d, %d)", p.x, p.y)
}
func (p *Point) IsBetween(p1 *Point, p2 *Point) bool {
return isBetween(p.x, p1.x, p2.x) && isBetween(p.y, p1.y, p2.y)
}
// Returns true is a is between (x, y) disregarding
// x, y order ( (x,y) is considered an interval.
// The definition of between includes both ends
func isBetween(a int, x int, y int) bool {
if x > y {
return isBetween(a, y, x)
}
return x <= a && a <= y
}
func (p *Point) Dist(p2 *Point) *Vector {
return NewVecFromInt(p2.x-p.x, p2.y-p.y)
}
func NewVecFromInt(x, y int) *Vector {
return &Vector{big.NewRat(int64(x), 1), big.NewRat(int64(y), 1)}
}
type Vector struct {
x, y *big.Rat
}
func (v *Vector) String() string {
return fmt.Sprintf("(%s, %s)", v.x, v.y)
}
func (v *Vector) Time(n *big.Rat) *Vector {
return &Vector{new(big.Rat).Mul(v.x, n), new(big.Rat).Mul(v.y, n)}
}
func (v *Vector) Opp() *Vector {
return v.Time(big.NewRat(-1, 1))
}
func (v *Vector) Plus(vec2 *Vector) *Vector {
return &Vector{new(big.Rat).Add(v.x, vec2.x), new(big.Rat).Add(v.y, vec2.y)}
}
func (v *Vector) AsPoint() *Point {
if !v.x.IsInt() || !v.y.IsInt() {
panic("Not a point")
}
return &Point{int(v.x.Num().Int64()), int(v.y.Num().Int64())}
}
func BaryCenter(p1, p2 *Point) *Vector {
return &Vector{
big.NewRat(int64(p1.x+p2.x), 2),
big.NewRat(int64(p1.y+p2.y), 2),
}
}
func (m *Map) isInbound(point *Point) bool {
return point.x >= 0 && point.x < m.width && point.y >= 0 && point.y < m.width
}
func (m *Map) Get(point *Point) (rune, bool) {
if !m.isInbound(point) {
return 0, false
}
idx := point.x + m.width*point.y
return m.data[idx], true
}
func (m *Map) getByDataIndex(idx int) *Point {
x := idx % m.width
y := idx / m.width
return &Point{x, y}
}
func NewMap(input string) *Map {
if !strings.HasSuffix(input, "\n") {
input += "\n"
}
width := strings.Index(input, "\n")
height := strings.Count(input, "\n")
data := []rune(strings.ReplaceAll(input, "\n", ""))
return &Map{data, width, height}
}
func (m *Map) getAllAntennaFrequencies() <-chan rune {
ch := make(chan rune)
go func() {
dejaVu := make(map[rune]bool)
dejaVu['.'] = true
for _, r := range m.data {
if _, ok := dejaVu[r]; !ok {
dejaVu[r] = true
ch <- r
}
}
close(ch)
}()
return ch
}
func (m *Map) getAllAntennaOfFrequency(freq rune) []*Point {
ret := make([]*Point, 0)
for i, r := range m.data {
if r == freq {
ret = append(ret, m.getByDataIndex(i))
}
}
return ret
}
type AntennaPair struct {
antenna1 *Point
antenna2 *Point
freq rune
}
func (m *Map) getAllAntennaPairsOfFrequency(freq rune) <-chan *AntennaPair {
antennas := m.getAllAntennaOfFrequency(freq)
ch := make(chan *AntennaPair)
go func() {
for i := 0; i < len(antennas); i++ {
for j := i + 1; j < len(antennas); j++ {
ch <- &AntennaPair{antennas[i], antennas[j], freq}
}
}
close(ch)
}()
return ch
}
func (m *Map) getEquidistantAntinodeLocationsForFreq(freq rune) <-chan *Point {
ch := make(chan *Point)
go func() {
for p := range m.getAllAntennaPairsOfFrequency(freq) {
bc := BaryCenter(p.antenna1, p.antenna2)
dist := p.antenna1.Dist(p.antenna2).Time(big.NewRat(3, 2))
antiNode1 := bc.Plus(dist).AsPoint()
antiNode2 := bc.Plus(dist.Opp()).AsPoint()
if m.isInbound(antiNode1) {
ch <- antiNode1
}
if m.isInbound(antiNode2) {
ch <- antiNode2
}
}
close(ch)
}()
return ch
}
func (m *Map) generateInlinePoints(p *Point, stepX, stepY int, filter func(*Point) bool, ch chan<- *Point) {
for {
p = &Point{p.x + stepX, p.y + stepY}
if !m.isInbound(p) {
return
}
if filter(p) {
ch <- p
}
}
}
func (m *Map) getStep(p *AntennaPair) (int, int) {
dist := p.antenna1.Dist(p.antenna2)
if dist.x.Cmp(big.NewRat(0, 1)) == 0 {
return 0, 1
}
if dist.y.Cmp(big.NewRat(0, 1)) == 0 {
return 1, 0
}
step := new(big.Rat).Quo(dist.y, dist.x)
stepX := int(step.Denom().Int64())
stepY := int(step.Num().Int64())
if stepX < 0 {
stepX = -stepX
}
return stepX, stepY
}
func (m *Map) getCollinearAntinodeLocationsFreq(freq rune) <-chan *Point {
ch := make(chan *Point)
go func() {
for pair := range m.getAllAntennaPairsOfFrequency(freq) {
stepX, stepY := m.getStep(pair)
filter := func(p *Point) bool {
return !p.IsBetween(pair.antenna1, pair.antenna2)
}
m.generateInlinePoints(pair.antenna1, stepX, stepY, filter, ch)
m.generateInlinePoints(pair.antenna1, -stepX, -stepY, filter, ch)
}
close(ch)
}()
return ch
}
func dedupPoints(points <-chan *Point) <-chan *Point {
ch := make(chan *Point)
go func() {
m := make(map[int]map[int]bool)
for p := range points {
if _, ok := m[p.x]; ok {
if _, ok2 := m[p.x][p.y]; ok2 {
continue
}
m[p.x][p.y] = true
} else {
m[p.x] = make(map[int]bool)
m[p.x][p.y] = true
}
ch <- p
}
close(ch)
}()
return ch
}
func (m *Map) getAllEquidistantAntinodeLocations() <-chan *Point {
ch := make(chan *Point)
go func() {
for freq := range m.getAllAntennaFrequencies() {
for p := range m.getEquidistantAntinodeLocationsForFreq(freq) {
ch <- p
}
}
close(ch)
}()
return dedupPoints(ch)
}
func (m *Map) getAllCollinearAntinodeLocations() <-chan *Point {
ch := make(chan *Point)
go func() {
for freq := range m.getAllAntennaFrequencies() {
for p := range m.getCollinearAntinodeLocationsFreq(freq) {
ch <- p
}
}
close(ch)
}()
return dedupPoints(ch)
}
func question8A(input string) int {
i := 0
m := NewMap(input)
for _ = range m.getAllEquidistantAntinodeLocations() {
i++
}
return i
}
func question8B(input string) int {
i := 0
m := NewMap(input)
for _ = range m.getAllCollinearAntinodeLocations() {
//fmt.Println(">> ", p)
i++
}
return i
}
func main() {
fmt.Printf("The answer to question 8A is %d \n", question8A(realInput))
fmt.Printf("The answer to question 8B is %d \n", question8B(mockInput))
}