-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathzork.py
117 lines (98 loc) · 3.62 KB
/
zork.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
import os
from os.path import exists, join
import requests
import subprocess
import time
import zipfile
from mycroft.util.log import LOG
class ZorkInterpreter:
def __init__(self, interpreter, data, save_file):
self.interpreter = interpreter
self.data = data
self.save_file = save_file
LOG.info('Starting Zork')
# Start zork using frotz
self.zork = subprocess.Popen([self.interpreter, self.data],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE)
time.sleep(0.1) # Allow to load
self.clear_until_prompt() # Clear initial startup messages
# Load default savegame
if exists(self.save_file):
LOG.info('Loading save game')
self.restore(join(self.save_file))
def save(self):
"""Save the game state."""
self.cmd('save')
time.sleep(0.5)
self.clear_until_prompt(':')
self.cmd(self.save_file) # Accept default savegame
time.sleep(0.5)
# Check if game returns Ok or query to overwrite
while True:
char = self.zork.stdout.read(1)
time.sleep(0.01)
if char == b'.': # Ok. (everything is done)
break # The save is complete
if char == b'?': # Indicates an overwrite query
self.cmd('y') # reply yes
time.sleep(0.5)
self.clear_until_prompt()
def delete_save(self):
if exists(self.save_file):
os.remove(self.save_file)
return True
return False
def restore(self, filename):
"""Restore saved game."""
self.cmd('restore')
time.sleep(0.5)
self.clear_until_prompt(':')
self.cmd(filename) # Accept default savegame
time.sleep(0.5)
self.clear_until_prompt()
def clear_until_prompt(self, prompt='>'):
"""Clear all received characters until the standard prompt."""
# Clear all data with title etecetera
LOG.debug('Prompt is {}'.format(prompt))
char = self.zork.stdout.read(1).decode()
while char != prompt:
time.sleep(0.001)
char = self.zork.stdout.read(1).decode()
def cmd(self, action):
"""Write a command to the interpreter."""
self.zork.stdin.write(action.encode() + b'\n')
self.zork.stdin.flush()
def read(self):
"""Read from zork interpreter process.
Returns:
(tuple) Room name, description.
"""
# read Room name
output = ""
output += self.zork.stdout.read(1).decode()
while str(output)[-1] != '\n':
output += self.zork.stdout.read(1).decode()
room = output.split('Score')[0].strip()
# Read room info
output = ""
output += self.zork.stdout.read(1).decode()
while output[-1] != '>':
output += self.zork.stdout.read(1).decode()
# Return room name and description removing the prompt
return (room, output[:-1])
def install_zork_data(destination_dir):
"""Install the zork data files in destination."""
zork_data_dir = join(destination_dir, 'zork')
try:
os.mkdir(zork_data_dir)
except FileExistsError:
pass
r = requests.get('http://www.infocom-if.org/downloads/zork1.zip',
stream=True)
download_path = '/tmp/zork_data.zip'
with open(download_path, 'wb') as fd:
for chunk in r.iter_content(chunk_size=1024):
fd.write(chunk)
with zipfile.ZipFile(download_path, 'r') as zip_ref:
zip_ref.extractall(zork_data_dir)