Lisp Programs For Beginners

I saw the InteractiveFiction project over in CeeProgramsForBeginners and, seeing some of the code there, was reminded why I have been learning lisp. I wrote an alternative version. It's about the same size, more readability, and has more functionality, and even some syntactic sugar. :)

I've added comments to the code, which should hopefully kind of explain what's going on. Abandon all hope of totally understanding the "Loop" statements until you've played with it a bunch. It's a great tool and I like the resulting code, but it's actually a complete sublanguage.

 ;; We define a "struct", which is like a C struct, for the rooms. Note that there
 ;; Are default values which can be used if we omit one from construction. 

(defstruct my-room (desc "An empty room.") ;; The exits will be a list of lists, what lispniks call an "assoc-list" ;; like so: ( (north room1) (south room2) ) ;; Think of it as a kind of simple tree. (exits ()))

;; This function does the work of "displaying" a room. ;; It shows a room, its exits, ;; and then waits for the user to type in a valid exit. ;; The Lisp reader is what we use, ;; which means we can do some funny things.

(defun run-room (loc) ;; Firstly, we fetch the fields "name" and "exits" from the room structure. (let ( (desc (my-room-desc loc)) (exits (my-room-exits loc)) )

;; Format is Lisp's printf, with all that entails. This prints out the room ;; description and then prints out a line "Exits:" (format t "~%~a~%~%Exits:~%" desc)

;; Dolist does just what it sounds like. It does the statement for each ;; member of the list in "exits". In this case, it displays the name of each ;; exit on its own line (dolist (x exits) (format t "~a~%" (first x)))

;; Then we print a prompt (format t "~%> ")

;; We use LOOP here, instead of the more obtuse do macro. The general idea ;; is to keep reading from input, letting lisp do the parsing. ;; We check if the input is a valid exit (if it exists in the assoc list) ;; and if so we return the SYMBOL that is in the next result. So we'd return ;; the NAME "forestroom" instead of the actual instance forestroom. This is ;; only to make things more convenient. (loop for dir = (read) for arc = (assoc dir exits) when arc do (return (second arc)) else do (format t "You cannot go ~a~%> " dir)))))

;; This function actually starts the maze. You just say (run-maze room1) or whatever ;; It is another loop. All it does is keep looping over rooms, making sure that if ;; the symbol "DONE" is ever returned, to terminate the loop. This means the maze can ;; actually end. :)

;; The "symbol-value" means "get the value at the symbol", which is pretty useful here ;; since it means that rooms don't depend on each other, only on symbols which lisp provides. (defun run-maze (start) (loop for next = (run-room start) then (run-room (symbol-value next)) while (not (eq next 'done))))

;; This is a macro, which means fancy syntactic sugar. All it does is ;; make it so that our room definitions can look pretty, and can safely ;; be ignored. (defmacro def-room (name desc &rest exit-pairs) `(defvar ,name (make-my-room :desc ,desc :exits ',exit-pairs)))

;; The example dungeon from the C page, with some slight changes.

;; Our macro makes our room definitions very pretty. ;; Note that we refer to rooms by name ;; without caring if they are made yet or not. ;; This is because we refer to them symbolically, ;; and run-maze is wise to this ;; and understands to look up the value at the symbol. ;; That kind of coding is one of the real benefits of lisp's approach.

(def-room footpath "You are on a footpath. You can see a forest to the north." (north forest) (south stream-room))

(def-room forest "You are in a forest. You can hear water running to the south." (north clearing) (south footpath) (east trees))

;; A bonus room ;) (def-room trees "You are in a forest, but you can't see it because of the trees." (west forest) (east footpath))

(def-room clearing "The forest thins to a clearing. There is a strange radiance north." (north circle) (south forest))

(def-room circle "There is a circle of little pixies here. They glow. Like fire." (south forest) (circle endgame))

(def-room stream-room "You are next to a stream. You can see a bridge to the west." (west bridge) (north footpath))

(def-room bridge "A tiny bridge leading to the southern fort. The path goes east." (east stream-room) (south fort))

(def-room fort "You have reached your little fort. It is empty save for your bed." (bed endgame) (north bridge))

(def-room endgame "There. You've finished the game. Gratz!" (done done))

#| ;; Example call: (run-maze footpath) |#

This was a surprisingly fun little thing that I took a while to write. I had something done real quick but I didn't like the simple way that the C program handled input, so I tweaked it a little and did some basic validation. I feel a lot better about using LOOP now. :)

Maybe this page could start a trend, something like *X* Programs for Beginners. The same simple programs implemented in many languages with the intent of educating beginners. DaveThomas made some excellent CodeKata pages for these kinds of exercises.

[For the above to be really useful to non-lispers, explanatory notes should be added to explain what is done, and also why. BTW, I quite liked the revised messages.]

That's all I have time for at the moment. This is rather out-of-context, I should make supporting examples. It was more that I saw the text adventure program and had a little fun. -- DaveFayram

You Lispers seem to be having fun with this, so how about a request for something a little more applicable for someone in the .Net world. How about doing a simple lisp program that connects to a SqlServer database and spits out the results of a query to a single web page, with maybe a little processing of the result to show off a few cool lisp features? Nothing too fancy, just enough to maybe get someone up and running in the windows world with Sql. I know it'd give me some incentive to try some sample projects in lisp if I could use it in my current environment, I'm sure others feel the same.

I'd be willing, but not on this page, which is divergent. Perhaps PracticalLispExamples? or some other such titled page. It'd be a nice opportunity for me to play with the cl database libraries at common-lisp.net. But your idea a bit under-specified. Could you be more specific? Preferably at my home page? -- DaveFayram

SQL examples can easily be found in tutorials from the major Lisp vendors like Franz Allegro and Xanalys LispWorks who make their products easily available for evaluation and learning (compared with players like Microsoft or Borland they are really to be appreciated for their no-hassle try-out policy ), but on the other hand it is non-standard. See for example http://www.lispworks.com/reference/lw43/LWUG/html/lwuser-179.htm#pgfId-886165

Speaking as somebody with some experience in database application, and experience with ADO.NET, Lisp based data access is a breeeze. The language itself is so much more conducive of good design for frameworks.


CategoryLisp CategoryExample CategoryInManyProgrammingLanguages


EditText of this page (last edited June 24, 2004) or FindPage with title or text search