2024 day 18 part 2
This commit is contained in:
parent
5467ea9393
commit
5d8d809844
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue