Definitely the smallest diff between Part 1 and Part 2 — I just deleted a line in my part 1 solution that hard-coded where the light entered the grid

**enter 0 0 (pair 1 0).**

…and instead added that programmaticaly in JavaScript. This wasn’t a fast or awesome Part 2 solution, and relied on JavaScript logic a fair amount, but the Part 1 solution was very clean in pretty much all Dusa.

Challenges

I think lots of people got tripped up on the fact that this problem used \\ characters, which are generally an escape character. Dusa doesn’t even support escape characters! So I had to read in the backslashes as &. This was the first time my JavaScript parsing logic used much of anything more than maps, split(), or slice(). (Day 15 also needed charCodeAt(), I suppose.)

Logic

Here’s the part 1 solution Dusa%20%3A-%0A%20%20%20%20cell%20X%20Y%20is%20%22%2F%22%2C%0A%20%20%20%20enter%20X%20Y%20(pair%20DX%20DY).%0A%0Aleave%20X%20Y%20(pair%20DY%20DX)%20%3A-%0A%20%20%20%20cell%20X%20Y%20is%20%22%26%22%2C%0A%20%20%20%20enter%20X%20Y%20(pair%20DX%20DY).%0A%0Aenter%20(plus%20X%20DX)%20(plus%20Y%20DY)%20(pair%20DX%20DY)%20%3A-%0A%20%20%20%20leave%20X%20Y%20(pair%20DX%20DY)%2C%0A%20%20%20%20cell%20(plus%20X%20DX)%20(plus%20Y%20DY)%20is%20_.%0A%0Acharged%20X%20Y%20%3A-%20enter%20X%20Y%20_.%0A%0Aenter%200%200%20(pair%201%200).%0A%0Afield%20ref12%200%20is%20%22.%22.%0Afield%20ref12%201%20is%20%22.%22.%0Afield%20ref12%202%20is%20%22%2F%22.%0Afield%20ref12%203%20is%20%22%2F%22.%0Afield%20ref12%204%20is%20%22.%22.%0Afield%20ref12%205%20is%20%22%7C%22.%0Afield%20ref12%206%20is%20%22.%22.%0Afield%20ref12%207%20is%20%22.%22.%0Afield%20ref12%208%20is%20%22.%22.%0Afield%20ref12%209%20is%20%22.%22.%0Afield%20ref11%200%20is%20%22.%22.%0Afield%20ref11%201%20is%20%22%7C%22.%0Afield%20ref11%202%20is%20%22.%22.%0Afield%20ref11%203%20is%20%22.%22.%0Afield%20ref11%204%20is%20%22.%22.%0Afield%20ref11%205%20is%20%22.%22.%0Afield%20ref11%206%20is%20%22-%22.%0Afield%20ref11%207%20is%20%22%7C%22.%0Afield%20ref11%208%20is%20%22.%22.%0Afield%20ref11%209%20is%20%22%26%22.%0Afield%20ref10%200%20is%20%22.%22.%0Afield%20ref10%201%20is%20%22-%22.%0Afield%20ref10%202%20is%20%22.%22.%0Afield%20ref10%203%20is%20%22-%22.%0Afield%20ref10%204%20is%20%22%2F%22.%0Afield%20ref10%205%20is%20%22.%22.%0Afield%20ref10%206%20is%20%22.%22.%0Afield%20ref10%207%20is%20%22%7C%22.%0Afield%20ref10%208%20is%20%22.%22.%0Afield%20ref10%209%20is%20%22.%22.%0Afield%20ref9%200%20is%20%22.%22.%0Afield%20ref9%201%20is%20%22.%22.%0Afield%20ref9%202%20is%20%22.%22.%0Afield%20ref9%203%20is%20%22.%22.%0Afield%20ref9%204%20is%20%22%2F%22.%0Afield%20ref9%205%20is%20%22.%22.%0Afield%20ref9%206%20is%20%22%26%22.%0Afield%20ref9%207%20is%20%22%26%22.%0Afield%20ref9%208%20is%20%22.%22.%0Afield%20ref9%209%20is%20%22.%22.%0Afield%20ref8%200%20is%20%22.%22.%0Afield%20ref8%201%20is%20%22.%22.%0Afield%20ref8%202%20is%20%22.%22.%0Afield%20ref8%203%20is%20%22.%22.%0Afield%20ref8%204%20is%20%22.%22.%0Afield%20ref8%205%20is%20%22.%22.%0Afield%20ref8%206%20is%20%22.%22.%0Afield%20ref8%207%20is%20%22.%22.%0Afield%20ref8%208%20is%20%22.%22.%0Afield%20ref8%209%20is%20%22%26%22.%0Afield%20ref7%200%20is%20%22.%22.%0Afield%20ref7%201%20is%20%22.%22.%0Afield%20ref7%202%20is%20%22.%22.%0Afield%20ref7%203%20is%20%22.%22.%0Afield%20ref7%204%20is%20%22.%22.%0Afield%20ref7%205%20is%20%22.%22.%0Afield%20ref7%206%20is%20%22.%22.%0Afield%20ref7%207%20is%20%22.%22.%0Afield%20ref7%208%20is%20%22.%22.%0Afield%20ref7%209%20is%20%22.%22.%0Afield%20ref6%200%20is%20%22.%22.%0Afield%20ref6%201%20is%20%22.%22.%0Afield%20ref6%202%20is%20%22.%22.%0Afield%20ref6%203%20is%20%22.%22.%0Afield%20ref6%204%20is%20%22.%22.%0Afield%20ref6%205%20is%20%22.%22.%0Afield%20ref6%206%20is%20%22.%22.%0Afield%20ref6%207%20is%20%22.%22.%0Afield%20ref6%208%20is%20%22%7C%22.%0Afield%20ref6%209%20is%20%22.%22.%0Afield%20ref5%200%20is%20%22.%22.%0Afield%20ref5%201%20is%20%22.%22.%0Afield%20ref5%202%20is%20%22.%22.%0Afield%20ref5%203%20is%20%22.%22.%0Afield%20ref5%204%20is%20%22.%22.%0Afield%20ref5%205%20is%20%22%7C%22.%0Afield%20ref5%206%20is%20%22-%22.%0Afield%20ref5%207%20is%20%22.%22.%0Afield%20ref5%208%20is%20%22.%22.%0Afield%20ref5%209%20is%20%22.%22.%0Afield%20ref4%200%20is%20%22%7C%22.%0Afield%20ref4%201%20is%20%22.%22.%0Afield%20ref4%202%20is%20%22-%22.%0Afield%20ref4%203%20is%20%22.%22.%0Afield%20ref4%204%20is%20%22%26%22.%0Afield%20ref4%205%20is%20%22.%22.%0Afield%20ref4%206%20is%20%22.%22.%0Afield%20ref4%207%20is%20%22.%22.%0Afield%20ref4%208%20is%20%22.%22.%0Afield%20ref4%209%20is%20%22.%22.%0Afield%20ref3%200%20is%20%22.%22.%0Afield%20ref3%201%20is%20%22%7C%22.%0Afield%20ref3%202%20is%20%22.%22.%0Afield%20ref3%203%20is%20%22.%22.%0Afield%20ref3%204%20is%20%22.%22.%0Afield%20ref3%205%20is%20%22%26%22.%0Afield%20ref3%206%20is%20%22.%22.%0Afield%20ref3%207%20is%20%22.%22.%0Afield%20ref3%208%20is%20%22.%22.%0Afield%20ref3%209%20is%20%22.%22.%0Afield%20ref2%200%20is%20ref3.%0Afield%20ref2%201%20is%20ref4.%0Afield%20ref2%202%20is%20ref5.%0Afield%20ref2%203%20is%20ref6.%0Afield%20ref2%204%20is%20ref7.%0Afield%20ref2%205%20is%20ref8.%0Afield%20ref2%206%20is%20ref9.%0Afield%20ref2%207%20is%20ref10.%0Afield%20ref2%208%20is%20ref11.%0Afield%20ref2%209%20is%20ref12.%0Afield%20ref1%20%22data%22%20is%20ref2.%0A) — the answer came from counting the charged facts, where a cell is charged if light enters it.

**charged X Y :- enter X Y _.**

The key logic to this solution was this: the direction of a light beam was described by a tuple pair DX DY, and if a beam is leaving a cell in a particular direction, and there’s a cell (regardless of contents) in that direction, then the beam is entering that adjacent cell in the direction of travel, in the same direction.

**enter (plus X DX) (plus Y DY) (pair DX DY) :-
    leave X Y (pair DX DY),
    cell (plus X DX) (plus Y DY) is _.**

All the rest of the solution is deriving leave facts from enter facts.

“Dots just let light pass through” is represented like this:

**leave X Y Dir :-
    cell X Y is ".",
    enter X Y Dir.**

I once again really wanted multiple-conclusion rules, because without them, second rule below requires some cut-paste of premises. Conceptually: light passes through a - cell if it has no vertical component, and if it has a vertical component then there will be beams exiting to both the left and the right.

**leave X Y Dir :-
    cell X Y is "-",
    enter X Y Dir,
    Dir == pair _ 0.

leave X Y (pair -1 0),
leave X Y (pair 1 0) :-
    cell X Y is "-",
    enter X Y (pair 0 _).**

(The rules for | are analogous.)

Finally, the reflecting mirrors were very nice to describe as one-rule-per-mirror-configuration, though I couldn’t help feeling like this in particular was an awkward way to describe multiplying a vector by a 2x2 rotation matrix.

**leave X Y (pair (minus 0 DY) (minus 0 DX)) :-
    cell X Y is "/",
    enter X Y (pair DX DY).

leave X Y (pair DY DX) :-
    cell X Y is "&",
    enter X Y (pair DX DY).**

JavaScript

These solutions have to use escape characters, I used file IO to avoid that when I solved the problem “for real.”