Home > Web Front-end > JS Tutorial > Resonant Collinearity

Resonant Collinearity

Barbara Streisand
Release: 2024-12-29 14:02:18
Original
988 people have browsed it

Resonant Collinearity

Advent of Code 2024 Day 8

Part 1

I think I get it. Can I do it?

As I understand it:

  • For each pair of identical ligatures
  • Find the point X where one ligature is 1N and the other is 2N - where N is some distance from X
  • As long as it is within the bounds of the grid, count it toward the answer

Here's a visual:

...........
...........
...X.......
...........
.....Y.....   <---1N from top X, 2N from bottom X
...........
.......Y...   <---2N from top X, 1N from bottom X
...........
.........X.
...........
Copy after login
Copy after login

It's clear visually.

How could I determine it algorithmically?

Calculating 1N and 2N algorithmically

Here's the example grid:

............
........0...
.....0......
.......0....
....0.......
......A.....
............
............
........A...
.........A..
............
............
Copy after login
Copy after login

I'll focus on the 0s:

  • There are four
  • Coordinates are: 1,8, 2,5, 3,7, 4,4

Comparing the first two:

1,8 vs. 2,5

1 row apart
3 col apart

2 possible antinodes:
0,11: 0 = min(1,2) - 1
3,2

For 0,11
0 = min(1,2) - 1
11 = ....
Copy after login
Copy after login

I realized while writing that I really need to know the slope of the line connecting the pair of points.

That way I can know whether to add or subtract from each axis to determine where the antinode is.

Refreshing my memory about slope

The formula is:

(y2 - y1) / (x2 - x1)
Copy after login
Copy after login

The outcome will be one of these four:

  • > 0 means positive slope: up and to the right
  • < 0 means negative slope: down and to the right
  • 0 means horizontal line
  • Infinity means vertical line

Returning to the example:

1,8 and 2,5

(5 - 8) / (2 - 1) = -3 / 1 = -3
Copy after login
Copy after login

What? A negative slope? No, that line has positive slope!

Oh...I see.

Array indexing counts up, but visually is moving down.

I need to count indices in reverse.

Instead of like this:

0 ............
1 ........0...
2 .....0......
3 .......0....
4 ....0.......
5 ......A.....
6 ............
7 ............
8 ........A...
9 .........A..
  ............
  ............
  0123456789
Copy after login
Copy after login

I need to count like this:

  ............
  ........0...
9 .....0......
8 .......0....
7 ....0.......
6 ......A.....
5 ............
4 ............
3 ........A...
2 .........A..
1 ............
0 ............
  0123456789
Copy after login
Copy after login

It should just require a bit more math:

array length - current row/col index
Copy after login

I'll try.

For the top-most 0:

12 rows
Row index: 1
12 - 1 = 11

Column index: 8

Coordinates: 8,11
Copy after login

For the 0 in the next row:

Row index: 2
12 - 2 = 10

Column index: 5

Coordinates: 5,10
Copy after login

And the slope:

(10 - 11) / (5 - 8)
   -1     /    -3
         1/3
Copy after login

A positive slope! That's correct!

Starting to code

Building the list of antenna coordinates

An empty object filled with a nested for loop:

let graph = input.split('\n').map(el => el.split(''))
let antennas = {}
for (let y = 0; y < graph.length; y++) {
  for (let x = 0; x < graph[0].length; x++) {
    if (graph[y][x] !== '.') {
      if (!(graph[y][x] in antennas)) {
        antennas[graph[y][x]] = []
      }
      antennas[graph[y][x]].push([graph.length - y,x])
    }
  }
}




<p>Creates this object for the example input:<br>
</p>

<pre class="brush:php;toolbar:false">{
  '0': [ [ 11, 8 ], [ 10, 5 ], [ 9, 7 ], [ 8, 4 ] ],
  A: [ [ 7, 6 ], [ 4, 8 ], [ 3, 9 ] ]
}
Copy after login

Looks great!

Next, calculating slope.

Writing an overly complex antinode-finder

My scope function is simple:

function getScope(p1,p2) {
  return (p2[0] - p1[0]) / (p2[1] - p1[1])
}
Copy after login

It expects two arrays and returns the scope using all four coordinates.

I'll want to call this function when comparing all pairs of similar-frequency coordinates.

That comparison happens in this super-nested for loop:

for (let freq in antennas) {
  let f = antennas[freq]
  for (let i = 0; i < f.length; i++) {
    for (let j = i + 1; j < f.length; j++) {
      // Comparing two antennas of the same frequency
    }
  }
}
Copy after login

Confirming it works on the example input:

[ 11, 8 ] [ 10, 5 ]
[ 11, 8 ] [ 9, 7 ]
[ 11, 8 ] [ 8, 4 ]
[ 10, 5 ] [ 9, 7 ]
[ 10, 5 ] [ 8, 4 ]
[ 9, 7 ] [ 8, 4 ]
[ 7, 6 ] [ 4, 8 ]
[ 7, 6 ] [ 3, 9 ]
[ 4, 8 ] [ 3, 9 ]
Copy after login

Nine comparisons. That's right!

And the scopes for each?

Those look right, too, thankfully.

Now for the overly complicated part, I think.

Handling all four slope types

They are:

...........
...........
...X.......
...........
.....Y.....   <---1N from top X, 2N from bottom X
...........
.......Y...   <---2N from top X, 1N from bottom X
...........
.........X.
...........
Copy after login
Copy after login

Let's handle this.

It's a lot, but the subtleties are important within each clause:

............
........0...
.....0......
.......0....
....0.......
......A.....
............
............
........A...
.........A..
............
............
Copy after login
Copy after login

Thankfully, all identified antinodes seem correctly placed.

Next, excluding ones that are out-of-bounds

Excluding the out-of-bounds antinodes

Enter...more conditions!

1,8 vs. 2,5

1 row apart
3 col apart

2 possible antinodes:
0,11: 0 = min(1,2) - 1
3,2

For 0,11
0 = min(1,2) - 1
11 = ....
Copy after login
Copy after login

I am checking for whether each coordinate is between 0 and the length of the rows or the columns.

Then, at the bottom of each clause in my antinode-finder, I call the function on both possible nodes:

(y2 - y1) / (x2 - x1)
Copy after login
Copy after login

And my answer will be the size of my valid set.

Does this actually work?

Running it generates 12. Not 14.

Why not?

...

After some debugging, I found my error:

1,8 and 2,5

(5 - 8) / (2 - 1) = -3 / 1 = -3
Copy after login
Copy after login

I'm off by one in my assignment of the row. I need a value that is one less:

0 ............
1 ........0...
2 .....0......
3 .......0....
4 ....0.......
5 ......A.....
6 ............
7 ............
8 ........A...
9 .........A..
  ............
  ............
  0123456789
Copy after login
Copy after login

That fixes things.

I see 14 now.

Time to run it on my puzzle input.

...

Correct answer!!!

That took a lot longer than I expected, but I did it!

I can only imagine what Part 2 will require.

Gulp.

Part 2

Yup. Lots more antinodes to identify.

This feels harder, though it may be a relatively simple adjustment.

Time to think on it.

...

Going in with low confidence of generating the correct answer

Mostly because of this gotcha:

exactly in line with at least two antennas of the same frequency

I think I understand this criteria.

My hunch is that at long as there are three of any given frequency, all three antennas are also antinodes.

If I'm wrong, then that's likely why my answer will be off: mistaking an antenna for an antinode.

But I think I have a strategy for identifying all the new antinodes.

Enter: more while loops to walk the lines

My current algorithm finds the antinodes on either end of two antennas.

I instead want to walk along the line in both directions until I am about to step out of bounds.

This will require some refactoring.

I'm ready.

Here's my updated condition for positive slope lines:

  ............
  ........0...
9 .....0......
8 .......0....
7 ....0.......
6 ......A.....
5 ............
4 ............
3 ........A...
2 .........A..
1 ............
0 ............
  0123456789
Copy after login
Copy after login

What changed:

  • I perform Math once up front
  • Inside the while loop I add the coordinate, then I just increment or decrement each coordinate by the corresponding diff
  • The condition uses my updated function which returns a boolean instead of adding the coordinate automatically

I had to do this for each clause.

I messed one up slightly, which caused me to get an off-by-1 answer using the example input, and to see a really weird grid, which helped me diagnose which clause was malfunctioning.

Eventually, I got it to work on the example input.

Then I ran it on my puzzle input.

And...

I generated the correct answer!!!

I'm so proud of myself!

And I'm so grateful that there was no sneaky edge case in my puzzle input!

Wow, that took several days of passive thinking to work through.

On to another day with two hard earned gold stars.

The above is the detailed content of Resonant Collinearity. For more information, please follow other related articles on the PHP Chinese website!

source:dev.to
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Latest Articles by Author
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template