with import ../util.nix; let # read input input = splitString "\n\n" (readFile ./input); stacks = let # each layer of stacks as a raw input string layers = dropLast (splitString "\n" (head input)); # each layer of stacks as a list parsedLayers = map (s: map (l: elemAt l 1) (chunksOf 4 (stringToCharacters s))) layers; in # flip from layers to stacks and remove empty slots map (filter (s: s != " ")) (transpose parsedLayers); # list of moves "move 1 from 7 to 9" => [1 7 9] moves = map (line: map toInt (subtractLists ["move" "from" "to"] (splitString " " line))) (splitString "\n" (last input)); # funcs for how many boxes can be moved moveTopOnly = cnt: 1; # crane can only move one bpx at a time moveAll = cnt: cnt; # crane can move any number of boxes at a time # performs a single move performMove = moveCntFunc: stacks: mv: if head mv == 0 then stacks # base case; no more boxes to move else let cnt = elemAt mv 0; cnt' = moveCntFunc cnt; src = elemAt mv 1; dest = elemAt mv 2; boxes = take cnt' (elemAt stacks (src -1)); stacks' = imap1 (i: s: if i == src then drop cnt' s else if i == dest then boxes ++ s else s) stacks; in performMove moveCntFunc stacks' [(cnt - cnt') src dest]; # performs all moves in sequence performMoves = moveCntFunc: foldl (performMove moveCntFunc) stacks moves; in { part1 = concatStrings (map head (performMoves moveTopOnly)); part2 = concatStrings (map head (performMoves moveAll)); }