AOC Day 5 2021

This is part of a greater series about solving advent of code with spreadsheets.

Part One and Two

As always, read the problem text first. In summary, the input is a list of line segments made by two points. The goal is to count the number of points where at least two lines overlap.

The data uses some simplifications …

(0) My co-worker helped me identify this when I was overthinking part one. Arbitrary line segment intersection is hard.

(1) My challenge input is contained to (10, 10) and (989, 989).

Part one asks to count unique intersections of horizontal and vertical lines only. Part two removes that filter.

Solving Part One and Part Two

The solution makes a grid of numbers. This creates a picture like the author’s example2. Each cell is a single point. Lines of 1’s represent a single line segment. 2 or more’s represent intersections. 0 replaces “."’s to depict empty points.

.......1..
..1....1..
..1....1..
.......1..
.112111211
..........
..........
..........
..........
222111....
(2) This view made the goal very clear. Lines on-top of each other intersect at an infinite number of points. They intersect with integer x’s and y’s only a few times.

The line segments are parsed into the following columns.

X1 D2 ...
Y1 E2 ...
X2 F2 ...
Y2 G2 ...

These 5 columns classify the type of line.

HORIZONTAL H2 = E2=G2 repeat →
VERTICAL I2 = D2=F2 repeat →
SLOPE J2 = (G2 - E2)/(F2 - D2) repeat →
BL TR DIAG K2 = IFERROR(J2=1,FALSE) repeat →
TL BR DIAG L2 = IFERROR(J2=-1,FALSE) repeat →

These 5 columns will help figure out if a line exists at a point or not.

MIN X M2 = MIN(D2,F2) repeat →
MAX X N2 = MAX(D2,F2) repeat →
MIN Y O2 = MIN(E2,G2) repeat →
MAX Y P2 = MIN(E2,G2) repeat →
Y INTERCEPT Q2 = IFERROR(
E2 - D2 * J2,
"vertical")
repeat →

This table uses an x-offset defined by cell AA1. More on this later.

The cells of the map work like this. This includes the diagonal lines. To remove them for part one take away the last 2 terms of the sum.

AA1 AA2 = AA1 AA3 = AA2 + 1
0 AB2 =
COUNTIFS($H$2:$H,"=TRUE",
$M$2:$M,"<="&AB$1,
$N$2:$N,">="&AB$1,
$O$2:$O,"="&$AA2) +

COUNTIFS($I$2:$I,"=TRUE",
$M$2:$M,"="&AB$1,
$O$2:$O,"<="&$AA2,
$P$2:$P,">="&$AA2) +

COUNTIFS($K$2:$K,"=TRUE",
$M$2:$M,"<="&AB$1,
$N$2:$N,">="&AB$1,
$Q$2:$Q,"="&($AA2-AB$1)) +

COUNTIFS($L$2:$L,"=TRUE",
$M$2:$M,"<="&AB$1),
$N$2:$N,">="&AB$1),
$Q$2:$Q,"="&($AA2+AB$1))
repeat →

This cell counts the number of points where at least two lines intersect.

>=2 INTERSECTIONS R2 = COUNTIF(AB2:AL, ">=2")

How Part One and Part Two Works

There are two new concepts at work here.

IFERROR

Errors in spreadsheets are poison. If one cell errors most uses of it will also error. For example, this table is full of errors.

DATA A2 = 1/0 =>
#DIV/0!
USE1 B2 = A2 + 10 =>
#DIV/0!
USE2 C2 = A2=10 =>
#DIV/0!

IFERROR checks if the value is in error and returns a new value if so. This cleans out divide by 0’s from vertical line slopes.

Slices

The challenge had lines between (0,0) and (1000,1000). To recreate the author’s map each point requires a cell. This doesn’t scale well. The sheet would need 1,000,000 cells. When I tried a million cells the program froze.

Instead of all this, the sheet deals in “slices”. Each map cell is independent of other map cells and so it’s possible to “batch” maps3. I chose to deal in 50 columns by 1000 row slices. Each slice took about 20 seconds so I was through 20 of them in no time4.

(3) Batches are not perfect. I miscopied the result of one of them. It took hours (and writing a python solution) to figure this out.

(4) “No time” compared to day 4.

Unpacking COUNTIFS

There are four COUNTIFS in each cell of the map. Each of them …

Two of these are worth unpacking.

The first formula is for horizontal lines. It has four criteria.

(5) In these formulas & is shorthand for string concatenation.

The second formula is for diagonals with a slope of 1. It too uses four criteria.

You may be interested in the previous or next day's solution.