(defun main [] // Day 1 // TODO implement unless (let [p (pairWithSum 2020 [1721 979 366 299 675 1456])] (when !(and (has p 1721) (has p 299)) (throw "pairWithSum is broken"))) (let [[a b] (pairWithSum 2020 (readInts "src/year2020/inputs/day1-1.txt"))] (when !(= 545379 (* a b)) (throw "pairWithSum is broken"))) (let [t (trioWithSum 2020 [1721 979 366 299 675 1456])] (when !(and (has t 675) (has t 366) (has t 979)) (throw "trioWithSum is broken"))) (let [[a b c] (trioWithSum 2020 (readInts "src/year2020/inputs/day1-1.txt"))] (when !(= 257778836 (* a b c)) (throw "trioWithSum is broken")))) (defun readLines [file] (.filter (.map // TODO implement escape sequences in kiss string literals (.split (File.getContent file) #|"\n"|#) StringTools.trim) (lambda [l] (< 0 l.length)))) (defun readInts [file] (let [lines (readLines file)] (lines.map Std.parseInt))) (defun :kiss.List pairWithSum [sum :kiss.List numbers] // Put the numbers in a map for random access. This gives an O(n) solution (deflocal :Map numbersMap (new Map)) (doFor number numbers (dict-set numbersMap number (- sum number)) (let [requiredForPair (dict-get numbersMap number)] (when (numbersMap.exists requiredForPair) (return [number requiredForPair])))) null) (defun :kiss.List trioWithSum [sum :kiss.List numbers] (deflocal &mut trio null) (doFor number numbers (let [requiredForTrio (- sum number) pairThatSatisfies (pairWithSum requiredForTrio numbers)] (when pairThatSatisfies (return [number (nth pairThatSatisfies 0) (nth pairThatSatisfies 1)])))) null)