Fork of https://github.com/google/lisp-koans so that I could go through them. THIS CONTAINS ANSWERS.

contemplate.lsp 7.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. ;; Copyright 2013 Google Inc.
  2. ;;
  3. ;; Licensed under the Apache License, Version 2.0 (the "License");
  4. ;; you may not use this file except in compliance with the License.
  5. ;; You may obtain a copy of the License at
  6. ;;
  7. ;; http://www.apache.org/licenses/LICENSE-2.0
  8. ;;
  9. ;; Unless required by applicable law or agreed to in writing, software
  10. ;; distributed under the License is distributed on an "AS IS" BASIS,
  11. ;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. ;; See the License for the specific language governing permissions and
  13. ;; limitations under the License.
  14. (in-package :cl-user)
  15. ;; lisp-unit defines the modules for loading / executing koans
  16. (load "lisp-unit.lsp")
  17. (defpackage :lisp-koans
  18. (:use :common-lisp)
  19. (:use :lisp-unit)
  20. #+sbcl (:use :sb-ext))
  21. (in-package :lisp-koans)
  22. ;; .koans file controls which files in *koan-dir-name* are loaded as
  23. ;; koans to complete
  24. (defvar *koan-dir-name* "koans")
  25. (with-open-file (in #P".koans")
  26. (with-standard-io-syntax
  27. (defvar *all-koans-groups* (read in))))
  28. ;; set *print-koan-progress* to t to list all completed koans before summary
  29. (defvar *print-koan-progress* t)
  30. ;; debug-print directives
  31. (defvar *dp-loading* nil)
  32. ;; Global state used to hold results of loading and processing koans
  33. (defvar *n-total-koans* 0)
  34. (defvar *collected-results* nil)
  35. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  36. ;; Functions for loading koans ;;
  37. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  38. (defun load-koan-group-named (koan-group-name)
  39. ;; Creates a package for the koan-group based on koan-group-name.
  40. ;; Loads a lisp file at *koan-dir-name* / koan-group-name .lsp
  41. ;; Adds all the koans from that file to the package.
  42. (let ((koan-file-name (concatenate 'string (string-downcase (string koan-group-name)) ".lsp")))
  43. (if *dp-loading* (format t "start loading ~A ~%" koan-file-name))
  44. (in-package :lisp-koans)
  45. (unless (find-package koan-group-name)
  46. (make-package koan-group-name
  47. :use '(:common-lisp :lisp-unit #+sbcl :sb-ext)))
  48. (setf *package* (find-package koan-group-name))
  49. (load (concatenate 'string *koan-dir-name* "/" koan-file-name))
  50. (incf *n-total-koans* (length (list-tests)))
  51. (in-package :lisp-koans)
  52. (if *dp-loading* (format t "done loading ~A ~%" koan-file-name))))
  53. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  54. ;; Functions for executing koans ;;
  55. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  56. (defun run-koan-group-named (koan-group-name)
  57. ;; Executes the koan group, using run-koans defined in lisp-unit
  58. ;; returning a test-results object.
  59. (if *dp-loading* (format t "start running ~A ~%" koan-group-name))
  60. (run-koans koan-group-name))
  61. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  62. ;; Functions for printing progress ;;
  63. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  64. (defun print-one-koan-status (k-result)
  65. (let ((koan-name (first k-result))
  66. (all-pass-p (every
  67. #'(lambda (x) (equalp :pass x))
  68. (second k-result))))
  69. (if all-pass-p
  70. (format t "~A has expanded your awareness.~%" koan-name)
  71. (format t "~A requires more meditation.~%" koan-name))))
  72. (defun print-koan-group-progress (kg-name kg-results)
  73. (format t "~%Thinking about ~A~%" kg-name)
  74. (dolist (k-result (reverse kg-results))
  75. (format t " ")
  76. (print-one-koan-status k-result))
  77. (format t "~%"))
  78. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  79. ;; Functions for processing results ;;
  80. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  81. (defun any-assert-non-pass-p ()
  82. (dolist (k-group-result *collected-results*)
  83. (dolist (koan-result (second k-group-result))
  84. (dolist (one-assert (second koan-result))
  85. (if (not (equal one-assert :pass))
  86. (return-from any-assert-non-pass-p one-assert)))))
  87. nil)
  88. (defun get-error-filename (collected-results)
  89. (first (first (last collected-results))))
  90. (defun get-error-koan-name (collected-results)
  91. (first (first (second (first (last (last collected-results)))))))
  92. (defun get-error-koan-status (collected-results)
  93. (second (first (second (first (last (last collected-results)))))))
  94. (defun koan-status-message (koan-status)
  95. (if (find :incomplete koan-status)
  96. (return-from koan-status-message
  97. " A koan is incomplete.~%"))
  98. (if (find :fail koan-status)
  99. (return-from koan-status-message
  100. " A koan is incorrect.~%"))
  101. (if (find :error koan-status)
  102. (return-from koan-status-message
  103. " A koan threw an error.~%"))
  104. (format t " last koan status: ~A~%" koan-status)
  105. "")
  106. (defun print-next-suggestion-message ()
  107. (let ((filename (get-error-filename *collected-results*))
  108. (koan-name (get-error-koan-name *collected-results*))
  109. (koan-status (get-error-koan-status *collected-results*)))
  110. (format t "You have not yet reached enlightenment ...~%")
  111. (format t (koan-status-message koan-status))
  112. (format t "~%")
  113. (format t "Please meditate on the following code:~%")
  114. (format t " File \"~A/~A.lsp\"~%" *koan-dir-name* (string-downcase filename))
  115. (format t " Koan \"~A\"~%" koan-name)
  116. (format t " Current koan assert status is \"~A\"~%" (reverse koan-status))))
  117. (defun print-completion-message ()
  118. (format t "**********************************************************~%")
  119. (format t "That was the last one, well done! ENLIGHTENMENT IS YOURS!~%")
  120. (format t "**********************************************************~%~%")
  121. (format t "If you demand greater challenge, take a look at extra-credit.lsp~%")
  122. (format t "Or, let the student become the teacher:~%")
  123. (format t " Write and submit your own improvements to github.com/google/lisp-koans!~%"))
  124. (defun n-completed-koans (collected-results)
  125. (loop for kg in collected-results
  126. sum (length (second kg)) into partial-sum
  127. finally (return partial-sum)))
  128. (defun all-asserts-passed-in-koan-p (koan-result)
  129. (equal
  130. (length (second koan-result))
  131. (count :pass (second koan-result))))
  132. (defun n-passed-koans-in-group (kg)
  133. (loop for k in (second kg)
  134. counting (all-asserts-passed-in-koan-p k) into partial-sum
  135. finally (return partial-sum)))
  136. (defun n-passed-koans-overall (collected-results)
  137. (loop for kg in collected-results
  138. sum (n-passed-koans-in-group kg) into partial-sum
  139. finally (return partial-sum)))
  140. (defun print-progress-message ()
  141. (format t "You are now ~A/~A koans and ~A/~A lessons closer to reaching enlightenment~%~%"
  142. (n-passed-koans-overall *collected-results*)
  143. *n-total-koans*
  144. (- (length *collected-results*) 1)
  145. (length *all-koans-groups*)))
  146. ;;;;;;;;;;
  147. ;; Main ;;
  148. ;;;;;;;;;;
  149. ;; Load all the koans before testing any, and
  150. ;; count how many total koans there are.
  151. (loop for koan-group-name in *all-koans-groups*
  152. do
  153. (load-koan-group-named koan-group-name))
  154. ;; Run through the koans until reaching the end condition.
  155. ;; Store the results in *collected-results*
  156. (setf *collected-results*
  157. (loop for koan-group-name in *all-koans-groups*
  158. for kg-results = (run-koan-group-named koan-group-name)
  159. collect (list koan-group-name kg-results)
  160. do (if *print-koan-progress*
  161. (print-koan-group-progress koan-group-name kg-results))
  162. ;; *proceed-after-failure* is defined in lisp-unit
  163. until (and (not *proceed-after-failure*) (any-non-pass-p kg-results))))
  164. ;; Output advice to the learner
  165. (if (any-assert-non-pass-p)
  166. (progn
  167. (print-next-suggestion-message)
  168. (format t "~%")
  169. (print-progress-message))
  170. (print-completion-message))