2024 day 18 part 2

This commit is contained in:
Tristan 2024-12-18 23:12:50 +00:00
parent 5467ea9393
commit 5d8d809844
2 changed files with 53 additions and 28 deletions

View file

@ -1,7 +1,8 @@
{lib, input ? "", my-lib, ...}@pkgs: rec { {lib, input ? "", my-lib, ...}@pkgs: rec {
inherit pkgs; inherit pkgs;
inherit lib; inherit lib;
inherit (builtins) elemAt genList elem concatStringsSep; inherit my-lib;
inherit (builtins) elemAt genList elem concatStringsSep length;
inherit (lib) splitString; inherit (lib) splitString;
inherit (lib.strings) toIntBase10; inherit (lib.strings) toIntBase10;
@ -21,18 +22,39 @@
chartToStr = chart: chart |> (map (concatStringsSep "")) |> concatStringsSep "\n"; chartToStr = chart: chart |> (map (concatStringsSep "")) |> concatStringsSep "\n";
inherit (my-lib.dijkstra {}) key;
mkSolution = {size, bytes, input}: rec { mkSolution = {size, bytes, input}: rec {
inherit size bytes input; inherit size bytes input;
walls = lib.sublist 0 bytes (init input); walls = init input;
chart = genChart size walls; part1result = p1Dijkstra.toGoal.steps;
part1result = dijkstra.toGoal.steps; p1Dijkstra = searchAfterBytes 12;
dijkstra = my-lib.dijkstra {
searchAfterBytes = bytes: let
walls = lib.sublist 0 bytes (init input);
chart = genChart size walls;
in my-lib.dijkstra {
pos = {x = 0; y = 0;}; pos = {x = 0; y = 0;};
goal = {x = size - 1; y = size - 1;}; goal = {x = size - 1; y = size - 1;};
chart = chart; chart = chart;
width = size; width = size;
height = size; height = size;
}; };
findFirst = bytes: prevPath: let
dijkstra = lib.traceSeq "retracing after ${toString bytes} with ${key wall}" (searchAfterBytes bytes);
wall = elemAt walls (bytes - 1);
wallCollides = elem (key wall) (map ({pos,...}: pos) prevPath);
in if !wallCollides
then findFirst (bytes + 1) prevPath
else
if dijkstra.isImpossible
then key wall
else
findFirst (bytes + 1) dijkstra.path;
part2result = findFirst bytes p1Dijkstra.path;
}; };
example = mkSolution { example = mkSolution {

View file

@ -1,4 +1,4 @@
{lib, pkgs, ...}: {pos, goal, chart, width, height}@init: rec { {lib, pkgs, ...}: init: rec {
inherit lib; inherit lib;
inherit (lib) splitString mod range; inherit (lib) splitString mod range;
inherit (lib.lists) findFirstIndex imap0; inherit (lib.lists) findFirstIndex imap0;
@ -44,14 +44,17 @@
search {pos = fwd; inherit dir; score = score + 1;} search {pos = fwd; inherit dir; score = score + 1;}
; ;
isCorner = pos: index2d pos init.chart == "." && isCorner = pos: index2d pos init.chart == "." # &&
(dirs # (dirs
|> mapAttrs (name: dir: let n = addVec pos dir; in index2d n init.chart == ".") # |> mapAttrs (name: dir: let n = addVec pos dir; in index2d n init.chart == ".")
|> ({north, east, south, west}: # |> ({north, east, south, west}:
north && east || east && south || south && west || west && north)) # north && east || east && south || south && west || west && north))
; ;
key = {x, y}: "${toString (y + 1)},${toString (x + 1)}"; key = {x, y}:
"${toString x},${toString y}";
# gives locations like vim cursor indicator
#"${toString (y + 1)},${toString (x + 1)}";
corners = range 0 (init.width - 1) |> map (x: corners = range 0 (init.width - 1) |> map (x:
range 0 (init.height - 1) |> map (y: {inherit x y;}) range 0 (init.height - 1) |> map (y: {inherit x y;})
@ -105,12 +108,14 @@
if isNull acc.steps then node else if isNull acc.steps then node else
if isNull node.steps then acc else if isNull node.steps then acc else
if acc.steps < node.steps then acc else node if acc.steps < node.steps then acc else node
) {turns = null; steps = null;} ) {turns = null; steps = null; pos = null;}
; ;
getScores = {done ? [], scores ? initScores}: let getScores = {done ? [], scores ? initScores}: let
prev = getLowest {inherit done scores;}; prev = getLowest {inherit done scores;};
in in
if isNull prev.pos then {inherit done scores; impossible = true;}
else
corners.${prev.pos} corners.${prev.pos}
|> mapAttrs (dir: edge: let |> mapAttrs (dir: edge: let
turns = if prev.dir == dir then prev.turns else prev.turns + 1; turns = if prev.dir == dir then prev.turns else prev.turns + 1;
@ -145,13 +150,18 @@
}) })
; ;
fastest = goal: s: let getFastest = goal: s: let
next = getScores s; next = getScores s;
in if elem (key goal) (next.done) then next else fastest goal next; in if next.impossible or false || elem (key goal) (next.done)
then next
else getFastest goal next;
pathScore = steps: turns: steps + turns * 1000; pathScore = steps: turns: steps + turns * 1000;
toGoal = (fastest init.goal {}).scores.${key init.goal}; isImpossible = (getFastest init.goal {}).impossible or false;
fastestTo = (getFastest init.goal {}).scores;
toGoal = fastestTo.${key init.goal};
part1result = pathScore toGoal.steps toGoal.turns; part1result = pathScore toGoal.steps toGoal.turns;
@ -193,20 +203,13 @@
; ;
}; };
cornerScores = fastest init.goal {}; cornerScores = getFastest init.goal {};
addDist = foldl' (acc: {dist,alt,dir,...}: path = (pathToList cornerScores.scores {}).path;
acc + dist + (if addDist alt == 1 then 0 else (addDist alt) - 2)
) 1;
part1path = (pathToList cornerScores.scores {}); pathChart = genList (y: genList (x:
if index2d {inherit x y;} init.chart == "#" then "#"
# not 520, too high
part2resultWrong = addDist part1path.path;
genChart = size: walls: path: genList (y: genList (x:
if elem {inherit x y;} walls then "#"
else if elem (key {inherit x y;}) (map ({pos,...}: pos) path) then "O" else if elem (key {inherit x y;}) (map ({pos,...}: pos) path) then "O"
else "." else "."
) size) size; ) init.width) init.height;
} }