2022-12-12 13:57:34 +01:00
|
|
|
{ pkgs, lib, AoCLib, ... }:
|
2022-12-12 12:57:59 +01:00
|
|
|
|
|
|
|
with lib;
|
|
|
|
|
|
|
|
let
|
2022-12-12 13:57:34 +01:00
|
|
|
inherit (AoCLib) scanl abs repeat cmp;
|
|
|
|
|
2022-12-12 12:57:59 +01:00
|
|
|
mapDirectionStepsToHorizontalVertical = { direction, steps }: {
|
|
|
|
horizontal = if direction == "L" then steps else
|
|
|
|
if direction == "R" then -steps else 0;
|
|
|
|
vertical = if direction == "D" then steps else
|
|
|
|
if direction == "U" then -steps else 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
foldHeadPosition =
|
|
|
|
{ x ? 0, y ? 0 }:
|
|
|
|
{ horizontal, vertical }: {
|
|
|
|
x = x + horizontal;
|
|
|
|
y = y + vertical;
|
|
|
|
};
|
|
|
|
|
|
|
|
movements = pipe ./input.txt [
|
|
|
|
fileContents
|
|
|
|
(splitString "\n")
|
|
|
|
(map (splitString " "))
|
|
|
|
(map (x: { direction = head x; steps = toInt (elemAt x 1); }))
|
|
|
|
(map mapDirectionStepsToHorizontalVertical)
|
|
|
|
(scanl foldHeadPosition {})
|
|
|
|
];
|
|
|
|
|
|
|
|
ropePieceLength = headPiece: tailPiece: let
|
|
|
|
deltaX = abs (headPiece.x - tailPiece.x);
|
|
|
|
deltaY = abs (headPiece.y - tailPiece.y);
|
|
|
|
in max deltaX deltaY;
|
|
|
|
|
|
|
|
moveRopePiece = headPiece: tailPiece: {
|
2022-12-12 13:57:34 +01:00
|
|
|
x = tailPiece.x + (cmp headPiece.x tailPiece.x);
|
|
|
|
y = tailPiece.y + (cmp headPiece.y tailPiece.y);
|
2022-12-12 12:57:59 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
moveRope = headToOverlap: rope: let
|
|
|
|
newHead = moveRopePiece headToOverlap (head rope);
|
|
|
|
moveIfNextPieceMoved = x: y:
|
|
|
|
if ropePieceLength x y > 1
|
|
|
|
then moveRopePiece x y
|
|
|
|
else y;
|
|
|
|
newTail = scanl moveIfNextPieceMoved newHead (tail rope);
|
|
|
|
in [newHead] ++ newTail;
|
|
|
|
|
|
|
|
moveRopeUntilHeadOverlapsAndReportLastPositions = headToOverlap: rope: let
|
|
|
|
newRope = moveRope headToOverlap rope;
|
|
|
|
nextIteration = moveRopeUntilHeadOverlapsAndReportLastPositions headToOverlap newRope;
|
|
|
|
in if head rope == headToOverlap
|
|
|
|
then {
|
|
|
|
inherit rope;
|
|
|
|
tailPositions = [];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
inherit (nextIteration) rope;
|
|
|
|
tailPositions = [(last newRope)] ++ nextIteration.tailPositions;
|
|
|
|
};
|
|
|
|
|
|
|
|
f = n: { rope ? (repeat { x = 0; y = 0; } n), tailPositions ? [{ x = 0; y = 0; }] }: newHeadPosition: let
|
|
|
|
newRope = moveRopeUntilHeadOverlapsAndReportLastPositions newHeadPosition rope;
|
|
|
|
in {
|
|
|
|
rope = newRope.rope;
|
|
|
|
tailPositions = tailPositions ++ newRope.tailPositions;
|
|
|
|
};
|
|
|
|
|
|
|
|
answer1 = pipe movements [
|
|
|
|
(foldl (f 2) {})
|
|
|
|
(x: x.tailPositions)
|
|
|
|
unique
|
|
|
|
length
|
|
|
|
toString
|
|
|
|
];
|
|
|
|
|
|
|
|
answer2 = pipe movements [
|
|
|
|
(foldl (f 10) {})
|
|
|
|
(x: x.tailPositions)
|
|
|
|
unique
|
|
|
|
length
|
|
|
|
toString
|
|
|
|
];
|
|
|
|
|
|
|
|
in pkgs.writeText "answers" ''
|
|
|
|
Task1:
|
|
|
|
${answer1}
|
|
|
|
|
|
|
|
Task2:
|
|
|
|
${answer2}
|
|
|
|
''
|