From 5d8d80984489ee5d11754f5bce6fd8bf419c1bd1 Mon Sep 17 00:00:00 2001 From: Tristan Date: Wed, 18 Dec 2024 23:12:50 +0000 Subject: [PATCH] 2024 day 18 part 2 --- 2024/18/solution.nix | 32 +++++++++++++++++++++++----- 2024/lib/dijkstra.nix | 49 +++++++++++++++++++++++-------------------- 2 files changed, 53 insertions(+), 28 deletions(-) diff --git a/2024/18/solution.nix b/2024/18/solution.nix index 65897eb..4aa02eb 100644 --- a/2024/18/solution.nix +++ b/2024/18/solution.nix @@ -1,7 +1,8 @@ {lib, input ? "", my-lib, ...}@pkgs: rec { inherit pkgs; inherit lib; - inherit (builtins) elemAt genList elem concatStringsSep; + inherit my-lib; + inherit (builtins) elemAt genList elem concatStringsSep length; inherit (lib) splitString; inherit (lib.strings) toIntBase10; @@ -21,18 +22,39 @@ chartToStr = chart: chart |> (map (concatStringsSep "")) |> concatStringsSep "\n"; + inherit (my-lib.dijkstra {}) key; + mkSolution = {size, bytes, input}: rec { inherit size bytes input; - walls = lib.sublist 0 bytes (init input); - chart = genChart size walls; - part1result = dijkstra.toGoal.steps; - dijkstra = my-lib.dijkstra { + walls = init input; + part1result = p1Dijkstra.toGoal.steps; + p1Dijkstra = searchAfterBytes 12; + + searchAfterBytes = bytes: let + walls = lib.sublist 0 bytes (init input); + chart = genChart size walls; + in my-lib.dijkstra { pos = {x = 0; y = 0;}; goal = {x = size - 1; y = size - 1;}; chart = chart; width = 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 { diff --git a/2024/lib/dijkstra.nix b/2024/lib/dijkstra.nix index 28b32da..7227267 100644 --- a/2024/lib/dijkstra.nix +++ b/2024/lib/dijkstra.nix @@ -1,4 +1,4 @@ -{lib, pkgs, ...}: {pos, goal, chart, width, height}@init: rec { +{lib, pkgs, ...}: init: rec { inherit lib; inherit (lib) splitString mod range; inherit (lib.lists) findFirstIndex imap0; @@ -44,14 +44,17 @@ search {pos = fwd; inherit dir; score = score + 1;} ; - isCorner = pos: index2d pos init.chart == "." && - (dirs - |> mapAttrs (name: dir: let n = addVec pos dir; in index2d n init.chart == ".") - |> ({north, east, south, west}: - north && east || east && south || south && west || west && north)) + isCorner = pos: index2d pos init.chart == "." # && + # (dirs + # |> mapAttrs (name: dir: let n = addVec pos dir; in index2d n init.chart == ".") + # |> ({north, east, south, west}: + # 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: range 0 (init.height - 1) |> map (y: {inherit x y;}) @@ -105,12 +108,14 @@ if isNull acc.steps then node else if isNull node.steps then acc else if acc.steps < node.steps then acc else node - ) {turns = null; steps = null;} + ) {turns = null; steps = null; pos = null;} ; getScores = {done ? [], scores ? initScores}: let prev = getLowest {inherit done scores;}; in + if isNull prev.pos then {inherit done scores; impossible = true;} + else corners.${prev.pos} |> mapAttrs (dir: edge: let 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; - 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; - 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; @@ -193,20 +203,13 @@ ; }; - cornerScores = fastest init.goal {}; + cornerScores = getFastest init.goal {}; - addDist = foldl' (acc: {dist,alt,dir,...}: - acc + dist + (if addDist alt == 1 then 0 else (addDist alt) - 2) - ) 1; + path = (pathToList cornerScores.scores {}).path; - part1path = (pathToList cornerScores.scores {}); - -# not 520, too high - part2resultWrong = addDist part1path.path; - - genChart = size: walls: path: genList (y: genList (x: - if elem {inherit x y;} walls then "#" + pathChart = genList (y: genList (x: + if index2d {inherit x y;} init.chart == "#" then "#" else if elem (key {inherit x y;}) (map ({pos,...}: pos) path) then "O" else "." - ) size) size; + ) init.width) init.height; }