This one was a little misleading, but that’s probably more due to me assuming too much going in than any tricky wording. My first thought was this would be a recursion puzzle because of the tree nature and there hadn’t been one yet; but I ended up not needing recursion to solve it. It probably would have been harder to get right if I had pursued that path.
After reading through the instructions a second time and looking at the sample I then decided it was just simple iteration through a grid. For each spot on the map I check what it’s parent (the character up one row in the same column of the map) is. If it’s S or | (pipe) then it becomes part of my path. For each blank (.) in my path I fill it in with | which can then become a parent for the rows below it. For each splitter (^) I change the neighboring blanks to | to show the path splitting in two. Since part 1 needs the count of splits, I increment a counter each time I do this.
When I reach the bottom, I’ve recreated the full tree as shown in the sample and found the count of splitters used.
DECLARE
v_map advent.t_map := advent.data2map('advent2025-7sample');
v_cnt PLS_INTEGER := 0;
v_width PLS_INTEGER := v_map.COUNT;
v_height PLS_INTEGER := v_map(1).COUNT;
BEGIN
FOR y IN 2 .. v_height
LOOP
FOR x IN 1 .. v_width
LOOP
IF v_map(x)(y - 1) IN ('S', '|')
THEN
CASE v_map(x)(y)
WHEN '.'
THEN
v_map(x)(y) := '|';
WHEN '^'
THEN
v_cnt := v_cnt + 1;
v_map(x - 1)(y) := '|';
v_map(x + 1)(y) := '|';
ELSE
NULL;
END CASE;
END IF;
END LOOP;
END LOOP;
advent.display_map(v_map);
DBMS_OUTPUT.put_line(v_cnt);
END;
For part 2, my initial thought was again trying to guess what the trick was the puzzle wanted rather than just reading through the text. Seeing the expansion form splitters to paths, my first guess was this would quickly explode with combinatorics that would be infeasible to tackle directly and I’d have to use memoization to avoid repetitive calculations. But again, after reading the instructions a second time I realized that after constructing the tree from the top down, I just needed to count the paths from the bottom up.
To do this I built a new collection (v_tree) that is another grid, but it is populated only with the elements that make up the path tree. I reused the logic of part 1, but at each step when I place a | on the map, I also add an element to the my tree collection. Each element is a counter of the number paths to reach it. All of the counts are initialized to 0 until I reach the last row in the grid, then each of those has a path-count of 1 (itself).
Now that I have my path tree built and seeded with counters. I simply iterate from the bottom up. Each step of the path will have a parent on the row above it either to the left, right, or directly above. And it can have more than one as the paths from above split and then merge again. For each parent found, increment that parent counter by the value of the child counter. Thus, as we go back up the grid, the counts keep increasing and are inclusive of every possible path below them. After I’ve summed up all the paths until I reach the top row I just return the counter for the starting position in the tree as it will be the parent of everything below it.
I was correct that the combinatoric expansion of exploring all possible paths from the top down would have been impractical. My grid had over 18 trillions possible paths from a starting tree of only 1537 splitters. That would have taken a fair amount of time to calculate all of those, but this simple bottom up summation did the job in under a tenth of a second.
DECLARE
TYPE pathcnt_tab IS TABLE OF INTEGER
INDEX BY SIMPLE_INTEGER;
TYPE tree_tab IS TABLE OF pathcnt_tab
INDEX BY SIMPLE_INTEGER;
v_tree tree_tab;
v_start INTEGER;
v_map advent.t_map := advent.data2map('advent2025-7');
v_width INTEGER := v_map.COUNT;
v_height INTEGER := v_map(1).COUNT;
BEGIN
FOR x IN 1 .. v_width
LOOP
IF v_map(x)(1) = 'S'
THEN
v_start := x;
v_tree(x)(1) := 0;
END IF;
END LOOP;
FOR y IN 2 .. v_height
LOOP
FOR x IN 1 .. v_width
LOOP
IF v_map(x)(y - 1) IN ('S', '|')
THEN
CASE v_map(x)(y)
WHEN '.'
THEN
v_map(x)(y) := '|';
v_tree(x)(y) := CASE WHEN y = v_height THEN 1 ELSE 0 END;
WHEN '^'
THEN
v_map(x - 1)(y) := '|';
v_tree(x - 1)(y) := 0;
v_map(x + 1)(y) := '|';
v_tree(x + 1)(y) := 0;
ELSE
NULL;
END CASE;
END IF;
END LOOP;
END LOOP;
FOR y IN REVERSE 2 .. v_height
LOOP
FOR x IN 1 .. v_width
LOOP
IF v_map(x)(y) = '|'
THEN
IF advent.mapchar(v_map, x - 1, y) = '^' AND advent.mapchar(v_map, x - 1, y - 1) = '|'
THEN
v_tree(x - 1)(y - 1) := v_tree(x - 1)(y - 1) + v_tree(x)(y);
END IF;
IF v_map(x)(y - 1) IN ('S', '|')
THEN
v_tree(x)(y - 1) := v_tree(x)(y - 1) + v_tree(x)(y);
END IF;
IF advent.mapchar(v_map, x + 1, y) = '^' AND advent.mapchar(v_map, x + 1, y - 1) = '|'
THEN
v_tree(x + 1)(y - 1) := v_tree(x + 1)(y - 1) + v_tree(x)(y);
END IF;
END IF;
END LOOP;
END LOOP;
DBMS_OUTPUT.put_line(v_tree(v_start)(1));
END;
Despite jumping ahead and then needing to rein myself in from trying to over complicate it I thought this one was a fun exercise.