Since I already know how to turn lead into gold, I did my
wizard game (and then items) implementations before reading
Land of Lisp's sections thereon, though the
non-time-reversed order is advisable. Here I will compare
what I did to what Land of Lisp did.
We both program in a lispy way. Compare my
(mapcar 'car (cddr *room*))
and the example
(mapcar #'car '((foo bar) (baz qux)))
or Land of Lisp's
(eq (cadr (assoc obj obj-locs)) loc)
to
(assoc edge (cddr *room*))
And so forth.
The biggest difference, already visible above is that I
decided to use a circular list where the head of the single
special list is the current location, and the details of
each location are all literally at that location, whereas
Land of Lisp used multiple special lists with #'ASSOC in a
relational way. Relational means that I can get a key from
list-1 that can be used to #'ASSOC an item in list-2.
(Imagine join(1) in shell, or mariadb / sqlite).
My single-list advantage is that we can inspect the
(sufficiently small) world, or just nearby entries of a
larger world
> *ROOMS*
#1=(CURRENT (LIVING-ROOM LAMP) (LADDER (ATTIC APPLE ORANGE) #1#)
(DOOR (GARDEN) #1#))
and lexically reason that (cdadr *rooms*) will be a SETFable
reference to the list that is the items at the current
location, (LAMP) in this case and that (caadr *rooms*) is
the name of the current location. symmetrically I think it's
clear to work out what (assoc 'door (cddr *rooms*)) is going
to return. On the other hand this also constrains me to not
making references that reach too far or would be hard to
work out. In Common Lisp, only up to 4 Ds and As come as
built-in functions. (cddddr '(1 2 3 4 5)) -> (5) but
#'cdddddr is not defined.
On the other hand, the relational approach doesn't quickly
run out of As and Ds to relate connected list items (or
involve writing a reader macro for run-length-encoded
#{c2a3d4adr list} which while cool might not be socially
acceptable in all contexts). Since #'assoc stops at the
first match, it also creates a natural history of item
locations like
```
(setq *items* '((whiskey . jar)))
(WHISKEY . PLAYER)
```
so while #'assoc returns the correct current whiskey
location (in the player) we can look into the past and see
there's whiskey in the jar.
My everything-is-where-it-is abstraction suffers a
correctable hiccup here as well. Since the player themselves
is not currently a game object, when I had the player #'TAKE
something, the item gets taken out of the game world and put
in a different list, the player's inventory. The solution to
this will be to put the player into the game world
and in general have non-location game entities be
instances of CLOS classes; and the player and other
characters/container items would have inventories, while
being inside the game world (my *ROOMS* list). Inventoryable
items seem natural to describe in the CLOS way using
multiple inheritance:
(defclass musical () ())
(defclass fruit () ())
(defclass beans (musical fruit) ())
Which let []
there be multiple objects of the same class that are not EQ
if they are not the same object:
```
(setq *dinner-today* (make-instance 'beans))
(setq *mystery-beans* (make-instance 'beans))
(setq *dinner-tomorrow* *mystery-beans*)
> (eq *dinner-today* *mystery-beans*)
NIL
> (eq *dinner-tomorrow* *mystery-beans*)
T
```
But Land of Lisp didn't get to CLOS yet. Already I've used
common lisp's seedy underbelly's Formatted Output for
describing the game world while Land of Lisp is currently
using '(VERY DESCRIPTIVE NAME WORDS IN LISTS) to keep data
in a processable form (strings will be used as well more
later I am promised).
I guess I have been using #'SETQ instead of #'DEFPARAMETER.
I used #'FIND when I should have used #'MEMBER like Land of
Lisp did. When it's clear from context I normally leave off
the sharp-sign from a function name, which is allowed, since
I like code to look as idiomatic as possible if there is an
exceptional clause I try to use it. (defun foo (x) (cons
'foo x)) (mapcar 'foo '(1 2)) ; same as (mapcar #'foo '(1
2))
I am looking forward to seeing some other Land of Lisp
wizard game writing phlogs! However loyal or disloyal to the
book they be.
Trivia:
Common lisp names can be case sensitive, or almost anything
else but you have to then demarcate them with pipes.
(setq
|People might think this is a "string".| '|but it isn't.|)