From c2ec0f25da32e448f593db6d7a2b821eb5923412 Mon Sep 17 00:00:00 2001 From: Matteo Landi Date: Wed, 6 Dec 2023 07:32:33 +0100 Subject: [PATCH] Add EXTRACT-{POSITIVE-}INTEGERS to utils, and pull WHILE from quickutil --- .gitignore | 5 +++++ .lispwords | 2 ++ package.lisp | 2 ++ src/2015/day15.lisp | 3 +-- src/2015/day21.lisp | 6 ++---- src/2015/day22.lisp | 7 +++---- src/2018/day10.lisp | 3 +-- src/2018/day13.lisp | 1 - src/2021/day04.lisp | 7 ++----- src/2021/day05.lisp | 3 +-- src/2021/day07.lisp | 3 +-- src/2021/day19.lisp | 8 +++----- src/2022/day04.lisp | 2 +- src/2022/day05.lisp | 3 +-- src/2022/day11.lisp | 6 ++---- src/2022/day14.lisp | 2 +- src/2022/day15.lisp | 4 +--- src/2022/day15.lisp.1 | 9 +++----- src/2022/day16.lisp | 2 +- src/2022/day19.lisp | 2 +- src/2022/day19.lisp.1 | 2 +- src/2022/day19.lisp.2 | 2 +- src/2022/day19.lisp.3 | 5 +---- src/2022/day19.lisp.4 | 2 +- src/2022/day19.lisp.5 | 2 +- src/2022/day19.lisp.6.part1 | 2 +- src/2022/day19.lisp.7 | 2 +- src/2022/day19.lisp.8 | 2 +- src/2022/day22.lisp | 2 +- src/2022/day22.lisp.part1 | 2 +- src/2022/day22.lisp.part2 | 2 +- src/2023/day04.lisp | 6 +++--- src/utils.lisp | 6 ++++++ vendor/make-quickutils.lisp | 1 + vendor/quickutil | 1 - vendor/quickutils.lisp | 41 ++++++++++++++++++++++++++++--------- 36 files changed, 86 insertions(+), 74 deletions(-) delete mode 120000 vendor/quickutil diff --git a/.gitignore b/.gitignore index 5020ae5..5148476 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,7 @@ +/.DS_Store /.common-lisp/ /.quicklisp/ +/src/.DS_Store +/vendor/.common-lisp/ +/vendor/.quicklisp/ +/vendor/quickutil diff --git a/.lispwords b/.lispwords index 5748b09..3d722b1 100644 --- a/.lispwords +++ b/.lispwords @@ -9,6 +9,7 @@ (define-test 2) (destructuring-bind 2) (dolist 1) +(dolist+ 1) (dorange 1) (dorange 1) (dorangei 1) @@ -16,6 +17,7 @@ (dotimes 1) (ecase 1) (flet 1) +(fn 1) (gathering 0) (handler-case 1) (if 1) diff --git a/package.lisp b/package.lisp index f5a602e..3658a63 100644 --- a/package.lisp +++ b/package.lisp @@ -81,6 +81,8 @@ :parse-integers :read-integer :parse-char + :extract-positive-integers + :extract-integers :define-solution :define-test)) diff --git a/src/2015/day15.lisp b/src/2015/day15.lisp index de17394..de8fb54 100644 --- a/src/2015/day15.lisp +++ b/src/2015/day15.lisp @@ -1,8 +1,7 @@ (defpackage :aoc/2015/15 #.cl-user::*aoc-use*) (in-package :aoc/2015/15) -(defun parse-properties (string) - (mapcar #'parse-integer (cl-ppcre:all-matches-as-strings "-?\\d+" string))) +(defun parse-properties (string) (extract-integers string)) (defun calories (props) (nth 4 props)) (defun parse-ingredient (string) diff --git a/src/2015/day21.lisp b/src/2015/day21.lisp index 4340aa3..d7a38d4 100644 --- a/src/2015/day21.lisp +++ b/src/2015/day21.lisp @@ -20,10 +20,8 @@ ("Defense +2" 40 0 2) ("Defense +3" 80 0 3))) -(defun parse-boss (lines) - (mapcar #'parse-integer - (cl-ppcre:all-matches-as-strings "\\d+" - (format nil "~{~A ~}" lines)))) +(defun parse-boss (&optional (lines (uiop:read-file-lines #P"src/2015/day21.txt"))) + (extract-positive-integers (format nil "~{~A ~}" lines))) (defun all-items-combinations () (loop for w in *weapons* append diff --git a/src/2015/day22.lisp b/src/2015/day22.lisp index a54ff5c..56a8c86 100644 --- a/src/2015/day22.lisp +++ b/src/2015/day22.lisp @@ -56,10 +56,9 @@ ;; Boss logic (defstruct (boss (:type list)) life damage) -(defun parse-boss (lines) - (mapcar #'parse-integer - (cl-ppcre:all-matches-as-strings "\\d+" - (format nil "~{~A ~}" lines)))) +(defun parse-boss (&optional (lines (uiop:read-file-lines #P"src/2015/day22.txt"))) + (extract-positive-integers (format nil "~{~A ~}" lines))) + (defun boss-attack (boss player) (max 1 (- (boss-damage boss) (player-armor-effect player)))) diff --git a/src/2018/day10.lisp b/src/2018/day10.lisp index d7bf707..3202538 100644 --- a/src/2018/day10.lisp +++ b/src/2018/day10.lisp @@ -8,8 +8,7 @@ (mapcar #'parse-star data)) (defun parse-star (string) - (destructuring-bind (x y vx vy) - (mapcar #'parse-integer (cl-ppcre:all-matches-as-strings "-?\\d+" string)) + (destructuring-bind (x y vx vy) (extract-integers string) (make-star :pos (list x y) :vel (list vx vy)))) diff --git a/src/2018/day13.lisp b/src/2018/day13.lisp index 968b9a3..a768a7d 100644 --- a/src/2018/day13.lisp +++ b/src/2018/day13.lisp @@ -84,7 +84,6 @@ (< (realpart c1) (realpart c2))))) (defun cart-move (cart track) - (declare (optimize (speed 3))) (with-slots (pos dir choices) cart (incf pos dir) (let ((ch (gethash pos track))) diff --git a/src/2021/day04.lisp b/src/2021/day04.lisp index 193829c..0fed83d 100644 --- a/src/2021/day04.lisp +++ b/src/2021/day04.lisp @@ -7,7 +7,7 @@ boards) (defun parse-bingo (data) - (let ((to-draw (extract-integers (car data))) + (let ((to-draw (extract-positive-integers (car data))) (boards (parse-boards (cdr data)))) (make-bingo :to-draw to-draw :boards boards))) @@ -19,13 +19,10 @@ (let ((lines (subseq data 1 6))) (looping (dolist (s lines) - (let ((row (extract-integers s))) + (let ((row (extract-positive-integers s))) (collect! row)))))) (parse-boards (subseq data 6))))) -(defun extract-integers (s) - (mapcar #'parse-integer (cl-ppcre:all-matches-as-strings "\\d+" s))) - (defun play (game) (looping diff --git a/src/2021/day05.lisp b/src/2021/day05.lisp index c9ff48a..0edfadb 100644 --- a/src/2021/day05.lisp +++ b/src/2021/day05.lisp @@ -5,8 +5,7 @@ (defun parse-lines (data) (mapcar #'parse-line data)) -(defun parse-line (string) - (mapcar #'parse-integer (cl-ppcre:all-matches-as-strings "\\d+" string))) +(defun parse-line (string) (extract-positive-integers string)) (defun part1 (lines) diff --git a/src/2021/day07.lisp b/src/2021/day07.lisp index 47757c2..b7df5c0 100644 --- a/src/2021/day07.lisp +++ b/src/2021/day07.lisp @@ -2,8 +2,7 @@ (in-package :aoc/2021/07) -(defun parse-crabs (data) - (mapcar #'parse-integer (cl-ppcre:all-matches-as-strings "\\d+" (first data)))) +(defun parse-crabs (data) (extract-positive-integers (first data))) (defun minimize-fuel (crabs distance-fun) diff --git a/src/2021/day19.lisp b/src/2021/day19.lisp index fc50245..23914a2 100644 --- a/src/2021/day19.lisp +++ b/src/2021/day19.lisp @@ -4,11 +4,9 @@ ;; Input (defun parse-scanner (paragraph &aux (paragraph (cl-ppcre:split "\\n" paragraph))) - (flet ((numbers (string) - (mapcar #'parse-integer (cl-ppcre:all-matches-as-strings "-?\\d+" string)))) - (cons - (first (numbers (first paragraph))) - (mapcar #'numbers (rest paragraph))))) + (cons + (first (extract-integers (first paragraph))) + (mapcar #'extract-integers (rest paragraph)))) (defun id (scn) (car scn)) (defun beacons (scn) (cdr scn)) diff --git a/src/2022/day04.lisp b/src/2022/day04.lisp index d983f07..2cbf64c 100644 --- a/src/2022/day04.lisp +++ b/src/2022/day04.lisp @@ -3,7 +3,7 @@ (defun assignment-pairs () - (mapcar [mapcar #'parse-integer (cl-ppcre:all-matches-as-strings "\\d+" _)] + (mapcar [extract-positive-integers _] (uiop:read-file-lines #P"src/2022/day04.txt"))) (defun solution-run () diff --git a/src/2022/day05.lisp b/src/2022/day05.lisp index bb07295..56a4985 100644 --- a/src/2022/day05.lisp +++ b/src/2022/day05.lisp @@ -14,8 +14,7 @@ for i from 1 do (setf (aref array i) (loop for ch in stack when (alpha-char-p ch) collect ch))) array) - (mapcar [mapcar #'parse-integer (cl-ppcre:all-matches-as-strings "\\d+" _)] - moves))))) + (mapcar [extract-positive-integers _] moves))))) (defun top-crates (stacks) (format nil "~{~A~}" (map 'list #'car (subseq stacks 1)))) diff --git a/src/2022/day11.lisp b/src/2022/day11.lisp index 0bf74ed..aa0e5bb 100644 --- a/src/2022/day11.lisp +++ b/src/2022/day11.lisp @@ -21,8 +21,7 @@ throw-if-not-div) (defun parse-number (s) (car (parse-numbers s))) -(defun parse-numbers (s) - (mapcar #'parse-integer (cl-ppcre:all-matches-as-strings "\\d+" s))) +(defun parse-numbers (s) (extract-positive-integers s)) (defun parse-operation (s) (bnd1 (old (symb "_")) @@ -121,8 +120,7 @@ throw-if-not-div) (defun parse-number (s) (car (parse-numbers s))) -(defun parse-numbers (s) - (mapcar #'parse-integer (cl-ppcre:all-matches-as-strings "\\d+" s))) +(defun parse-numbers (s) (extract-positive-integers s)) (defun parse-operation (s) (bnd1 (old (symb "_")) diff --git a/src/2022/day14.lisp b/src/2022/day14.lisp index 34e2dac..cfe3210 100644 --- a/src/2022/day14.lisp +++ b/src/2022/day14.lisp @@ -9,7 +9,7 @@ (defun parse-cave (&optional (file #P"src/2022/day14.txt")) (let ((cave (make-hash-table :test 'equal))) (dolist (s (uiop:read-file-lines file)) - (loop for (from-col from-row to-col to-row) on (mapcar #'parse-integer (cl-ppcre:all-matches-as-strings "\\d+" s)) by #'cddr + (loop for (from-col from-row to-col to-row) on (extract-positive-integers s) by #'cddr while to-row do (loop with delta-row = (<=> to-row from-row) with delta-col = (<=> to-col from-col) for row = from-row then (+ row delta-row) diff --git a/src/2022/day15.lisp b/src/2022/day15.lisp index c97a78d..eaf84cb 100644 --- a/src/2022/day15.lisp +++ b/src/2022/day15.lisp @@ -9,14 +9,12 @@ (defun r (s) (manhattan-distance (pos s) (beacon s))) (defun parse-sensor (string) - (destructuring-bind (sx sy bx by) - (mapcar #'parse-integer (cl-ppcre:all-matches-as-strings "-?\\d+" string)) + (destructuring-bind (sx sy bx by) (extract-integers string) (make-sensor :pos (list sx sy) :beacon (list bx by)))) (defun sensors (&optional (file #P"src/2022/day15.txt")) (mapcar #'parse-sensor (uiop:read-file-lines file))) - (defun bounding-square (sensors) (loop for s in sensors for r = (r s) for (x y) = (car s) diff --git a/src/2022/day15.lisp.1 b/src/2022/day15.lisp.1 index b6cc6d4..4ea713b 100644 --- a/src/2022/day15.lisp.1 +++ b/src/2022/day15.lisp.1 @@ -6,8 +6,7 @@ (defun parse-input (&optional (file #P"src/2022/day15.txt")) (loop for s in (uiop:read-file-lines file) - for (sx sy bx by) = (cl-ppcre:all-matches-as-strings "-?\\d+" s) - collect (mapcar #'parse-integer (list sx sy bx by)))) + collect (extract-integers s))) (defun bounding-box (&optional (input (parse-input))) (loop for (sx sy bx by) in input minimize sx into min-x maximize sx into max-x @@ -42,8 +41,7 @@ #; Scratch (defun parse-input (&optional (file #P"src/2022/day15.txt")) (loop for s in (uiop:read-file-lines file) - for (sx sy bx by) = (mapcar #'parse-integer - (cl-ppcre:all-matches-as-strings "-?\\d+" s)) + for (sx sy bx by) = (extract-integers s) collect (list (list sx sy) (list bx by)))) (defun bounding-box (&optional (input (parse-input))) (loop for (sensor beacon) in input @@ -95,8 +93,7 @@ (defun x (pos) (first pos)) (defun y (pos) (second pos)) (defun parse-nanobot (string) - (destructuring-bind (sx sy bx by) - (mapcar #'parse-integer (cl-ppcre:all-matches-as-strings "-?\\d+" string)) + (destructuring-bind (sx sy bx by) (extract-integers string) (make-nanobot :pos (list sx sy) :r (manhattan-distance (list sx sy) (list bx by))))) diff --git a/src/2022/day16.lisp b/src/2022/day16.lisp index e76a388..e6d7898 100644 --- a/src/2022/day16.lisp +++ b/src/2022/day16.lisp @@ -6,7 +6,7 @@ (defun parse-valve (s) (let ((names (mapcar #'symb (cl-ppcre:all-matches-as-strings "[A-Z]{2}" s))) - (rate (first (mapcar #'parse-integer (cl-ppcre:all-matches-as-strings "\\d+" s))))) + (rate (first (extract-positive-integers s)))) (make-valve :name (car names) :rate rate :connected-to (rest names)))) diff --git a/src/2022/day19.lisp b/src/2022/day19.lisp index f428cfa..dd51159 100644 --- a/src/2022/day19.lisp +++ b/src/2022/day19.lisp @@ -12,7 +12,7 @@ (destructuring-bind (id ore-robot-cost clay-robot-cost obsidian-robot-ore-cost obsidian-robot-clay-cost geode-robot-ore-cost geode-robot-obsidian-cost) - (mapcar #'parse-integer (cl-ppcre:all-matches-as-strings "\\d+" string)) + (extract-positive-integers string) (make-blueprint :id id :costs (list (list diff --git a/src/2022/day19.lisp.1 b/src/2022/day19.lisp.1 index a976818..2f24c94 100644 --- a/src/2022/day19.lisp.1 +++ b/src/2022/day19.lisp.1 @@ -8,7 +8,7 @@ (destructuring-bind (id ore-robot-cost clay-robot-cost obsidian-robot-ore-cost obsidian-robot-clay-cost geode-robot-ore-cost geode-robot-obsidian-cost) - (mapcar #'parse-integer (cl-ppcre:all-matches-as-strings "\\d+" string)) + (extract-positive-integers string) (make-blueprint :id id :costs (list (list diff --git a/src/2022/day19.lisp.2 b/src/2022/day19.lisp.2 index ba063bb..fa3c833 100644 --- a/src/2022/day19.lisp.2 +++ b/src/2022/day19.lisp.2 @@ -8,7 +8,7 @@ (destructuring-bind (id ore-robot-cost clay-robot-cost obsidian-robot-ore-cost obsidian-robot-clay-cost geode-robot-ore-cost geode-robot-obsidian-cost) - (mapcar #'parse-integer (cl-ppcre:all-matches-as-strings "\\d+" string)) + (extract-positive-integers string) (make-blueprint :id id :costs (list (list diff --git a/src/2022/day19.lisp.3 b/src/2022/day19.lisp.3 index 4ab03ec..bc3afaf 100644 --- a/src/2022/day19.lisp.3 +++ b/src/2022/day19.lisp.3 @@ -8,7 +8,7 @@ (destructuring-bind (id ore-robot-cost clay-robot-cost obsidian-robot-ore-cost obsidian-robot-clay-cost geode-robot-ore-cost geode-robot-obsidian-cost) - (mapcar #'parse-integer (cl-ppcre:all-matches-as-strings "\\d+" string)) + (extract-positive-integers string) (make-blueprint :id id :ore (list ore-robot-cost 0 0) :clay (list clay-robot-cost 0 0) @@ -18,9 +18,6 @@ (defun blueprints (&optional (file #P"src/2022/day19.txt")) (mapcar #'parse-blueprint (uiop:read-file-lines file))) -(defmacro while (test-form &body body) - `(loop while ,test-form ,@body)) - (defun can-collect-ore? (target blueprint remaining) (cond ((< remaining 0) nil) ((<= target remaining) t) diff --git a/src/2022/day19.lisp.4 b/src/2022/day19.lisp.4 index 3febd5e..ad3229e 100644 --- a/src/2022/day19.lisp.4 +++ b/src/2022/day19.lisp.4 @@ -5,7 +5,7 @@ id ore clay obsidian geode) (defun parse-blueprint (string) - (bnd1 (nums (mapcar #'parse-integer (cl-ppcre:all-matches-as-strings "\\d+" string))) + (bnd1 (nums (extract-positive-integers string)) (make-blueprint :id (elt nums 0) :ore (subseq nums 1 2) :clay (subseq nums 2 3) diff --git a/src/2022/day19.lisp.5 b/src/2022/day19.lisp.5 index d03e249..d5b098f 100644 --- a/src/2022/day19.lisp.5 +++ b/src/2022/day19.lisp.5 @@ -18,7 +18,7 @@ id ore clay obsidian geode) (defun parse-blueprint (string) - (bnd1 (nums (mapcar #'parse-integer (cl-ppcre:all-matches-as-strings "\\d+" string))) + (bnd1 (nums (extract-positive-integers string)) (make-blueprint :id (elt nums 0) :ore (subseq nums 1 2) :clay (subseq nums 2 3) diff --git a/src/2022/day19.lisp.6.part1 b/src/2022/day19.lisp.6.part1 index 55017a5..cb591f0 100644 --- a/src/2022/day19.lisp.6.part1 +++ b/src/2022/day19.lisp.6.part1 @@ -8,7 +8,7 @@ (destructuring-bind (id ore-robot-cost clay-robot-cost obsidian-robot-ore-cost obsidian-robot-clay-cost geode-robot-ore-cost geode-robot-obsidian-cost) - (mapcar #'parse-integer (cl-ppcre:all-matches-as-strings "\\d+" string)) + (extract-positive-integers string) (make-blueprint :id id :costs (list (list diff --git a/src/2022/day19.lisp.7 b/src/2022/day19.lisp.7 index ac42988..0e6c7c3 100644 --- a/src/2022/day19.lisp.7 +++ b/src/2022/day19.lisp.7 @@ -8,7 +8,7 @@ (destructuring-bind (id ore-robot-cost clay-robot-cost obsidian-robot-ore-cost obsidian-robot-clay-cost geode-robot-ore-cost geode-robot-obsidian-cost) - (mapcar #'parse-integer (cl-ppcre:all-matches-as-strings "\\d+" string)) + (extract-positive-integers string) (make-blueprint :id id :costs (list (list diff --git a/src/2022/day19.lisp.8 b/src/2022/day19.lisp.8 index 23aaa87..45de795 100644 --- a/src/2022/day19.lisp.8 +++ b/src/2022/day19.lisp.8 @@ -6,7 +6,7 @@ id ore clay obsidian geode) (defun parse-blueprint (string) - (bnd1 (nums (mapcar #'parse-integer (cl-ppcre:all-matches-as-strings "\\d+" string))) + (bnd1 (nums (extract-positive-integers string)) (make-blueprint :id (elt nums 0) :ore (subseq nums 1 2) :clay (subseq nums 2 3) diff --git a/src/2022/day22.lisp b/src/2022/day22.lisp index cc09e0f..a468f2d 100644 --- a/src/2022/day22.lisp +++ b/src/2022/day22.lisp @@ -45,7 +45,7 @@ :col-max col-max))) (defun parse-instructions (s) - (let ((steps (mapcar #'parse-integer (cl-ppcre:all-matches-as-strings "\\d+" s))) + (let ((steps (extract-positive-integers s)) (turns (cl-ppcre:all-matches-as-strings "[LR]" s))) (list steps turns))) diff --git a/src/2022/day22.lisp.part1 b/src/2022/day22.lisp.part1 index d34f68f..1968831 100644 --- a/src/2022/day22.lisp.part1 +++ b/src/2022/day22.lisp.part1 @@ -45,7 +45,7 @@ :col-max col-max))) (defun parse-instructions (s) - (let ((steps (mapcar #'parse-integer (cl-ppcre:all-matches-as-strings "\\d+" s))) + (let ((steps (extract-positive-integers s)) (turns (cl-ppcre:all-matches-as-strings "[LR]" s))) (list steps turns))) diff --git a/src/2022/day22.lisp.part2 b/src/2022/day22.lisp.part2 index cc09e0f..a468f2d 100644 --- a/src/2022/day22.lisp.part2 +++ b/src/2022/day22.lisp.part2 @@ -45,7 +45,7 @@ :col-max col-max))) (defun parse-instructions (s) - (let ((steps (mapcar #'parse-integer (cl-ppcre:all-matches-as-strings "\\d+" s))) + (let ((steps (extract-positive-integers s)) (turns (cl-ppcre:all-matches-as-strings "[LR]" s))) (list steps turns))) diff --git a/src/2023/day04.lisp b/src/2023/day04.lisp index 8c2b6e1..730a4ae 100644 --- a/src/2023/day04.lisp +++ b/src/2023/day04.lisp @@ -4,9 +4,9 @@ (defun winning-numbers (s) (bnd1 (numbers (second (split-sequence:split-sequence #\: s))) - (destructuring-bind (winning-numbers your-numbers) (split-sequence:split-sequence #\| numbers) - (intersection (mapcar #'parse-integer (cl-ppcre:all-matches-as-strings "\\d+" winning-numbers)) - (mapcar #'parse-integer (cl-ppcre:all-matches-as-strings "\\d+" your-numbers)))))) + (destructuring-bind (winning yours) (split-sequence:split-sequence #\| numbers) + (intersection (extract-positive-integers winning) + (extract-positive-integers yours))))) (defun card-points (s) (ash 1 (1- (length (winning-numbers s))))) #+#:excluded (card-points "Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53") diff --git a/src/utils.lisp b/src/utils.lisp index 5de41f8..6fd3d4b 100644 --- a/src/utils.lisp +++ b/src/utils.lisp @@ -812,6 +812,12 @@ "Return the first character of `string`" (char string 0)) +(defun extract-positive-integers (s) + (mapcar #'parse-integer (cl-ppcre:all-matches-as-strings "\\d+" s))) + +(defun extract-integers (s) + (mapcar #'parse-integer (cl-ppcre:all-matches-as-strings "-?\\d+" s))) + ;;;; Problems ----------------------------------------------------------------- (defmacro define-solution ((year day) (arg &optional (reader 'identity)) diff --git a/vendor/make-quickutils.lisp b/vendor/make-quickutils.lisp index c63919b..9e5005b 100644 --- a/vendor/make-quickutils.lisp +++ b/vendor/make-quickutils.lisp @@ -37,6 +37,7 @@ :symb :void :when-let + :while :with-gensyms ) diff --git a/vendor/quickutil b/vendor/quickutil deleted file mode 120000 index 466cd57..0000000 --- a/vendor/quickutil +++ /dev/null @@ -1 +0,0 @@ -/home/ubuntu/Workspace/quickutil \ No newline at end of file diff --git a/vendor/quickutils.lisp b/vendor/quickutils.lisp index 0d7ab38..b848e9e 100644 --- a/vendor/quickutils.lisp +++ b/vendor/quickutils.lisp @@ -2,7 +2,7 @@ ;;;; See http://quickutil.org for details. ;;;; To regenerate: -;;;; (qtlc:save-utils-as "quickutils.lisp" :utilities '(:AIF :AWHEN :BND* :BND1 :COPY-ARRAY :COPY-HASH-TABLE :DIGITS :DIVF :DOLIST+ :DORANGE :DORANGEI :DOSEQ :FLATTEN :HASH-TABLE-ALIST :HASH-TABLE-KEY-EXISTS-P :HASH-TABLE-KEYS :HASH-TABLE-VALUES :IF-LET :IOTA :LOOPING :MAKE-KEYWORD :MKSTR :MULF :NCYCLE :REPEAT :STRING-STARTS-WITH-P :SYMB :VOID :WHEN-LET :WITH-GENSYMS) :ensure-package T :package "AOC.QUICKUTILS") +;;;; (qtlc:save-utils-as "quickutils.lisp" :utilities '(:AIF :AWHEN :BND* :BND1 :COPY-ARRAY :COPY-HASH-TABLE :DIGITS :DIVF :DOLIST+ :DORANGE :DORANGEI :DOSEQ :FLATTEN :HASH-TABLE-ALIST :HASH-TABLE-KEY-EXISTS-P :HASH-TABLE-KEYS :HASH-TABLE-VALUES :IF-LET :IOTA :LOOPING :MAKE-KEYWORD :MKSTR :MULF :NCYCLE :REPEAT :STRING-STARTS-WITH-P :SYMB :VOID :WHEN-LET :WHILE :WITH-GENSYMS) :ensure-package T :package "AOC.QUICKUTILS") (eval-when (:compile-toplevel :load-toplevel :execute) (unless (find-package "AOC.QUICKUTILS") @@ -23,7 +23,8 @@ :MKSTR :SYMB :STRING-DESIGNATOR :WITH-GENSYMS :LOOPING :MAKE-KEYWORD :MULF :NCYCLE :REPEAT - :STRING-STARTS-WITH-P :VOID :WHEN-LET)))) + :STRING-STARTS-WITH-P :VOID :WHEN-LET + :WHILE)))) (defmacro let1 (var val &body body) "Bind VAR to VAL within BODY. Equivalent to LET with one binding." @@ -414,11 +415,11 @@ unique symbol the named variable will be bound to." (defmacro looping (&body body) - "Run `body` in an environment where the symbols COLLECT!, SUM!, and -COUNT! are bound to functions that can be used to collect, sum, or count things -respectively. + "Run `body` in an environment where the symbols COLLECT!, SUM!, COUNT!, MIN! +and MAX! are bound to functions that can be used to collect, sum, count, +minimize or maximize things respectively. -Mixed usage of COLLECT!, SUM!, and COUNT! is not supported +Mixed usage of COLLECT!, SUM!, COUNT!, MIN! and MAX! is not supported. Examples: @@ -474,9 +475,23 @@ Examples: (setf ,loop-type 'count! ,result 0)) (when item (incf ,result) - item))))) + item)))) + (,(symb "MIN!") (item) + (if (and ,loop-type (not (eql ,loop-type 'min!))) + (error "Cannot use MIN! together with ~A" ,loop-type) + (progn + (if (not ,loop-type) + (setf ,loop-type 'min! ,result item)) + (setf ,result (min ,result item))))) + (,(symb "MAX!") (item) + (if (and ,loop-type (not (eql ,loop-type 'max!))) + (error "Cannot use MAX! together with ~A" ,loop-type) + (progn + (if (not ,loop-type) + (setf ,loop-type 'max! ,result item)) + (setf ,result (max ,result item)))))) ,@body) - (if (eql ,loop-type 'collect!) + (if (eq ,loop-type 'collect!) (nreverse ,result) ,result)))) @@ -573,12 +588,18 @@ PROGN." (when ,(caar binding-list) ,@(bind (cdr binding-list) forms)))))) + + (defmacro while (expression &body body) + "Executes `body` while `expression` is true." + `(loop while ,expression do + ,@body)) + (eval-when (:compile-toplevel :load-toplevel :execute) (export '(aif awhen bnd* bnd1 copy-array copy-hash-table digits divf dolist+ dorange dorangei doseq flatten hash-table-alist hash-table-key-exists-p hash-table-keys hash-table-values if-let iota looping make-keyword mkstr mulf ncycle repeat - string-starts-with-p symb void when-let when-let* with-gensyms - with-unique-names))) + string-starts-with-p symb void when-let when-let* while + with-gensyms with-unique-names))) ;;;; END OF quickutils.lisp ;;;;