{ lib, ... }: with lib; with builtins; rec { readLines = f: init (filter isString (split "\n" (readFile f))); reSplit = re: s: filter isString (split re s); matchAll = re: s: filter isList (split re s); splitWhitespace = reSplit "[[:space:]]+"; abs = i: if i >= 0 then i else i * -1; delta = x: y: abs (x - y); listSum = foldl' add 0; listSumWith = f: l: foldl' add 0 (map f l); deleteAt = l: i: (take i l) ++ (drop (i + 1) l); eq = x: y: x == y; greaterThan = x: y: x > y; listRange = l: genList identity (length l); invert = f: x: !(f x); elemAtMid = l: elemAt l ((length l) / 2); removeAll = rl: (flip pipe) (map remove rl); pipe' = flip pipe; inRange = i: l: (i >= 0) && (i < length l); identity = x: x; transpose = l: map (i: map ((flip elemAt) i) l) (listRange (head l)); matVecMul = m: v: map (r: foldl' add 0 (zipListsWith mul v r)) m; vecSum = zipListsWith add; vecDiff = zipListsWith sub; scalarVecMul = i: map (mul i); scalarVecDiv = i: map ((flip div) i); matIndex = i: pipe' (map (flip elemAt) i); inRangeMatrix = i: m: if i == [ ] then true else (isList m) && (inRange (head i) m) && (inRangeMatrix (tail i) (elemAt m (head i))); raycastUntil = pred: direction: pos: if pred pos then [ ] else [ pos ] ++ (raycastUntil pred direction (vecSum pos direction)); getMatrixIndices = m: let makeLayers = m: if isList m then [ (listRange m) ] ++ (makeLayers (head m)) else []; layers = makeLayers m; in mapCartesianProduct (args@{...}: attrValues args) (listToAttrs (map (k: nameValuePair (toString k) (elemAt layers k)) (listRange layers))); gcd = a: b: if a == 0 then b else if b == 0 then a else if a < b then gcd b a else gcd b (mod a b); listGcd = l: foldl' gcd (head l) (tail l); shortenVec = vec: scalarVecDiv (listGcd (map abs vec)) vec; }