Created
November 3, 2016 22:38
-
-
Save spacebat/3265d66170a600e717681d674bb56c37 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(defpackage :99-bottles | |
(:use :cl) | |
(:export #:print-song)) | |
(in-package :99-bottles) | |
(defun wrap (number) | |
(if (minusp number) | |
(+ number 100) | |
number)) | |
(defclass verse () | |
((iteration | |
:initarg :iteration | |
:initform (error ":iteration required") | |
:accessor iteration))) | |
(defmethod initialize-instance :after ((verse verse) &key) | |
(check-type (iteration verse) integer) | |
(setf (iteration verse) (wrap (iteration verse)))) | |
(defun get-verse (&optional (iteration 99)) | |
(check-type iteration integer) | |
(make-instance 'verse :iteration iteration)) | |
(defgeneric quantifier (verse) | |
(:method ((verse verse)) | |
(quantifier (iteration verse))) | |
(:method ((number (eql 0))) | |
"no more bottles") | |
(:method ((number integer)) | |
(format nil "~R bottle~:*~P" (wrap number)))) | |
(defgeneric action (verse) | |
(:method ((verse verse)) | |
(action (iteration verse))) | |
(:method ((number (eql 0))) | |
"Go to the store and buy some more") | |
(:method ((number integer)) | |
"Take one down and pass it around")) | |
(defgeneric next-verse (verse) | |
(:method ((verse verse)) | |
(next-verse (iteration verse))) | |
(:method ((number (eql 0))) | |
nil) | |
(:method ((number integer)) | |
(get-verse (- number 1)))) | |
(defmethod print-object ((verse verse) stream) | |
(flet ((print-verse () | |
(format stream "~%~@(~A~) of beer on the wall, ~:*~A of beer.~%~A, ~A of beer on the wall.~%" | |
(quantifier verse) | |
(action verse) | |
(quantifier (- (iteration verse) 1))))) | |
(if *print-escape* | |
(print-unreadable-object (verse stream :type t) | |
(print-verse)) | |
(print-verse)))) | |
(defun print-song (&optional (start 99) (stream t)) | |
"Print to STREAM a sequence of verses of the song 99 Bottles of | |
Beer, starting at cardinal START." | |
(loop for verse = (get-verse start) then (next-verse verse) | |
while verse | |
do (princ verse stream))) | |
;; CL-USER> (99-bottles:print-song 2) | |
;; Two bottles of beer on the wall, two bottles of beer. | |
;; Take one down and pass it around, one bottle of beer on the wall. | |
;; One bottle of beer on the wall, one bottle of beer. | |
;; Take one down and pass it around, no more bottles of beer on the wall. | |
;; No more bottles of beer on the wall, no more bottles of beer. | |
;; Go to the store and buy some more, ninety-nine bottles of beer on the wall. | |
;; NIL |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment