Skip to content

Commit 3610bee

Browse files
committed
Commit for assignment5
1 parent 764d3a4 commit 3610bee

22 files changed

Lines changed: 10910 additions & 0 deletions

‎rjw366/adventure/.project‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<projectDescription>
3+
<name>adventure</name>
4+
<comment></comment>
5+
<projects>
6+
</projects>
7+
<buildSpec>
8+
<buildCommand>
9+
<name>org.python.pydev.PyDevBuilder</name>
10+
<arguments>
11+
</arguments>
12+
</buildCommand>
13+
</buildSpec>
14+
<natures>
15+
<nature>org.python.pydev.pythonNature</nature>
16+
</natures>
17+
</projectDescription>

‎rjw366/adventure/.pydevproject‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2+
<?eclipse-pydev version="1.0"?><pydev_project>
3+
<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
4+
<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
5+
</pydev_project>

‎rjw366/adventure/README.txt‎

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
This is a faithful port of the “Adventure” game to Python 3 from the
2+
original 1977 FORTRAN code by Crowther and Woods (it is driven by the
3+
same ``advent.dat`` file!) that lets you explore Colossal Cave, where
4+
others have found fortunes in treasure and gold, though it is rumored
5+
that some who enter are never seen again. Use your operating
6+
system command line to run the package::
7+
8+
$ python adventure.py
9+
WELCOME TO ADVENTURE!! WOULD YOU LIKE INSTRUCTIONS?
10+
11+
> no
12+
YOU ARE STANDING AT THE END OF A ROAD BEFORE A SMALL BRICK BUILDING.
13+
AROUND YOU IS A FOREST. A SMALL STREAM FLOWS OUT OF THE BUILDING AND
14+
DOWN A GULLY.
15+
16+
> east
17+
YOU ARE INSIDE A BUILDING, A WELL HOUSE FOR A LARGE SPRING.
18+
THERE ARE SOME KEYS ON THE GROUND HERE.
19+
THERE IS A SHINY BRASS LAMP NEARBY.
20+
THERE IS FOOD HERE.
21+
THERE IS A BOTTLE OF WATER HERE.
22+
23+
> get lamp
24+
OK
25+
26+
> leave
27+
YOU'RE AT END OF ROAD AGAIN.
28+
29+
> south
30+
YOU ARE IN A VALLEY IN THE FOREST BESIDE A STREAM TUMBLING ALONG A
31+
ROCKY BED.
32+
33+
The original Adventure paid attention to only the first five letters of
34+
each command, so a long command like ``inventory`` could simply be typed
35+
as ``inven``. This package defines a symbol for both versions of every
36+
long word, so you can type the long or short version as you please.
37+
38+
You can save your game at any time by calling the ``save`` command
39+
with a filename, and then can resume it later::
40+
41+
> save advent.save
42+
GAME SAVED
43+
> quit
44+
DO YOU REALLY WANT TO QUIT NOW?
45+
> y
46+
OK
47+
48+
$ python -m adventure mygame
49+
GAME RESTORED
50+
> look
51+
SORRY, BUT I AM NOT ALLOWED TO GIVE MORE DETAIL. I WILL REPEAT THE
52+
LONG DESCRIPTION OF YOUR LOCATION.
53+
YOU ARE IN A VALLEY IN THE FOREST BESIDE A STREAM TUMBLING ALONG A
54+
ROCKY BED.
55+
56+
You can find two complete, working walkthroughs of the game in its
57+
``tests`` directory, which you can run using the ``discover`` module::
58+
59+
$ python -m unittest discover
60+
61+
I wrote most of this package over Christmas vacation 2010, to learn more
62+
about the workings of the game that so enthralled me as a child; the
63+
project also gave me practice writing Python 3. I still forget the
64+
parentheses when writing ``print()`` if I am not paying attention.
65+
66+
For extra authenticity, the output of the Adventure game in this mode is
67+
typed to your screen at 1200 baud. You will note that although this
68+
prints the text faster than you can read it anyway, your experience of
69+
the game will improve considerably, especially when a move results in a
70+
surprise.
71+
72+
Why is the game better at 1200 baud? When a paragraph of text is
73+
allowed to appear on the screen all at once, your eyes scan the entire
74+
paragraph for important information, often ruining any surprises before
75+
you can then settle down and read it from the beginning. But at 1200
76+
baud, you wind up reading the text in order as it appears, which unfolds
77+
the narrative sequentially as the author of Adventure intended.
78+
79+
Changelog
80+
=========
81+
82+
| 1.3 — 2012 April 27 — installs on Windows; fixed undefined commands
83+
| 1.2 — 2012 April 5 — restoring saves from command line; 5-letter commands
84+
| 1.1 — 2011 March 12 — traditional mode; more flexible Python syntax
85+
| 1.0 — 2011 February 15 — 100% test coverage, feature-complete
86+
| 0.3 — 2011 January 31 — first public release

