Skip to content

Instantly share code, notes, and snippets.

@spacebat
Created November 3, 2016 22:38
Show Gist options
  • Save spacebat/3265d66170a600e717681d674bb56c37 to your computer and use it in GitHub Desktop.
Save spacebat/3265d66170a600e717681d674bb56c37 to your computer and use it in GitHub Desktop.
(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