# HG changeset patch
# User Steve Losh
# Date 1544912712 18000
# Node ID c19da8761e5752072bfbf856d95e855c6e938f51
# Parent 99fa06464617ebc7d2cad78be1ba63fb4907f86c
The Great Packaging
diff r 99fa06464617 r c19da8761e57 euler.asd
 a/euler.asd Tue Jul 31 16:18:33 2018 +0000
+++ b/euler.asd Sat Dec 15 17:25:12 2018 0500
@@ 1,3 +1,14 @@
+(defclass automodule (module) ())
+
+(defmethod componentchildren ((self automodule))
+ (mapcar (lambda (p) (makeinstance 'clsourcefile :type "lisp"
+ :pathname p
+ :name (pathnamename p)
+ :parent (componentparent self)))
+ (directoryfiles (componentpathname self)
+ (makepathname :directory nil :name *wild* :type "lisp"))))
+
+
(asdf:defsystem :euler
:name "euler"
:description "Project Euler solutions."
@@ 13,11 +24,11 @@
:1am
:anaphora
:clpcg
 :clstrings
:iterate
:localtime
:losh
:pileup
+ :str
)
@@ 32,5 +43,6 @@
(:file "utils")
(:file "hungarian")
(:file "problems")
 (:file "poker")))))
+ (:file "poker")
+ (:automodule "problems")))))
diff r 99fa06464617 r c19da8761e57 package.lisp
 a/package.lisp Tue Jul 31 16:18:33 2018 +0000
+++ b/package.lisp Sat Dec 15 17:25:12 2018 0500
@@ 1,12 +1,15 @@
(defpackage :euler
 (:use
 :cl
 :iterate
 :losh
 :euler.quickutils)
 (:importfrom :1am :is)
 (:shadowingimportfrom :1am :test)
 (:export :runtests))
+ (:use :cl :iterate :losh :euler.quickutils)
+ (:export
+ :*use*
+ :runtests
+
+ :defineproblem
+
+ :primefactorization
+ :irange
+
+ ))
(defpackage :euler.poker
(:use
@@ 18,11 +21,13 @@
:euler.quickutils))
(defpackage :euler.hungarian
 (:use
 :cl
 :iterate
 :losh
 :euler
 :euler.quickutils)
+ (:use :cl :euler :iterate :losh :euler.quickutils)
(:export
:findminimalassignment))
+
+(defparameter euler:*use* '(:use
+ :cl
+ :euler
+ :iterate
+ :losh
+ :euler.quickutils))
diff r 99fa06464617 r c19da8761e57 src/problems.lisp
 a/src/problems.lisp Tue Jul 31 16:18:33 2018 +0000
+++ b/src/problems.lisp Sat Dec 15 17:25:12 2018 0500
@@ 1,94 +1,5 @@
(inpackage :euler)
(defun problem1 ()
 ;; If we list all the natural numbers below 10 that are multiples of 3 or 5,
 ;; we get 3, 5, 6 and 9. The sum of these multiples is 23.
 ;;
 ;; Find the sum of all the multiples of 3 or 5 below 1000.
 (iterate (for i :from 1 :below 1000)
 (when (or (dividesp i 3)
 (dividesp i 5))
 (summing i))))

(defun problem2 ()
 ;; Each new term in the Fibonacci sequence is generated by adding the previous
 ;; two terms. By starting with 1 and 2, the first 10 terms will be:
 ;;
 ;; 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
 ;;
 ;; By considering the terms in the Fibonacci sequence whose values do not
 ;; exceed four million, find the sum of the evenvalued terms.
 (iterate (for n :infibonacci t)
 (while (<= n 4000000))
 (when (evenp n)
 (summing n))))

(defun problem3 ()
 ;; The prime factors of 13195 are 5, 7, 13 and 29.
 ;;
 ;; What is the largest prime factor of the number 600851475143?
 (apply #'max (primefactorization 600851475143)))

(defun problem4 ()
 ;; A palindromic number reads the same both ways. The largest palindrome made
 ;; from the product of two 2digit numbers is 9009 = 91 × 99.
 ;;
 ;; Find the largest palindrome made from the product of two 3digit numbers.
 (iterate
 ;; We COULD brute force this, but it's more fun to do it smartly.
 (with result = 0)
 (for i :from 999 :downto 100)
 (iterate (for j :from i :downto 100)
 (for product = (* i j))
 ;; Because we're counting down, we can break in this inner loop as
 ;; soon as our products drop below the current maximum.
 (while (>= product (or result 0)))
 (when (palindromep product)
 (setf result product)))
 (finally (return result))))

(defun problem5 ()
 ;; 2520 is the smallest number that can be divided by each of the numbers from
 ;; 1 to 10 without any remainder.
 ;;
 ;; What is the smallest positive number that is evenly divisible by all of the
 ;; numbers from 1 to 20?
 (iterate
 ;; all numbers are divisible by 1 and we can skip checking everything <= 10
 ;; because:
 ;;
 ;; anything divisible by 12 is automatically divisible by 2
 ;; anything divisible by 12 is automatically divisible by 3
 ;; anything divisible by 12 is automatically divisible by 4
 ;; anything divisible by 15 is automatically divisible by 5
 ;; anything divisible by 12 is automatically divisible by 6
 ;; anything divisible by 14 is automatically divisible by 7
 ;; anything divisible by 16 is automatically divisible by 8
 ;; anything divisible by 18 is automatically divisible by 9
 ;; anything divisible by 20 is automatically divisible by 10
 (with divisors = (range 11 20))
 (for i :from 20 :by 20) ; it must be divisible by 20
 (finding i :suchthat (every (curry #'dividesp i) divisors))))

(defun problem6 ()
 ;; The sum of the squares of the first ten natural numbers is,
 ;; 1² + 2² + ... + 10² = 385
 ;;
 ;; The square of the sum of the first ten natural numbers is,
 ;; (1 + 2 + ... + 10)² = 55² = 3025
 ;;
 ;; Hence the difference between the sum of the squares of the first ten
 ;; natural numbers and the square of the sum is 3025 − 385 = 2640.
 ;;
 ;; Find the difference between the sum of the squares of the first one hundred
 ;; natural numbers and the square of the sum.
 (flet ((sumofsquares (to)
 (summation (irange 1 to :key #'square)))
 (squareofsum (to)
 (square (summation (irange 1 to)))))
 (abs ( (sumofsquares 100) ; apparently it wants the absolute value
 (squareofsum 100)))))

(defun problem7 ()
;; By listing the first six prime numbers: 2, 3, 5, 7, 11, and 13, we can see
;; that the 6th prime is 13.
@@ 1157,7 +1068,7 @@
;; How many hands does Player 1 win?
(iterate (for line :infile "data/054poker.txt" :using #'readline)
(for cards = (mapcar #'euler.poker::parsecard
 (clstrings:split line #\space)))
+ (str:split #\space line)))
(for p1 = (take 5 cards))
(for p2 = (drop 5 cards))
(counting (euler.poker::pokerhandbeatsp p1 p2))))
@@ 1300,7 +1211,7 @@
readallfromstring))
(rawwords (<> "/usr/share/dict/words"
readfileintostring
 (clstrings:split <> #\newline)
+ (str:split #\newline <>)
(mapcar #'stringdowncase <>)))
(words (makehashset :test 'equal :initialcontents rawwords)))
(labels
@@ 1314,7 +1225,7 @@
(<> (applycipher keyword)
(stringify <>)
(stringdowncase <>)
 (clstrings:split <>)
+ (str:words <>)
(removeifnot (curry #'hsetcontainsp words) <>)
length))
(answer (keyword)
@@ 2300,12 +2211,6 @@
;;;; Tests 
(test p1 (is (= 233168 (problem1))))
(test p2 (is (= 4613732 (problem2))))
(test p3 (is (= 6857 (problem3))))
(test p4 (is (= 906609 (problem4))))
(test p5 (is (= 232792560 (problem5))))
(test p6 (is (= 25164150 (problem6))))
(test p7 (is (= 104743 (problem7))))
(test p8 (is (= 23514624000 (problem8))))
(test p9 (is (= 31875000 (problem9))))
diff r 99fa06464617 r c19da8761e57 src/problems/001.lisp
 /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/problems/001.lisp Sat Dec 15 17:25:12 2018 0500
@@ 0,0 +1,14 @@
+(defpackage :euler/001 #.euler:*use*)
+(inpackage :euler/001)
+
+;; If we list all the natural numbers below 10 that are multiples of 3 or 5, we
+;; get 3, 5, 6 and 9. The sum of these multiples is 23.
+;;
+;; Find the sum of all the multiples of 3 or 5 below 1000.
+
+(defineproblem (1 233168)
+ (iterate (for i :from 1 :below 1000)
+ (when (or (dividesp i 3)
+ (dividesp i 5))
+ (summing i))))
+
diff r 99fa06464617 r c19da8761e57 src/problems/002.lisp
 /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/problems/002.lisp Sat Dec 15 17:25:12 2018 0500
@@ 0,0 +1,17 @@
+(defpackage :euler/002 #.euler:*use*)
+(inpackage :euler/002)
+
+;; Each new term in the Fibonacci sequence is generated by adding the previous
+;; two terms. By starting with 1 and 2, the first 10 terms will be:
+;;
+;; 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
+;;
+;; By considering the terms in the Fibonacci sequence whose values do not exceed
+;; four million, find the sum of the evenvalued terms.
+
+(defineproblem (2 4613732)
+ (iterate (for n :infibonacci t)
+ (while (<= n 4000000))
+ (when (evenp n)
+ (summing n))))
+
diff r 99fa06464617 r c19da8761e57 src/problems/003.lisp
 /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/problems/003.lisp Sat Dec 15 17:25:12 2018 0500
@@ 0,0 +1,10 @@
+(defpackage :euler/003 #.euler:*use*)
+(inpackage :euler/003)
+
+;; The prime factors of 13195 are 5, 7, 13 and 29.
+;;
+;; What is the largest prime factor of the number 600851475143?
+
+(defineproblem (3 6857)
+ (apply #'max (primefactorization 600851475143)))
+
diff r 99fa06464617 r c19da8761e57 src/problems/004.lisp
 /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/problems/004.lisp Sat Dec 15 17:25:12 2018 0500
@@ 0,0 +1,23 @@
+(defpackage :euler/004 #.euler:*use*)
+(inpackage :euler/004)
+
+;; A palindromic number reads the same both ways. The largest palindrome made
+;; from the product of two 2digit numbers is 9009 = 91 × 99.
+;;
+;; Find the largest palindrome made from the product of two 3digit numbers.
+
+(defineproblem (4 906609)
+ (iterate
+ ;; We COULD brute force this, but it's more fun to do it smartly.
+ (with result = 0)
+ (for i :from 999 :downto 100)
+ (iterate (for j :from i :downto 100)
+ (for product = (* i j))
+ ;; Because we're counting down, we can break in this inner loop as
+ ;; soon as our products drop below the current maximum.
+ (while (>= product (or result 0)))
+ (when (palindromep product)
+ (setf result product)))
+ (finally (return result))))
+
+
diff r 99fa06464617 r c19da8761e57 src/problems/005.lisp
 /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/problems/005.lisp Sat Dec 15 17:25:12 2018 0500
@@ 0,0 +1,27 @@
+(defpackage :euler/005 #.euler:*use*)
+(inpackage :euler/005)
+
+
+;; 2520 is the smallest number that can be divided by each of the numbers from
+;; 1 to 10 without any remainder.
+;;
+;; What is the smallest positive number that is evenly divisible by all of the
+;; numbers from 1 to 20?
+
+(defineproblem (5 232792560)
+ (iterate
+ ;; all numbers are divisible by 1 and we can skip checking everything <= 10
+ ;; because:
+ ;;
+ ;; anything divisible by 12 is automatically divisible by 2
+ ;; anything divisible by 12 is automatically divisible by 3
+ ;; anything divisible by 12 is automatically divisible by 4
+ ;; anything divisible by 15 is automatically divisible by 5
+ ;; anything divisible by 12 is automatically divisible by 6
+ ;; anything divisible by 14 is automatically divisible by 7
+ ;; anything divisible by 16 is automatically divisible by 8
+ ;; anything divisible by 18 is automatically divisible by 9
+ ;; anything divisible by 20 is automatically divisible by 10
+ (with divisors = (range 11 20))
+ (for i :from 20 :by 20) ; it must be divisible by 20
+ (finding i :suchthat (every (curry #'dividesp i) divisors))))
diff r 99fa06464617 r c19da8761e57 src/problems/006.lisp
 /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/problems/006.lisp Sat Dec 15 17:25:12 2018 0500
@@ 0,0 +1,25 @@
+(defpackage :euler/006 #.euler:*use*)
+(inpackage :euler/006)
+
+;; The sum of the squares of the first ten natural numbers is,
+;; 1² + 2² + ... + 10² = 385
+;;
+;; The square of the sum of the first ten natural numbers is,
+;; (1 + 2 + ... + 10)² = 55² = 3025
+;;
+;; Hence the difference between the sum of the squares of the first ten natural
+;; numbers and the square of the sum is 3025 − 385 = 2640.
+;;
+;; Find the difference between the sum of the squares of the first one hundred
+;; natural numbers and the square of the sum.
+
+(defineproblem (6 25164150)
+ (flet ((sumofsquares (to)
+ (summation (irange 1 to) :key #'square))
+ (squareofsum (to)
+ (square (summation (irange 1 to)))))
+ (abs ( (sumofsquares 100) ; apparently it wants the absolute value
+ (squareofsum 100)))))
+
+
+
diff r 99fa06464617 r c19da8761e57 src/utils.lisp
 a/src/utils.lisp Tue Jul 31 16:18:33 2018 +0000
+++ b/src/utils.lisp Sat Dec 15 17:25:12 2018 0500
@@ 1,5 +1,19 @@
(inpackage :euler)
+;;;; Problems 
+(defun runtests ()
+ (1am:run))
+
+(defmacro defineproblem ((number &optional solution) &body body)
+ (let ((name (symb 'problem number)))
+ `(progn
+ (defun ,name () ,@body)
+ ,@(when solution
+ `((1am:test ,(symb 'test name)
+ (1am:is (= ,solution (,name))))))
+ ',name)))
+
+
;;;; Iterate 
(defmacrodriver (FOR var ITERATING function SEED value &optional
INCLUDESEED includeseed?)
@@ 164,7 +178,7 @@
,line%)
(parseline (l)
(map ,resulttype% ,key%
 (clstrings:split l ,delimiter%))))
+ (str:split ,delimiter% l))))
(,kwd ,var :next (parseline (nextline))))))))
@@ 781,8 +795,6 @@
(definemodifymacro adjoinf (item &rest keywordargs) adjoin%)


(defun pythagoreantripletp (a b c)
(math a ^ 2 + b ^ 2 = c ^ 2))
@@ 974,7 +986,6 @@
(* precision (round number precision)))

;;;; A* Search 
(defstruct path
state
diff r 99fa06464617 r c19da8761e57 vendor/makequickutils.lisp
 a/vendor/makequickutils.lisp Tue Jul 31 16:18:33 2018 +0000
+++ b/vendor/makequickutils.lisp Sat Dec 15 17:25:12 2018 0500
@@ 23,6 +23,7 @@
:readfileintostring
:removef
:switch
+ :symb
:withgensyms
)
diff r 99fa06464617 r c19da8761e57 vendor/quickutils.lisp
 a/vendor/quickutils.lisp Tue Jul 31 16:18:33 2018 +0000
+++ b/vendor/quickutils.lisp Sat Dec 15 17:25:12 2018 0500
@@ 2,7 +2,7 @@
;;;; See http://quickutil.org for details.
;;;; To regenerate:
;;;; (qtlc:saveutilsas "quickutils.lisp" :utilities '(:COMPOSE :COPYARRAY :CURRY :DEFINECONSTANT :EMPTYP :ENSUREBOOLEAN :ENSUREFUNCTION :ENSUREGETHASH :EQUIVALENCECLASSES :MAPCOMBINATIONS :MAPPERMUTATIONS :MAXF :MINF :NGRAMS :RANGE :RCURRY :READFILEINTOSTRING :REMOVEF :SWITCH :WITHGENSYMS) :ensurepackage T :package "EULER.QUICKUTILS")
+;;;; (qtlc:saveutilsas "quickutils.lisp" :utilities '(:COMPOSE :COPYARRAY :CURRY :DEFINECONSTANT :EMPTYP :ENSUREBOOLEAN :ENSUREFUNCTION :ENSUREGETHASH :EQUIVALENCECLASSES :MAPCOMBINATIONS :MAPPERMUTATIONS :MAXF :MINF :NGRAMS :RANGE :RCURRY :READFILEINTOSTRING :REMOVEF :SWITCH :SYMB :WITHGENSYMS) :ensurepackage T :package "EULER.QUICKUTILS")
(evalwhen (:compiletoplevel :loadtoplevel :execute)
(unless (findpackage "EULER.QUICKUTILS")
@@ 23,7 +23,8 @@
:WITHOPENFILE* :WITHINPUTFROMFILE
:READFILEINTOSTRING :REMOVEF
:STRINGDESIGNATOR :WITHGENSYMS
 :EXTRACTFUNCTIONNAME :SWITCH))))
+ :EXTRACTFUNCTIONNAME :SWITCH :MKSTR
+ :SYMB))))
(evalwhen (:compiletoplevel :loadtoplevel :execute)
(defun makegensymlist (length &optional (x "G"))
"Returns a list of `length` gensyms, each generated as if with a call to `makegensym`,
@@ 543,11 +544,28 @@
"Like `switch`, but signals a continuable error if no key matches."
(generateswitchbody whole object clauses test key '(cerror "Return NIL from CSWITCH.")))
+
+ (defun mkstr (&rest args)
+ "Receives any number of objects (string, symbol, keyword, char, number), extracts all printed representations, and concatenates them all into one string.
+
+Extracted from _On Lisp_, chapter 4."
+ (withoutputtostring (s)
+ (dolist (a args) (princ a s))))
+
+
+ (defun symb (&rest args)
+ "Receives any number of objects, concatenates all into one string with `#'mkstr` and converts them to symbol.
+
+Extracted from _On Lisp_, chapter 4.
+
+See also: `symbolicate`"
+ (values (intern (apply #'mkstr args))))
+
(evalwhen (:compiletoplevel :loadtoplevel :execute)
(export '(compose copyarray curry defineconstant emptyp ensureboolean
ensurefunction ensuregethash equivalenceclasses mapcombinations
mappermutations maxf minf ngrams range rcurry
 readfileintostring removef switch eswitch cswitch withgensyms
 withuniquenames)))
+ readfileintostring removef switch eswitch cswitch symb
+ withgensyms withuniquenames)))
;;;; END OF quickutils.lisp ;;;;