‎rjw366/adventure/TODO.txt‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
2+
* Test whether climbing down the dome with the gold nugget breaks your neck.
3+
* Test dropping into the secret canyon from the direction that gets no dragon.

‎rjw366/adventure/__init__.py‎

Whitespace-only changes.

‎rjw366/adventure/advent.dat‎

Lines changed: 1808 additions & 0 deletions
Large diffs are not rendered by default.

‎rjw366/adventure/adventure.py‎

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
"""Offer Adventure at a custom command prompt."""
2+
3+
import argparse
4+
import os
5+
import re
6+
from sys import executable, stdout
7+
from time import sleep
8+
from play import load_advent_dat
9+
from game import Game
10+
11+
BAUD = 1200
12+
13+
def baudout(s):
14+
for c in s:
15+
sleep(9. / BAUD) # 8 bits + 1 stop bit @ the given baud rate
16+
stdout.write(c)
17+
stdout.flush()
18+
19+
def loop():
20+
parser = argparse.ArgumentParser(
21+
description='Adventure into the Colossal Caves.',
22+
prog='{} -m adventure'.format(os.path.basename(executable)))
23+
parser.add_argument(
24+
'savefile', nargs='?', help='The filename of game you have saved.')
25+
args = parser.parse_args()
26+
27+
if args.savefile is None:
28+
game = Game()
29+
load_advent_dat(game)
30+
game.start()
31+
baudout(game.output)
32+
else:
33+
game = Game.resume(args.savefile)
34+
baudout('GAME RESTORED\n')
35+
36+
while not game.is_finished:
37+
line = raw_input('> ')
38+
words = re.findall(r'\w+', line)
39+
if words:
40+
baudout(game.do_command(words))
41+
42+
if __name__ == "__main__":
43+
try:
44+
loop()
45+
except EOFError:
46+
pass

‎rjw366/adventure/data.py‎

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
"""Parse the original PDP ``advent.dat`` file."""
2+
3+
from operator import attrgetter
4+
from model import Hint, Message, Move, Object, Room, Word
5+
6+
# The Adventure data file knows only the first five characters of each
7+
# word in the game, so we have to know the full verion of each word.
8+
9+
long_words = { w[:5]: w for w in """upstream downstream forest
10+
forward continue onward return retreat valley staircase outside building stream
11+
cobble inward inside surface nowhere passage tunnel canyon awkward
12+
upward ascend downward descend outdoors barren across debris broken
13+
examine describe slabroom depression entrance secret bedquilt plover
14+
oriental cavern reservoir office headlamp lantern pillow velvet fissure tablet
15+
oyster magazine spelunker dwarves knives rations bottle mirror beanstalk
16+
stalactite shadow figure drawings pirate dragon message volcano geyser
17+
machine vending batteries carpet nuggets diamonds silver jewelry treasure
18+
trident shards pottery emerald platinum pyramid pearl persian spices capture
19+
release discard mumble unlock nothing extinguish placate travel proceed
20+
continue explore follow attack strike devour inventory detonate ignite
21+
blowup peruse shatter disturb suspend sesame opensesame abracadabra
22+
shazam excavate information""".split() }
23+
24+
class Data(object):
25+
def __init__(self):
26+
self.rooms = {}
27+
self.vocabulary = {}
28+
self.objects = {}
29+
self.messages = {}
30+
self.class_messages = []
31+
self.hints = {}
32+
self.magic_messages = {}
33+
34+
def referent(self, word):
35+
if word.kind == 'noun':
36+
return self.objects[word.n % 1000]
37+
38+
# Helper functions.
39+
40+
def make_object(dictionary, klass, n):
41+
if n not in dictionary:
42+
dictionary[n] = obj = klass()
43+
obj.n = n
44+
return dictionary[n]
45+
46+
def expand_tabs(segments):
47+
it = iter(segments)
48+
line = next(it)
49+
for segment in it:
50+
spaces = 8 - len(line) % 8
51+
line += ' ' * spaces + segment
52+
return line
53+
54+
def accumulate_message(dictionary, n, line):
55+
dictionary[n] = dictionary.get(n, '') + line + '\n'
56+
57+
# Knowledge of what each section contains.
58+
59+
def section1(data, n, *etc):
60+
room = make_object(data.rooms, Room, n)
61+
if not etc[0].startswith('>$<'):
62+
room.long_description += expand_tabs(etc) + '\n'
63+
64+
def section2(data, n, line):
65+
make_object(data.rooms, Room, n).short_description += line + '\n'
66+
67+
def section3(data, x, y, *verbs):
68+
last_travel = data._last_travel
69+
if last_travel[0] == x and last_travel[1][0] == verbs[0]:
70+
verbs = last_travel[1] # same first verb implies use whole list
71+
else:
72+
data._last_travel = [x, verbs]
73+
74+
m, n = divmod(y, 1000)
75+
mh, mm = divmod(m, 100)
76+
77+
if m == 0:
78+
condition = (None,)
79+
elif 0 < m < 100:
80+
condition = ('%', m)
81+
elif m == 100:
82+
condition = ('not_dwarf',)
83+
elif 100 < m <= 200:
84+
condition = ('carrying', mm)
85+
elif 200 < m <= 300:
86+
condition = ('carrying_or_in_room_with', mm)
87+
elif 300 < m:
88+
condition = ('prop!=', mm, mh - 3)
89+
90+
if n <= 300:
91+
action = make_object(data.rooms, Room, n)
92+
elif 300 < n <= 500:
93+
action = n # special computed goto
94+
else:
95+
action = make_object(data.messages, Message, n - 500)
96+
97+
move = Move()
98+
if len(verbs) == 1 and verbs[0] == 1:
99+
move.is_forced = True
100+
else:
101+
move.verbs = [ make_object(data.vocabulary, Word, verb_n)
102+
for verb_n in verbs if verb_n < 100 ] # skip bad "109"
103+
move.condition = condition
104+
move.action = action
105+
data.rooms[x].travel_table.append(move)
106+
107+
def section4(data, n, text, *etc):
108+
text = text.lower()
109+
text = long_words.get(text, text)
110+
word = make_object(data.vocabulary, Word, n)
111+
if word.text is None: # this is the first word with index "n"
112+
word.text = text
113+
else: # there is already a word sitting at "n", so create a synonym
114+
original = word
115+
word = Word()
116+
word.n = n
117+
word.text = text
118+
original.add_synonym(word)
119+
word.kind = ['travel', 'noun', 'verb', 'snappy_comeback'][n // 1000]
120+
if word.kind == 'noun':
121+
n %= 1000
122+
obj = make_object(data.objects, Object, n)
123+
obj.names.append(text)
124+
obj.is_treasure = (n >= 50)
125+
data.objects[text] = obj
126+
if text not in data.vocabulary: # since duplicate names exist
127+
data.vocabulary[text] = word
128+
129+
def section5(data, n, *etc):
130+
if 1 <= n <= 99:
131+
data._object = make_object(data.objects, Object, n)
132+
data._object.inventory_message = expand_tabs(etc)
133+
else:
134+
n /= 100
135+
messages = data._object.messages
136+
if etc[0].startswith('>$<'):
137+
more = ''
138+
else:
139+
more = expand_tabs(etc) + '\n'
140+
messages[n] = messages.get(n, '') + more
141+
142+
def section6(data, n, *etc):
143+
message = make_object(data.messages, Message, n)
144+
message.text += expand_tabs(etc) + '\n'
145+
146+
def section7(data, n, room_n, *etc):
147+
if not room_n:
148+
return
149+
obj = make_object(data.objects, Object, n)
150+
room = make_object(data.rooms, Room, room_n)
151+
obj.drop(room)
152+
if len(etc):
153+
if etc[0] == -1:
154+
obj.is_fixed = True
155+
else:
156+
room2 = make_object(data.rooms, Room, etc[0])
157+
obj.rooms.append(room2) # exists two places, like grate
158+
obj.starting_rooms = list(obj.rooms) # remember where things started
159+
160+
def section8(data, word_n, message_n):
161+
if not message_n:
162+
return
163+
word = make_object(data.vocabulary, Word, word_n + 2000)
164+
message = make_object(data.messages, Message, message_n)
165+
for word2 in word.synonyms:
166+
word2.default_message = message
167+
168+
def section9(data, bit, *nlist):
169+
for n in nlist:
170+
room = make_object(data.rooms, Room, n)
171+
if bit == 0:
172+
room.is_light = True
173+
elif bit == 1:
174+
room.liquid = make_object(data.objects, Object, 22) #oil
175+
elif bit == 2:
176+
room.liquid = make_object(data.objects, Object, 21) #water
177+
elif bit == 3:
178+
room.is_forbidden_to_pirate = True
179+
else:
180+
hint = make_object(data.hints, Hint, bit)
181+
hint.rooms.append(room)
182+
183+
def section10(data, score, line, *etc):
184+
data.class_messages.append((score, line))
185+
186+
def section11(data, n, turns_needed, penalty, question_n, message_n):
187+
hint = make_object(data.hints, Hint, n)
188+
hint.turns_needed = turns_needed
189+
hint.penalty = penalty
190+
hint.question = make_object(data.messages, Message, question_n)
191+
hint.message = make_object(data.messages, Message, message_n)
192+
193+
def section12(data, n, line):
194+
accumulate_message(data.magic_messages, n, line)
195+
196+
# Process every section of the file in turn.
197+
198+
def parse(data, datafile):
199+
"""Read the Adventure data file and return a ``Data`` object."""
200+
data._last_travel = [0, [0]] # x and verbs used by section 3
201+
202+
while True:
203+
section_number = int(datafile.readline())
204+
if not section_number: # no further sections
205+
break
206+
store = globals().get('section%d' % section_number)
207+
while True:
208+
fields = [ (int(field) if field.lstrip('-').isdigit() else field)
209+
for field in datafile.readline().strip().split('\t') ]
210+
if fields[0] == -1: # end-of-section marker
211+
break
212+
store(data, *fields)
213+
214+
del data._last_travel # state used by section 3
215+
del data._object # state used by section 5
216+
217+
data.object_list = sorted(set(data.objects.values()), key=attrgetter('n'))
218+
#data.room_list = sorted(set(data.rooms.values()), key=attrgetter('n'))
219+
for obj in data.object_list:
220+
name = obj.names[0]
221+
if hasattr(data, name):
222+
name = name + '2' # create identifiers like ROD2, PLANT2
223+
setattr(data, name, obj)
224+
225+
return data

0 commit comments

Comments
 (0)