-
Notifications
You must be signed in to change notification settings - Fork 0
/
extraction.py
executable file
·220 lines (173 loc) · 6.66 KB
/
extraction.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
class ExtractedFile():
"""Contiains all the data from file which it reads when constructed.
max_carried - max # of items carried
starting_room - room # when player starts
treasure_count - # of treasures
word_length - # of character in vocabulary words
light_duration - # of turns the lamp (item 9) will run
treasure_room - room # where treasure must be placed
actions - list of ExtractedActions
nouns - the nouns in index order
verbs- the verbs in index order
grouped_nouns - groups of synonyms (a list of lists)
grouped_verbs - groups of synonyms (a list of lists)
rooms - list of ExtractedRooms
messages - list of messages
items - list of ExractedItems
"""
def __init__(self, file):
read_num(file) # unknown value
max_item_index = read_num(file)
max_action_index = read_num(file)
max_word_index = read_num(file)
max_room_index = read_num(file)
self.max_carried = read_num(file)
self.starting_room = read_num(file)
self.treasure_count = read_num(file)
self.word_length = read_num(file)
self.light_duration = read_num(file)
max_message_index = read_num(file)
self.treasure_room = read_num(file)
self.actions = []
for i in range(0, max_action_index+1):
self.actions.append(ExtractedAction(file))
self.verbs = []
self.nouns = []
for i in range(0, max_word_index+1):
self.verbs.append(read_string(file))
self.nouns.append(read_string(file))
self.grouped_verbs = group_words(self.verbs)
self.grouped_nouns = group_words(self.nouns)
self.rooms = []
for i in range(0, max_room_index+1):
self.rooms.append(ExtractedRoom(file))
self.messages = []
for i in range(0, max_message_index+1):
self.messages.append(read_string(file))
self.items = []
for i in range(0, max_item_index+1):
self.items.append(ExtractedItem(file))
for a in self.actions:
a.comment = read_string(file).strip()
class ExtractedAction():
"""Contains the bytecode for a unit of game logic.
verb - verb number the player must enter, or 0 for 'occurances'
noun - noun number the player must enter, 0 if none. If
verb is 0, this is a % chance to execute each turn.
conditions - list of tuples (condition-op, value)
actions = list of action bytecodes
"""
def __init__(self, file):
input_num = read_num(file)
self.verb, self.noun = split_number(input_num, 150)
condition_nums = [
read_num(file),
read_num(file),
read_num(file),
read_num(file),
read_num(file)
]
self.conditions = [split_number(c, 20) for c in condition_nums]
action_nums = [
read_num(file),
read_num(file)
]
self.actions = [s for a in action_nums for s in split_number(a, 150)]
class ExtractedRoom():
"""Contains the data for a room.
description - room text
north - room # north of this one, 0 for no exit.
south - room # south of this one.
east - room # east of this one.
west - room # west of this one.
up - room # up of this one.
down - room # down of this one.
"""
def __init__(self, file):
self.north = read_num(file)
self.south = read_num(file)
self.east = read_num(file)
self.west = read_num(file)
self.up = read_num(file)
self.down = read_num(file)
self.description = read_string(file)
class ExtractedItem():
"""Contains the data for an item.
description - item description, displayed in 'look' text.
starting_room - room where item starts.
carry_word - word used to refer to this item when getting or
dropping it; if None item can't be carried.
"""
def __init__(self, file):
self.description, extra = read_string_plus(file)
self.starting_room = int(extra)
self.carry_word = None
if self.description.endswith("/"):
wordstart = self.description.rfind(
"/", 0, len(self.description) - 1)
self.carry_word = self.description[wordstart +
1:len(self.description) - 1]
self.description = self.description[:wordstart]
# Utility Functions
def read_num(file):
"""Reads a line from 'file', converting it to an integer."""
line = file.readline()
return int(line)
def read_string_plus(file):
"""Reads a string from 'file', which can be a multi-line string. It must be
quoted with double-quotes, and may not contain them.
The first line must start with a double quote, but there can be extra text
after the closing quote.
this function returns a tuple of the content text and this extra text.
"""
buffer = []
extra = ""
while True:
line = file.readline()
if line == "":
break
if len(buffer) == 0:
if line[0] == "\"": # remove opening quote
line = line[1:]
else: # did not start with opening quote?
raise ValueError(f"'{line}' is not a string.")
endquotepos = line.rfind("\"")
if endquotepos < 0:
buffer.append(line)
else:
buffer.append(line[:endquotepos])
extra = line[endquotepos+1:]
break
return ("".join(buffer), extra)
def read_string(file):
"""Reads a string from the file, discarding any extra text after it on its last line."""
return read_string_plus(file)[0]
def split_number(number, multiplier):
"""Decodes a number into two. The number = high * multiplier + low, and
This method returns the tuple (high, low).
"""
low = int(number % multiplier)
high = int(number / multiplier)
return (high, low)
def group_words(words):
"""Takes a list of words, and groups them, returning a list-of-lists.
The idea is that each word starting with '*' is a synonym for the previous word,
and we group these synonyms together with their base word.
The word '.' is padding, and we discard it if found.
"""
grouped = []
buffer = []
for word in words:
if word not in (".", "*."): # This must be the padding, I think
if word == "":
pass
elif word[0] == "*":
buffer.append(word[1:])
elif len(buffer) == 0:
buffer.append(word)
else:
grouped.append(buffer)
buffer = [word]
if len(buffer) > 0:
grouped.append(buffer)
return grouped