Last active
November 29, 2021 18:43
-
-
Save CTimmerman/275278abeea166a74fd3cf759a239b7e to your computer and use it in GitHub Desktop.
Demonstrates how a Lisp adventure game from the book "Casting SPELs in LISP" is more readable in Python. See also https://gist.github.com/CTimmerman/34b7b9d7b161442a5c5da7b4afbba163
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
""" | |
Casting SPELs with LISP demo code ported to Python | |
By Cees Timmerman | |
2017-07-04 v1.0 | |
""" | |
from __future__ import print_function | |
''' | |
(setf *objects* '(whiskey-bottle bucket frog chain)) | |
(setf *map* '((living-room (you are in the living-room of a wizards house. there is a | |
wizard snoring loudly on the couch.) | |
(west door garden) | |
(upstairs stairway attic)) | |
(garden (you are in a beautiful garden. there is a well in front of you.) | |
(east door living-room)) | |
(attic (you are in the attic of the wizards house. there is a giant | |
welding torch in the corner.) | |
(downstairs stairway living-room)))) | |
(setf *object-locations* '((whiskey-bottle living-room) | |
(bucket living-room) | |
(chain garden) | |
(frog garden))) | |
(setf *location* 'living-room) | |
(defun describe-location (location map) | |
(second (assoc location map))) | |
(describe-location 'living-room *map*) | |
(defun describe-path (path) | |
`(there is a ,(second path) going ,(first path) from here.)) | |
(describe-path '(west door garden)) | |
(defun describe-paths (location map) | |
(apply #'append (mapcar #'describe-path (cddr (assoc location map))))) | |
(describe-paths 'living-room *map*) | |
(defun is-at (obj loc obj-loc) | |
(eq (second (assoc obj obj-loc)) loc)) | |
(is-at 'whiskey-bottle 'living-room *object-locations*) | |
(defun describe-floor (loc objs obj-loc) | |
(apply #'append (mapcar (lambda (x) | |
`(you see a ,x on the floor.)) | |
(remove-if-not (lambda (x) | |
(is-at x loc obj-loc)) | |
objs)))) | |
(describe-floor 'living-room *objects* *object-locations*) | |
(defun look () | |
(append (describe-location *location* *map*) | |
(describe-paths *location* *map*) | |
(describe-floor *location* *objects* *object-locations*))) | |
(look) | |
(defun walk-direction (direction) | |
(let ((next (assoc direction (cddr (assoc *location* *map*))))) | |
(cond (next (setf *location* (third next)) (look)) | |
(t '(you cant go that way.))))) | |
(walk-direction 'west) | |
(defmacro defspel (&rest rest) `(defmacro ,@rest)) | |
(defspel walk (direction) | |
`(walk-direction ',direction)) | |
(walk east) | |
(defun pickup-object (object) | |
(cond ((is-at object *location* *object-locations*) (push (list object 'body) *object-locations*) | |
`(you are now carrying the ,object)) | |
(t '(you cannot get that.)))) | |
(defspel pickup (object) | |
`(pickup-object ',object)) | |
(pickup whiskey-bottle) | |
(defun inventory () | |
(remove-if-not (lambda (x) | |
(is-at x 'body *object-locations*)) | |
*objects*)) | |
(defun have (object) | |
(member object (inventory))) | |
(setf *chain-welded* nil) | |
(defun weld (subject object) | |
(cond ((and (eq *location* 'attic) | |
(eq subject 'chain) | |
(eq object 'bucket) | |
(have 'chain) | |
(have 'bucket) | |
(not *chain-welded*)) | |
(setf *chain-welded* 't) | |
'(the chain is now securely welded to the bucket.)) | |
(t '(you cannot weld like that.)))) | |
(weld 'chain 'bucket) | |
(setf *bucket-filled* nil) | |
(defun dunk (subject object) | |
(cond ((and (eq *location* 'garden) | |
(eq subject 'bucket) | |
(eq object 'well) | |
(have 'bucket) | |
*chain-welded*) | |
(setf *bucket-filled* 't) '(the bucket is now full of water)) | |
(t '(you cannot dunk like that.)))) | |
(defspel game-action (command subj obj place &rest rest) | |
`(defspel ,command (subject object) | |
`(cond ((and (eq *location* ',',place) | |
(eq ',subject ',',subj) | |
(eq ',object ',',obj) | |
(have ',',subj)) | |
,@',rest) | |
(t '(i cant ,',command like that.))))) | |
(game-action weld chain bucket attic | |
(cond ((and (have 'bucket) (setf *chain-welded* 't)) | |
'(the chain is now securely welded to the bucket.)) | |
(t '(you do not have a bucket.)))) | |
(weld chain bucket) | |
(game-action dunk bucket well garden | |
(cond (*chain-welded* (setf *bucket-filled* 't) '(the bucket is now full of water)) | |
(t '(the water level is too low to reach.)))) | |
(game-action splash bucket wizard living-room | |
(cond ((not *bucket-filled*) '(the bucket has nothing in it.)) | |
((have 'frog) '(the wizard awakens and sees that you stole his frog. | |
he is so upset he banishes you to the | |
netherworlds- you lose! the end.)) | |
(t '(the wizard awakens from his slumber and greets you warmly. | |
he hands you the magic low-carb donut- you win! the end.)))) | |
''' | |
FIRST = 0 | |
SECOND = 1 | |
THIRD = 2 | |
CDR = "[1:]" | |
CAR = "[0]" | |
OBJECTS = "whiskey-bottle bucket frog chain".split(' ') | |
MAP = { | |
'living-room': [ | |
'You are in the living-room of a wizards house. there is a wizard snoring loudly on the couch.', | |
'west door garden', | |
'upstairs stairway attic'], | |
'garden': [ | |
'You are in a beautiful garden. there is a well in front of you.', | |
'east door living-room'], | |
'attic': [ | |
'''You are in the attic of the wizards house. there is a giant | |
welding torch in the corner.''', | |
'downstairs stairway living-room'] | |
} | |
OBJECT_LOCATIONS = { | |
'whiskey-bottle': 'living-room', | |
'bucket': 'living-room', | |
'chain': 'garden', | |
'frog': 'garden' | |
} | |
LOCATION = 'living-room' | |
def describe_location(location, map): | |
return map[location][0] | |
#print(describe_location('living-room', MAP)) | |
def describe_path(path): | |
return 'There is a {} going {} from here.'.format(path.split()[1], path.split()[0]) | |
#print(describe_path('west door garden')) | |
def describe_paths(location, map): | |
return ' '.join(describe_path(path) for path in map[location][1:]) | |
#print(describe_paths('living-room', MAP)) | |
def describe_floor(loc, objs, obj_loc): | |
return ' '.join(['You see a {} on the floor.'.format(k) for k in obj_loc if obj_loc[k] == loc]) | |
print(describe_floor('living-room', OBJECTS, OBJECT_LOCATIONS)) | |
def look(): | |
return '\n'.join([ | |
describe_location(LOCATION, MAP), | |
describe_paths(LOCATION, MAP), | |
describe_floor(LOCATION, OBJECTS, OBJECT_LOCATIONS) | |
]) | |
print(look()) | |
def walk_direction(direction): | |
global LOCATION | |
try: | |
#next = MAP[LOCATION][direction] | |
directions = MAP[LOCATION][1:] | |
next = [d.split() for d in directions if d.split()[0] == direction][0] | |
#(let ((next (assoc direction (cddr (assoc LOCATION MAP))))) | |
LOCATION = next[2] | |
return look() | |
except: | |
return 'You cant go that way.' | |
#walk_direction('west') | |
#wtf? def defspel(&rest rest) `(defmacro ,@rest)) | |
def walk(direction): | |
return walk_direction(direction) | |
#walk('east') | |
def pickup_object(object): | |
if OBJECT_LOCATIONS[object] == LOCATION: OBJECT_LOCATIONS[object] = 'body' | |
else: return 'You cannot get that.' | |
def pickup(object): | |
return pickup_object(object) | |
#pickup('whiskey-bottle') | |
def inventory(): | |
return [k for k in OBJECTS if OBJECT_LOCATIONS[k] == 'body'] | |
def have(object): | |
return OBJECT_LOCATIONS[object] == 'body' #object in inventory() | |
CHAIN_WELDED = None | |
def weld(subject, object): | |
global CHAIN_WELDED | |
if LOCATION == 'attic' \ | |
and subject == 'chain' \ | |
and object == 'bucket' \ | |
and have('chain') \ | |
and have('bucket') \ | |
and not CHAIN_WELDED: | |
CHAIN_WELDED = True | |
return 'The chain is now securely welded to the bucket.' | |
else: | |
return 'You cannot weld like that.' | |
#weld('chain', 'bucket') | |
BUCKET_FILLED = None | |
def dunk(subject, object): | |
if LOCATION == 'garden' \ | |
and subject == 'bucket' \ | |
and object == 'well' \ | |
and have('bucket') \ | |
and CHAIN_WELDED: | |
BUCKET_FILLED = True | |
return 'The bucket is now full of water' | |
else: | |
return 'You cannot dunk like that.' | |
def game_action(command, subj, obj, place, rest): | |
code =""" | |
global {command} | |
def {command}(subject, object): | |
if LOCATION == '{place}' \ | |
and subject == '{subj}' \ | |
and object == '{obj}' \ | |
and have('{subj}'): | |
exec(\"\"\"{rest}\"\"\") | |
else: print("I cant {command} like that.") | |
""".format(command=command, subj=subj, obj=obj, place=place, rest=rest) | |
#print(code) | |
exec(code) | |
game_action('weld', 'chain', 'bucket', 'attic', | |
""" | |
if have('bucket'): | |
global CHAIN_WELDED | |
CHAIN_WELDED = True | |
print('The chain is now securely welded to the bucket.') | |
else: print('You do not have a bucket.') | |
""" | |
) | |
#weld('chain', 'bucket') | |
game_action('dunk', 'bucket', 'well', 'garden', | |
"""if CHAIN_WELDED: global BUCKET_FILLED; BUCKET_FILLED = True; print('The bucket is now full of water') | |
else: print('The water level is too low to reach.')""") | |
game_action('splash', 'bucket', 'wizard', 'living-room', | |
""" | |
if not BUCKET_FILLED: print('The bucket has nothing in it.') | |
elif have('frog'): print('''The wizard awakens and sees that you stole his frog. | |
He is so upset he banishes you to the | |
Netherworlds- you lose! the end.''') | |
else: print('''The wizard awakens from his slumber and greets you warmly. | |
he hands you the magic low-carb donut- you win! the end.''') | |
""") | |
while 1: | |
try: | |
a = raw_input().split() | |
if a[0] == "exit": break | |
if len(a) > 1: | |
cmd = "{}('{}')".format(a[0], "', '".join(a[1:])) | |
#print(cmd) | |
msg = eval(cmd) | |
if(msg): print(msg) | |
else: print(eval("{}()".format(a[0]))) | |
except Exception as ex: | |
print(ex, "\nTry look, pickup, dunk, splash, weld, walk, inventory, have, or exit.") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment