Implement debug commands, like saving and loading state
This commit is contained in:
parent
753a7a9ec6
commit
2eae52efac
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +1,2 @@
|
|||||||
/challenge.bin
|
/challenge.bin
|
||||||
|
/dumps
|
||||||
|
20
README.md
20
README.md
@ -1,3 +1,23 @@
|
|||||||
# synacor.py
|
# synacor.py
|
||||||
|
|
||||||
My sort-of-OOP, ~~poorly-documented~~concise response to the Synacor challenge
|
My sort-of-OOP, ~~poorly-documented~~concise response to the Synacor challenge
|
||||||
|
|
||||||
|
## Debug commands
|
||||||
|
|
||||||
|
At any time the program is waiting for input, a string of the following form may be input:
|
||||||
|
|
||||||
|
.<cmd> <args>
|
||||||
|
|
||||||
|
This will execute the file `<cmd>.py` with `dbg_args[0]` set to `<cmd>` and `<args>` stored in `dbg_args[1..n]`.
|
||||||
|
|
||||||
|
For example, the self-test and decryption at the beginning of the program takes a comparatively long time. To save the state to the `dumps/init` file, enter:
|
||||||
|
|
||||||
|
.dbg_dump dumps/init
|
||||||
|
|
||||||
|
Similarly, debug commands may be passed as command-line arguments to `synacor.py` in the form:
|
||||||
|
|
||||||
|
./synacor.py <cmd> <args>
|
||||||
|
|
||||||
|
For example, to load the `dumps/init` state to skip the self-test and decryption, run:
|
||||||
|
|
||||||
|
./synacor.py dbg_load dumps/init
|
||||||
|
30
dbg_dump.py
Normal file
30
dbg_dump.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# synacor.py - An implementation of the Synacor Challenge
|
||||||
|
# Copyright © 2016 RunasSudo
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import pickle
|
||||||
|
|
||||||
|
if len(dbg_args) < 2:
|
||||||
|
print('Usage: .{} <file>'.format(dbg_args[0]))
|
||||||
|
else:
|
||||||
|
model = {
|
||||||
|
'SYN_PTR': SYN_PTR,
|
||||||
|
'SYN_MEM': SYN_MEM,
|
||||||
|
'SYN_REG': SYN_REG,
|
||||||
|
'SYN_STK': SYN_STK
|
||||||
|
}
|
||||||
|
|
||||||
|
with open(dbg_args[1], 'wb') as f:
|
||||||
|
pickle.dump(model, f)
|
28
dbg_load.py
Normal file
28
dbg_load.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# synacor.py - An implementation of the Synacor Challenge
|
||||||
|
# Copyright © 2016 RunasSudo
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import pickle
|
||||||
|
|
||||||
|
if len(dbg_args) < 2:
|
||||||
|
print('Usage: {} {} <file>'.format(sys.argv[0], dbg_args[0]))
|
||||||
|
else:
|
||||||
|
with open(dbg_args[1], 'rb') as f:
|
||||||
|
model = pickle.load(f)
|
||||||
|
|
||||||
|
SYN_PTR = model['SYN_PTR']
|
||||||
|
SYN_MEM = model['SYN_MEM']
|
||||||
|
SYN_REG = model['SYN_REG']
|
||||||
|
SYN_STK = model['SYN_STK']
|
24
synacor.py
24
synacor.py
@ -22,6 +22,7 @@ SYN_PTR = 0
|
|||||||
SYN_MEM = [0] * 32768
|
SYN_MEM = [0] * 32768
|
||||||
SYN_REG = [0] * 8
|
SYN_REG = [0] * 8
|
||||||
SYN_STK = []
|
SYN_STK = []
|
||||||
|
SYN_STDIN_BUF = []
|
||||||
|
|
||||||
class OpLiteral:
|
class OpLiteral:
|
||||||
def __init__(self, value):
|
def __init__(self, value):
|
||||||
@ -52,16 +53,20 @@ def swallowOp():
|
|||||||
SYN_PTR += 1
|
SYN_PTR += 1
|
||||||
return op
|
return op
|
||||||
|
|
||||||
# Read code into memory
|
if len(sys.argv) > 1:
|
||||||
with open('challenge.bin', 'rb') as data:
|
dbg_args = sys.argv[1:]
|
||||||
|
with open(dbg_args[0] + '.py', 'r') as f:
|
||||||
|
exec(f.read(), globals(), locals())
|
||||||
|
else:
|
||||||
|
# Read code into memory
|
||||||
|
with open('challenge.bin', 'rb') as data:
|
||||||
while True:
|
while True:
|
||||||
byteData = data.read(2)
|
byteData = data.read(2)
|
||||||
if len(byteData) < 2:
|
if len(byteData) < 2:
|
||||||
break
|
break
|
||||||
SYN_MEM[SYN_PTR] = struct.unpack('<H', byteData)[0]
|
SYN_MEM[SYN_PTR] = struct.unpack('<H', byteData)[0]
|
||||||
SYN_PTR += 1
|
SYN_PTR += 1
|
||||||
|
SYN_PTR = 0
|
||||||
SYN_PTR = 0
|
|
||||||
|
|
||||||
# Begin execution
|
# Begin execution
|
||||||
while True:
|
while True:
|
||||||
@ -120,6 +125,15 @@ while True:
|
|||||||
elif instruction == 19: #OUT
|
elif instruction == 19: #OUT
|
||||||
print(chr(swallowOp().get()), end='')
|
print(chr(swallowOp().get()), end='')
|
||||||
elif instruction == 20: #IN
|
elif instruction == 20: #IN
|
||||||
swallowOp().set(ord(sys.stdin.read(1))) # the spec says a whole line will be read, so ¯\_(ツ)_/¯
|
while len(SYN_STDIN_BUF) == 0:
|
||||||
|
line = sys.stdin.readline()
|
||||||
|
if line.startswith('.'): # debug command
|
||||||
|
dbg_args = line.rstrip()[1:].split()
|
||||||
|
with open(dbg_args[0] + '.py', 'r') as f:
|
||||||
|
SYN_PTR -= 1; exec(f.read(), globals(), locals()); SYN_PTR += 1
|
||||||
|
else:
|
||||||
|
SYN_STDIN_BUF = list(line)
|
||||||
|
|
||||||
|
swallowOp().set(ord(SYN_STDIN_BUF.pop(0)))
|
||||||
else:
|
else:
|
||||||
raise Exception('Unimplemented opcode {} at {}'.format(instruction, SYN_PTR))
|
raise Exception('Unimplemented opcode {} at {}'.format(instruction, SYN_PTR))
|
||||||
|
Reference in New Issue
Block a user