diff --git a/dbg_pdb.py b/dbg_pdb.py new file mode 100644 index 0000000..aa9dc03 --- /dev/null +++ b/dbg_pdb.py @@ -0,0 +1,17 @@ +# synacor.py - An implementation of the Synacor Challenge +# Copyright © 2017 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 . + +DBG_FLAG = True diff --git a/electric_boogaloo.md b/electric_boogaloo.md index f202d13..1d59cde 100644 --- a/electric_boogaloo.md +++ b/electric_boogaloo.md @@ -252,3 +252,27 @@ Similarly, the `R1` for the teleporter code is the value of `R8` from the Ackerm 1592 set R1 R8 The remaining two codes, for the coins and the vault, are more complicated still, but follow the same pattern of determining `R1` based on the player's history. + +For the coins, the call to `0731` derives an `R1` from the values at memory locations `69de` to `69e2`. One would presume that this relates to the order in which coins are inserted into the puzzle, and following the trail of callbacks for the coins confirms this. The important lines are: + + 13c0 rmem R3 099e # nr of coins inserted + 13c3 add R3 R3 69dd + 13c7 add R3 R3 0001 + 13cb wmem R3 R2 # R2 is the number of dots on the coin + +Thus the values should be 9, 2, 5, 7 and 3: the missing numbers in the solved equation. + +It is now trivial to generate the correct value of `R1`. Based on the code beginning, `15fd`: + +```python +data_69de = [9, 2, 5, 7, 3] + +R1 = 0 +for i in range(len(data_69de)): + R2 = data_69de[i] + R1 = R1 + R2 + R1 = (R1 * 0x7bac) % 0x8000 + R1 = R1 ^ R2 +``` + +The result is `0b3b`. diff --git a/synacor.py b/synacor.py index 23cbcd6..593341d 100755 --- a/synacor.py +++ b/synacor.py @@ -130,7 +130,9 @@ while True: if len(SYN_STK) == 0: raise Exception('Attempted to return with empty stack at {}'.format(SYN_PTR)) SYN_PTR = SYN_STK.pop() - DBG_CSTK.pop() + + if len(DBG_CSTK) > 0: + DBG_CSTK.pop() elif instruction == 19: #OUT print(chr(swallowOp().get()), end='') elif instruction == 20: #IN diff --git a/tools/generate_codes.py b/tools/generate_codes.py index be70f61..f07717f 100755 --- a/tools/generate_codes.py +++ b/tools/generate_codes.py @@ -21,6 +21,7 @@ import sys IV_LEN = 3 CODE_LEN = 12 +# Emulate 0731 def generate_code(R1, R2, R3, R4): R2data = SYN_MEM[R2+1:R2+1+SYN_MEM[R2]] R4data = SYN_MEM[R4+1:R4+1+SYN_MEM[R4]] @@ -63,12 +64,12 @@ for R2 in range(0x17b4, 0x7562): R1 ^= 0x4154 SYN_MEM[R2] = R1 -# Look for calls to 0731 +# Calls to 0731 CODE_PARAMS = [ (0x0058, 0x650a, 0x7fff, 0x6e8b), # R1 from the maze (0x1092, 0x650a, 0x7fff, 0x6eed), (0x6486, 0x650a, 0x7fff, 0x7239), # R1 is R8 from Ackermann - # 162e is a bit tricky + (0x0b3b, 0x650a, 0x7fff, 0x73df), # R1 from the dots on the coins # 1691 is a bit tricky ]