project-euler/shared.lisp

94 lines
2.8 KiB
Common Lisp

(defmacro ret ((variable value) &body body)
`(let ((,variable ,value))
,@body
,variable))
(defmacro with-gensyms ((&rest names) &body body)
`(let ,(loop for name in names collect `(,name (gensym)))
,@body))
(defmacro -> (start &rest rest)
(loop with result = start
for (head . tail) in rest
do (setf result (cons head (cons result tail)))
finally (return result)))
(defmacro ->> (start &rest rest)
(loop with result = start
for form in rest
do (setf result (append form (list result)))
finally (return result)))
(defmacro as-> (start symbol &rest rest)
(loop with result = start
for form in rest
do (setf result (substitute result symbol form))
finally (return result)))
(defmacro multf (place multiplier)
`(setf ,place (* ,place ,multiplier)))
(defun get-primes (max)
"Return a list of the first primes up to MAX"
(let ((primes nil)
(composites (make-array (1+ max) :initial-element 0)))
(loop for n from 2 upto max
do (when (= 0 (aref composites n))
(push n primes)
(loop for m from (* 2 n) upto max by n
do (incf (aref composites m)))))
(nreverse primes)))
(defun read-matrix-from-file (path)
"Reads a two-dimensional array of integers into a matrix (2D array), from PATH"
(let* ((list (mapcar (lambda (line)
(mapcar #'parse-integer
(uiop:split-string line :separator '(#\,))))
(uiop:read-file-lines path)))
(array (make-array (list (length list) (length (first list))))))
(loop for i upfrom 0
for row in list
do (loop for j upfrom 0
for value in row
do (setf (aref array i j) value)))
array))
(defun in-bounds-p (i max)
"Returns non-NIL if I is on the interval [0, MAX)"
(and (>= i 0)
(< i max)))
(defun factorial (n)
(ret (product 1)
(loop for x from n above 1 do
(multf product x))))
(defun n-choose-r (n r)
(/ (factorial n)
(* (factorial r) (factorial (- n r)))))
(defun divisiblep (n divisor)
"Returns non-NIL when N is divisible by DIVISOR"
(= 0 (mod n divisor)))
(defun remove-index (index sequence)
"Returns a new list that is a copy of SEQUENCE with the item at INDEX removed"
(loop for i upfrom 0
for item in sequence
unless (= i index) collect item))
(defun for-each-permutation (f a &optional tail)
"Calls F on each permutation of sequence A, optionally consed onto TAIL"
(cond ((null a) (funcall f tail))
(t (loop with length = (length a)
for i from 0 below length
for remaining = (remove-index i a)
do (for-each-permutation f remaining (cons (elt a i) tail))))))
(defun for-each-combination (function list n)
(labels ((recurse (list n set)
(cond ((zerop n) (funcall function set))
(t (loop for (item . rest) on list do
(recurse rest (1- n) (cons item set)))))))
(recurse list n nil)))