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

contemplate.lsp 7.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  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. (: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. (make-package koan-group-name
  46. :use '(:common-lisp :lisp-unit :sb-ext))
  47. (setf *package* (find-package koan-group-name))
  48. (load (concatenate 'string *koan-dir-name* "/" koan-file-name))
  49. (incf *n-total-koans* (length (list-tests)))
  50. (in-package :lisp-koans)
  51. (if *dp-loading* (format t "done loading ~A ~%" koan-file-name))))
  52. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  53. ;; Functions for executing koans ;;
  54. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  55. (defun run-koan-group-named (koan-group-name)
  56. ;; Executes the koan group, using run-koans defined in lisp-unit
  57. ;; returning a test-results object.
  58. (if *dp-loading* (format t "start running ~A ~%" koan-group-name))
  59. (run-koans koan-group-name))
  60. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  61. ;; Functions for printing progress ;;
  62. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  63. (defun print-one-koan-status (k-result)
  64. (let ((koan-name (first k-result))
  65. (all-pass-p (every
  66. #'(lambda (x) (equalp :pass x))
  67. (second k-result))))
  68. (if all-pass-p
  69. (format t "~A has expanded your awareness.~%" koan-name)
  70. (format t "~A has damaged your karma.~%" koan-name))))
  71. (defun print-koan-group-progress (kg-name kg-results)
  72. (format t "~%Thinking about ~A~%" kg-name)
  73. (dolist (k-result (reverse kg-results))
  74. (format t " ")
  75. (print-one-koan-status k-result))
  76. (format t "~%"))
  77. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  78. ;; Functions for processing results ;;
  79. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  80. (defun any-assert-non-pass-p ()
  81. (dolist (k-group-result *collected-results*)
  82. (dolist (koan-result (second k-group-result))
  83. (dolist (one-assert (second koan-result))
  84. (if (not (equal one-assert :pass))
  85. (return-from any-assert-non-pass-p one-assert)))))
  86. nil)
  87. (defun get-error-filename (collected-results)
  88. (first (first (last collected-results))))
  89. (defun get-error-koan-name (collected-results)
  90. (first (first (second (first (last (last collected-results)))))))
  91. (defun get-error-koan-status (collected-results)
  92. (second (first (second (first (last (last collected-results)))))))
  93. (defun koan-status-message (koan-status)
  94. (if (find :incomplete koan-status)
  95. (return-from koan-status-message
  96. " A koan is incomplete.~%"))
  97. (if (find :fail koan-status)
  98. (return-from koan-status-message
  99. " A koan is incorrect.~%"))
  100. (if (find :error koan-status)
  101. (return-from koan-status-message
  102. " A koan threw an error.~%"))
  103. (format t " last koan status: ~A~%" koan-status)
  104. "")
  105. (defun print-next-suggestion-message ()
  106. (let ((filename (get-error-filename *collected-results*))
  107. (koan-name (get-error-koan-name *collected-results*))
  108. (koan-status (get-error-koan-status *collected-results*)))
  109. (format t "You have not yet reached enlightenment ...~%")
  110. (format t (koan-status-message koan-status))
  111. (format t "~%")
  112. (format t "Please meditate on the following code:~%")
  113. (format t " File \"~A/~A.lsp\"~%" *koan-dir-name* (string-downcase filename))
  114. (format t " Koan \"~A\"~%" koan-name)
  115. (format t " Current koan assert status is \"~A\"~%" (reverse koan-status))))
  116. (defun print-completion-message ()
  117. (format t "That was the last one, well done!~%")
  118. (format t "If you want more, take a look at extra-credit.lsp~%"))
  119. (defun n-completed-koans (collected-results)
  120. (loop for kg in collected-results
  121. sum (length (second kg)) into partial-sum
  122. finally (return partial-sum)))
  123. (defun all-asserts-passed-in-koan-p (koan-result)
  124. (equal
  125. (length (second koan-result))
  126. (count :pass (second koan-result))))
  127. (defun n-passed-koans-in-group (kg)
  128. (loop for k in (second kg)
  129. counting (all-asserts-passed-in-koan-p k) into partial-sum
  130. finally (return partial-sum)))
  131. (defun n-passed-koans-overall (collected-results)
  132. (loop for kg in collected-results
  133. sum (n-passed-koans-in-group kg) into partial-sum
  134. finally (return partial-sum)))
  135. (defun print-progress-message ()
  136. (format t "You are now ~A/~A koans and ~A/~A lessons away from reaching enlightenment~%~%"
  137. (n-passed-koans-overall *collected-results*)
  138. *n-total-koans*
  139. (- (length *collected-results*) 1)
  140. (length *all-koans-groups*)))
  141. ;;;;;;;;;;
  142. ;; Main ;;
  143. ;;;;;;;;;;
  144. ;; Load all the koans before testing any, and
  145. ;; count how many total koans there are.
  146. (loop for koan-group-name in *all-koans-groups*
  147. do
  148. (load-koan-group-named koan-group-name))
  149. ;; Run through the koans until reaching the end condition.
  150. ;; Store the results in *collected-results*
  151. (setf *collected-results*
  152. (loop for koan-group-name in *all-koans-groups*
  153. for kg-results = (run-koan-group-named koan-group-name)
  154. collect (list koan-group-name kg-results)
  155. do (if *print-koan-progress*
  156. (print-koan-group-progress koan-group-name kg-results))
  157. ;; *proceed-after-failure* is defined in lisp-unit
  158. until (and (not *proceed-after-failure*) (any-non-pass-p kg-results))))
  159. ;; Output advice to the learner
  160. (if (any-assert-non-pass-p)
  161. (progn
  162. (print-next-suggestion-message)
  163. (format t "~%")
  164. (print-progress-message))
  165. (print-completion-message))