summaryrefslogtreecommitdiff
path: root/vba
diff options
context:
space:
mode:
Diffstat (limited to 'vba')
-rw-r--r--vba/vba.py1181
-rw-r--r--vba/vba_autoplayer.py495
-rw-r--r--vba/vba_config.py12
-rw-r--r--vba/vba_keyboard.py562
4 files changed, 0 insertions, 2250 deletions
diff --git a/vba/vba.py b/vba/vba.py
deleted file mode 100644
index ea7bb2e..0000000
--- a/vba/vba.py
+++ /dev/null
@@ -1,1181 +0,0 @@
-#!/usr/bin/jython
-# -*- encoding: utf-8 -*-
-"""
-vba-clojure (but really it's jython/python/jvm)
-
-This is jython, not python. Use jython to run this file. Before running this
-file, some of the dependencies need to be constructed. These can be obtained
-from the vba-clojure project.
- sudo apt-get install g++ libtool openjdk-6-jre openjdk-6-jdk libsdl1.2-dev mercurial ant autoconf jython
-
- export JAVA_INCLUDE_PATH=/usr/lib/jvm/java-6-openjdk-amd64/include/
- export JAVA_INCLUDE_PATH2=/usr/lib/jvm/java-6-openjdk-amd64/include/
-
- hg clone http://hg.bortreb.com/vba-clojure
- cd vba-clojure/
- ./dl-libs.sh
- cd java/
- ant all
- cd ..
- autoreconf -i
- ./configure
- make
- sudo make install
-
-Make sure vba-clojure bindings are in $CLASSPATH:
- export CLASSPATH=$CLASSPATH:java/dist/gb-bindings.jar
-
-Make sure vba-clojure is available within "java.library.path":
- sudo ln -s \
- $HOME/local/vba-clojure/vba-clojure/src/clojure/.libs/libvba.so.0.0.0 \
- /usr/lib/jni/libvba.so
-
-(In the above command, substitute the first path with the path of the vba-clojure
-directory you made, if it is different.)
-
-Also make sure VisualBoyAdvance.cfg is somewhere in the $PATH for VBA to find.
-A default configuration is provided in vba-clojure under src/.
-
-Usage (in jython, not python):
- import vba
-
- # activate the laser beam
- vba.load_rom("/path/to/baserom.gbc")
-
- # make the emulator eat some instructions
- vba.nstep(300)
-
- # save the state because we're paranoid
- copyrights = vba.get_state()
- # or ...
- vba.save_state("copyrights")
- # >>> vba.load_state("copyrights") == copyrights
- # True
-
- # play for a while, then press F12
- vba.run()
-
- # let's save the game again
- vba.save_state("unknown-delete-me")
-
- # and let's go back to the other state
- vba.set_state(copyrights)
-
- # or why not the other way around?
- vba.set_state(vba.load_state("unknown-delete-me"))
-
- vba.get_memory_at(0xDCDA)
- vba.set_memory_at(0xDCDB, 0xFF)
- vba.get_memory_range(0xDCDA, 10)
-
-TOOD:
- [ ] set a specific register
- [ ] get a specific register
- [ ] breakpoints
- [ ] vgm stuff
- [ ] gbz80disasm integration
- [ ] pokecrystal.extras integration
-
-"""
-
-import os
-import sys
-import re
-from array import array
-import string
-from copy import copy
-import unittest
-
-# for converting bytes to readable text
-from chars import chars
-
-from map_names import map_names
-
-# for _check_java_library_path
-from java.lang import System
-
-# for passing states to the emulator
-from java.nio import ByteBuffer
-
-# For getRegisters and other times we have to pass a java int array to a
-# function.
-import jarray
-
-# load in the vba-clojure bindings
-import com.aurellem.gb.Gb as Gb
-
-# load the vba-clojure library
-Gb.loadVBA()
-
-from vba_config import *
-
-try:
- import vba_keyboard as keyboard
-except ImportError:
- print "Not loading the keyboard module (which uses networkx)."
-
-if not os.path.exists(rom_path):
- raise Exception("rom_path is not configured properly; edit vba_config.py? " + str(rom_path))
-
-def _check_java_library_path():
- """
- Returns the value of java.library.path.
-
- The vba-clojure library must be compiled
- and linked from this location.
- """
- return System.getProperty("java.library.path")
-
-class RomList(list):
-
- """
- Simple wrapper to prevent a giant rom from being shown on screen.
- """
-
- def __init__(self, *args, **kwargs):
- list.__init__(self, *args, **kwargs)
-
- def __repr__(self):
- """
- Simplifies this object so that the output doesn't overflow stdout.
- """
- return "RomList(too long)"
-
-button_masks = {
- "a": 0x0001,
- "b": 0x0002,
- "r": 0x0010,
- "l": 0x0020,
- "u": 0x0040,
- "d": 0x0080,
- "select": 0x0004,
- "start": 0x0008,
- "restart": 0x0800,
- "listen": -1, # what?
-}
-
-# useful for directly stating what to press
-a, b, r, l, u, d, select, start, restart = "a", "b", "r", "l", "u", "d", "select", "start", "restart"
-
-def button_combiner(buttons):
- """
- Combines multiple button presses into an integer.
-
- This is used when sending a keypress to the emulator.
- """
- result = 0
-
- # String inputs need to be cleaned up so that "start" doesn't get
- # recognized as "s" and "t" etc..
- if isinstance(buttons, str):
- if "restart" in buttons:
- buttons = buttons.replace("restart", "")
- result |= button_masks["restart"]
- if "start" in buttons:
- buttons = buttons.replace("start", "")
- result |= button_masks["start"]
- if "select" in buttons:
- buttons = buttons.replace("select", "")
- result |= button_masks["select"]
-
- # allow for the "a, b" and "a b" formats
- if ", " in buttons:
- buttons = buttons.split(", ")
- elif " " in buttons:
- buttons = buttons.split(" ")
-
- if isinstance(buttons, list):
- if len(buttons) > 9:
- raise Exception("can't combine more than 9 buttons at a time")
-
- for each in buttons:
- result |= button_masks[each]
-
- #print "button: " + str(result)
- return result
-
-def load_rom(path=None):
- """
- Starts the emulator with a certain ROM.
-
- Defaults to rom_path if no parameters are given.
- """
- if path == None:
- path = rom_path
- try:
- root = load_state("root")
- except:
- # "root.sav" is required because if you create it in the future, you
- # will have to shutdown the emulator and possibly lose your state. Some
- # functions require there to be at least one root state available to do
- # computations between two states.
- sys.stderr.write("ERROR: unable to read \"root.sav\", please run"
- " generate_root() or get_root() to make an initial save.\n")
- Gb.startEmulator(path)
-
-def shutdown():
- """
- Stops the emulator. Closes the window.
-
- The "opposite" of this is the load_rom function.
- """
- Gb.shutdown()
-
-def step():
- """
- Advances the emulator forward by one step.
- """
- Gb.step()
-
-def nstep(steplimit):
- """
- Step the game forward by a certain number of instructions.
- """
- for counter in range(0, steplimit):
- Gb.step()
-
-def step_until_capture():
- """
- Loop step() until SDLK_F12 is detected.
- """
- Gb.stepUntilCapture()
-
-# just some aliases for step_until_capture
-run = go = step_until_capture
-
-def translate_chars(charz):
- result = ""
- for each in charz:
- result += chars[each]
- return result
-
-def _create_byte_buffer(data):
- """
- Converts data into a ByteBuffer.
-
- This is useful for interfacing with the Gb class.
- """
- buf = ByteBuffer.allocateDirect(len(data))
- if isinstance(data[0], int):
- for byte in data:
- buf.put(byte)
- else:
- for byte in data:
- buf.put(ord(byte))
- return buf
-
-def set_state(state, do_step=False):
- """
- Injects the given state into the emulator.
-
- Use do_step if you want to call step(), which also allows
- SDL to render the latest frame. Note that the default is to
- not step, and that the screen (if it is enabled) will appear
- as if it still has the last state loaded. This is normal.
- """
- Gb.loadState(_create_byte_buffer(state))
- if do_step:
- step()
-
-def get_state():
- """
- Retrieves the current state of the emulator.
- """
- buf = Gb.saveState()
- state = [buf.get(x) for x in range(0, buf.capacity())]
- arr = array("b")
- arr.extend(state)
- return arr.tostring() # instead of state
-
-def save_state(name, state=None, override=False):
- """
- Saves the given state to save_state_path.
-
- The file format must be ".sav"
- (and this will be appended to your string if necessary).
- """
- if state == None:
- state = get_state()
- if len(name) < 4 or name[-4:] != ".sav":
- name += ".sav"
- save_path = os.path.join(save_state_path, name)
- if not override and os.path.exists(save_path):
- raise Exception("oops, save state path already exists: " + str(save_path))
- else:
- # convert the state into a reasonable output
- data = array('b')
- data.extend(state)
- output = data.tostring()
-
- file_handler = open(save_path, "wb")
- file_handler.write(output)
- file_handler.close()
-
-def load_state(name):
- """
- Reads a state from file based on name.
-
- Looks in save_state_path for a file
- with this name (".sav" is optional).
- """
- save_path = os.path.join(save_state_path, name)
- if not os.path.exists(save_path):
- if len(name) < 4 or name[-4:] != ".sav":
- name += ".sav"
- save_path = os.path.join(save_state_path, name)
- file_handler = open(save_path, "rb")
- state = file_handler.read()
- file_handler.close()
- return state
-
-def generate_root():
- """
- Restarts the emulator and saves the initial state to "root.sav".
- """
- shutdown()
- load_rom()
- root = get_state()
- save_state("root", state=root, override=True)
- return root
-
-def get_root():
- """
- Loads the root state.
-
- (Or restarts the emulator and creates a new root state.)
- """
- try:
- root = load_state("root")
- except:
- root = generate_root()
-
-def get_registers():
- """
- Returns a list of current register values.
- """
- register_array = jarray.zeros(Gb.NUM_REGISTERS, "i")
- Gb.getRegisters(register_array)
- return list(register_array)
-
-def set_registers(registers):
- """
- Applies the set of registers to the CPU.
- """
- Gb.writeRegisters(registers)
-write_registers = set_registers
-
-def get_rom():
- """
- Returns the ROM in bytes.
- """
- rom_array = jarray.zeros(Gb.ROM_SIZE, "i")
- Gb.getROM(rom_array)
- return RomList(rom_array)
-
-def get_ram():
- """
- Returns the RAM in bytes.
- """
- ram_array = jarray.zeros(Gb.RAM_SIZE, "i")
- Gb.getRAM(ram_array)
- return RomList(ram_array)
-
-def say_hello():
- """
- Test that the VBA/GB bindings are working.
- """
- Gb.sayHello()
-
-def get_memory():
- """
- Returns memory in bytes.
- """
- memory_size = 0x10000
- memory = jarray.zeros(memory_size, "i")
- Gb.getMemory(memory)
- return RomList(memory)
-
-def set_memory(memory):
- """
- Sets memory in the emulator.
-
- Use get_memory() to retrieve the current state.
- """
- Gb.writeMemory(memory)
-
-def get_pixels():
- """
- Returns a list of pixels on the screen display.
-
- Broken, probably. Use screenshot() instead.
- """
- sys.stderr.write("ERROR: seems to be broken on VBA's end? Good luck. Use"
- " screenshot() instead.\n")
- size = Gb.DISPLAY_WIDTH * Gb.DISPLAY_HEIGHT
- pixels = jarray.zeros(size, "i")
- Gb.getPixels(pixels)
- return RomList(pixels)
-
-def screenshot(filename, literal=False):
- """
- Saves a PNG screenshot to the file at filename.
-
- Use literal if you want to store it in the current directory.
- Default is to save it to screenshots/ under the project.
- """
- screenshots_path = os.path.join(project_path, "screenshots/")
- filename = os.path.join(screenshots_path, filename)
- if len(filename) < 4 or filename[-4:] != ".png":
- filename += ".png"
- Gb.nwritePNG(filename)
- print "Screenshot saved to: " + str(filename)
-save_png = screenshot
-
-def read_memory(address):
- """
- Read an integer at an address.
- """
- return Gb.readMemory(address)
-get_memory_at = read_memory
-
-def get_memory_range(start_address, byte_count):
- """
- Returns a list of bytes.
-
- start_address - address to start reading at
- byte_count - how many bytes (0 returns just 1 byte)
- """
- bytez = []
- for counter in range(0, byte_count):
- byte = get_memory_at(start_address + counter)
- bytez.append(byte)
- return bytez
-
-def set_memory_at(address, value):
- """
- Sets a byte at a certain address in memory.
-
- This directly sets the memory instead of copying
- the memory from the emulator.
- """
- Gb.setMemoryAt(address, value)
-
-def press(buttons, holdsteps=1, aftersteps=1):
- """
- Press a button.
-
- Use steplimit to say for how many steps you want to press
- the button (try leaving it at the default, 1).
- """
- if hasattr(buttons, "__len__"):
- number = button_combiner(buttons)
- elif isinstance(buttons, int):
- number = buttons
- else:
- number = buttons
- for step_counter in range(0, holdsteps):
- Gb.step(number)
-
- # clear the button press
- if aftersteps > 0:
- for step_counter in range(0, aftersteps):
- Gb.step(0)
-
-def get_buttons():
- """
- Returns the currentButtons[0] value
-
- (an integer with bits set for which
- buttons are currently pressed).
- """
- return Gb.getCurrentButtons()
-
-class State(RomList):
- name = None
-
-class Recording:
- def __init__(self):
- self.frames = []
- self.states = {}
-
- def _get_frame_count(self):
- return len(self.frames)
-
- frame_count = property(fget=_get_frame_count)
-
- def save(self, name=None):
- """
- Saves the current state.
- """
- state = State(get_state())
- state.name = name
- self.states[self.frame_count] = state
-
- def load(self, name):
- """
- Loads a state by name in the state list.
- """
- for state in self.states.items():
- if state.name == name:
- set_state(state)
- return state
- return False
-
- def step(self, stepcount=1, first_frame=0, replay=False):
- """
- Records button presses for each frame.
- """
- if replay:
- stepcount = len(self.frames[first_name:])
-
- for counter in range(first_frame, stepcount):
- if replay:
- press(self.frames[counter], steplimit=0)
- else:
- self.frames.append(get_buttons())
- nstep(1)
-
- def replay_from(self, thing):
- """
- Replays based on a State or the name of a saved state.
- """
- if isinstance(thing, State):
- set_state(thing)
- else:
- thing = self.load(thing)
- frame_id = self.states.index(thing)
- self.step(first_frame=frame_id, replay=True)
-
-class Registers:
- order = [
- "pc",
- "sp",
- "af",
- "bc",
- "de",
- "hl",
- "iff",
- "div",
- "tima",
- "tma",
- "tac",
- "if",
- "lcdc",
- "stat",
- "scy",
- "scx",
- "ly",
- "lyc",
- "dma",
- "wy",
- "wx",
- "vbk",
- "hdma1",
- "hdma2",
- "hdma3",
- "hdma4",
- "hdma5",
- "svbk",
- "ie",
- ]
-
- def __setitem__(self, key, value):
- current_registers = get_registers()
- current_registers[Registers.order.index(key)] = value
- set_registers(current_registers)
-
- def __getitem__(self, key):
- current_registers = get_registers()
- return current_registers[Registers.order.index(key)]
-
- def __list__(self):
- return get_registers()
-
- def _get_register(id):
- def constructed_func(self, id=copy(id)):
- return get_registers()[id]
- return constructed_func
-
- def _set_register(id):
- def constructed_func(self, value, id=copy(id)):
- current_registers = get_registers()
- current_registers[id] = value
- set_registers(current_registers)
- return constructed_func
-
- pc = property(fget=_get_register(0), fset=_set_register(0))
- sp = property(fget=_get_register(1), fset=_set_register(1))
- af = property(fget=_get_register(2), fset=_set_register(2))
- bc = property(fget=_get_register(3), fset=_set_register(3))
- de = property(fget=_get_register(4), fset=_set_register(4))
- hl = property(fget=_get_register(5), fset=_set_register(5))
- iff = property(fget=_get_register(6), fset=_set_register(6))
- div = property(fget=_get_register(7), fset=_set_register(7))
- tima = property(fget=_get_register(8), fset=_set_register(8))
- tma = property(fget=_get_register(9), fset=_set_register(9))
- tac = property(fget=_get_register(10), fset=_set_register(10))
- _if = property(fget=_get_register(11), fset=_set_register(11))
- lcdc = property(fget=_get_register(12), fset=_set_register(12))
- stat = property(fget=_get_register(13), fset=_set_register(13))
- scy = property(fget=_get_register(14), fset=_set_register(14))
- scx = property(fget=_get_register(15), fset=_set_register(15))
- ly = property(fget=_get_register(16), fset=_set_register(16))
- lyc = property(fget=_get_register(17), fset=_set_register(17))
- dma = property(fget=_get_register(18), fset=_set_register(18))
- wy = property(fget=_get_register(19), fset=_set_register(19))
- wx = property(fget=_get_register(20), fset=_set_register(20))
- vbk = property(fget=_get_register(21), fset=_set_register(21))
- hdma1 = property(fget=_get_register(22), fset=_set_register(22))
- hdma2 = property(fget=_get_register(23), fset=_set_register(23))
- hdma3 = property(fget=_get_register(24), fset=_set_register(24))
- hdma4 = property(fget=_get_register(25), fset=_set_register(25))
- hdma5 = property(fget=_get_register(26), fset=_set_register(26))
- svbk = property(fget=_get_register(27), fset=_set_register(27))
- ie = property(fget=_get_register(28), fset=_set_register(28))
-
- def __repr__(self):
- spacing = "\t"
- output = "Registers:\n"
- for (id, each) in enumerate(self.order):
- output += spacing + each + " = " + hex(get_registers()[id])
- #hex(self[each])
- output += "\n"
- return output
-
-registers = Registers()
-
-def call(bank, address):
- """
- Jumps into a function at a certain address.
-
- Go into the start menu, pause the game and try call(1, 0x1078) to see a
- string printed to the screen.
- """
- push = [
- registers.pc,
- registers.hl,
- registers.de,
- registers.bc,
- registers.af,
- 0x3bb7,
- ]
-
- for value in push:
- registers.sp -= 2
- set_memory_at(registers.sp + 1, value >> 8)
- set_memory_at(registers.sp, value & 0xFF)
- if get_memory_range(registers.sp, 2) != [value & 0xFF, value >> 8]:
- print "desired memory values: " + str([value & 0xFF, value >> 8] )
- print "actual memory values: " + str(get_memory_range(registers.sp , 2))
- print "wrong value at " + hex(registers.sp) + " expected " + hex(value) + " but got " + hex(get_memory_at(registers.sp))
-
- if bank != 0:
- registers["af"] = (bank << 8) | (registers["af"] & 0xFF)
- registers["hl"] = address
- registers["pc"] = 0x2d63 # FarJump
- else:
- registers["pc"] = address
-
-class cheats:
- """
- Helpers to manage the cheating infrastructure.
-
- import vba; vba.load_rom(); vba.cheats.add_gameshark("0100CFCF", "text speedup 1"); vba.cheats.add_gameshark("0101CCCF", "text speedup 2"); vba.go()
- """
-
- @staticmethod
- def enable(id):
- """
- void gbCheatEnable(int i)
- """
- Gb.cheatEnable(id)
-
- @staticmethod
- def disable(id):
- """
- void gbCheatDisable(int i)
- """
- Gb.cheatDisable(id)
-
- @staticmethod
- def load_file(filename):
- """
- Loads a .clt file. By default each cheat is disabled.
- """
- Gb.loadCheatsFromFile(filename)
-
- @staticmethod
- def remove_all():
- """
- Removes all cheats from memory.
-
- void gbCheatRemoveAll()
- """
- Gb.cheatRemoveAll()
-
- @staticmethod
- def remove_cheat(id):
- """
- Removes a specific cheat from memory by id.
-
- void gbCheatRemove(int i)
- """
- Gb.cheatRemove(id)
-
- @staticmethod
- def add_gamegenie(code, description=""):
- """
- void gbAddGgCheat(const char *code, const char *desc)
- """
- Gb.cheatAddGamegenie(code, description)
-
- @staticmethod
- def add_gameshark(code, description=""):
- """
- gbAddGsCheat(const char *code, const char *desc)
- """
- Gb.cheatAddGameshark(code, description)
-
-def get_stack():
- """
- Return a list of functions on the stack.
- """
- addresses = []
- sp = registers.sp
-
- for x in range(0, 11):
- sp = sp - (2 * x)
- hi = get_memory_at(sp + 1)
- lo = get_memory_at(sp)
- address = ((hi << 8) | lo)
- addresses.append(address)
-
- return addresses
-
-class crystal:
- """
- Just a simple namespace to store a bunch of functions for Pokémon Crystal.
- """
-
- @staticmethod
- def text_wait(step_size=1, max_wait=200, sfx_limit=0, debug=False, callback=None):
- """
- Presses the "A" button when text is done being drawn to screen.
-
- The `debug` parameter is only useful when debugging this function. It
- enables the `max_wait` feature, which causes the function to exit
- instead of hanging around.
-
- The `sfx_limit` parameter is useful for when the player is given an
- item during the text. Set it to 1 to not treat the sound as the end of
- text. The next loop around it will return to the normal behavior of the
- function.
-
- :param step_size: number of steps per wait loop
- :param max_wait: number of wait loops to perform
- """
- while max_wait > 0:
- hi = get_memory_at(registers.sp + 1)
- lo = get_memory_at(registers.sp)
- address = ((hi << 8) | lo)
-
- if address in range(0xa1b, 0xa46) + range(0xaaf, 0xaf5): # 0xaef:
- print "pressing, then breaking.. address is: " + str(hex(address))
-
- # set CurSFX
- set_memory_at(0xc2bf, 0)
-
- press("a", holdsteps=10, aftersteps=1)
-
- # check if CurSFX is SFX_READ_TEXT_2
- if get_memory_at(0xc2bf) == 0x8:
- print "cursfx is set to SFX_READ_TEXT_2, looping.."
- return crystal.text_wait(step_size=step_size, max_wait=max_wait, debug=debug, callback=callback, sfx_limit=sfx_limit)
- else:
- if sfx_limit > 0:
- sfx_limit = sfx_limit - 1
- print "decreasing sfx_limit"
- else:
- # probably the last textbox in a sequence
- print "cursfx is not set to SFX_READ_TEXT_2, so: breaking"
-
- break
- else:
- stack = get_stack()
-
- # yes/no box or the name selection box
- if address in range(0xa46, 0xaaf):
- print "probably at a yes/no box.. exiting."
- break
-
- # date/time box (day choice)
- # 0x47ab is the one from the intro, 0x49ab is the one from mom.
- elif 0x47ab in stack or 0x49ab in stack: # was any([x in stack for x in range(0x46EE, 0x47AB)])
- print "probably at a date/time box ? exiting."
- break
-
- # "How many minutes?" selection box
- elif 0x4826 in stack:
- print "probably at a \"How many minutes?\" box ? exiting."
- break
-
- else:
- nstep(step_size)
-
- # if there is a callback, then call the callback and exit when the
- # callback returns True. This is especially useful during the
- # OakSpeech intro where textboxes are running constantly, and then
- # suddenly the player can move around. One way to detect that is to
- # set callback to a function that returns
- # "vba.get_memory_at(0xcfb1) != 0".
- if callback != None:
- result = callback()
- if result == True:
- print "callback returned True, exiting"
- return
-
- # only useful when debugging. When this is left on, text that
- # takes a while to print to screen will cause this function to
- # exit.
- if debug == True:
- max_wait = max_wait - 1
-
- if max_wait == 0:
- print "max_wait was hit"
-
- @staticmethod
- def walk_through_walls_slow():
- memory = get_memory()
- memory[0xC2FA] = 0
- memory[0xC2FB] = 0
- memory[0xC2FC] = 0
- memory[0xC2FD] = 0
- set_memory(memory)
-
- @staticmethod
- def walk_through_walls():
- """
- Lets the player walk all over the map.
-
- These values are probably reset by some of the map/collision
- functions when you move on to a new location, so this needs
- to be executed each step/tick if continuous walk-through-walls
- is desired.
- """
- set_memory_at(0xC2FA, 0)
- set_memory_at(0xC2FB, 0)
- set_memory_at(0xC2FC, 0)
- set_memory_at(0xC2FD, 0)
-
- #@staticmethod
- #def set_enemy_level(level):
- # set_memory_at(0xd213, level)
-
- @staticmethod
- def nstep(steplimit=500):
- """
- Steps the CPU forward and calls some functions in between each step.
-
- (For example, to manipulate memory.) This is pretty slow.
- """
- for step_counter in range(0, steplimit):
- crystal.walk_through_walls()
- #call(0x1, 0x1078)
- step()
-
- @staticmethod
- def disable_triggers():
- set_memory_at(0x23c4, 0xAF)
- set_memory_at(0x23d0, 0xAF);
-
- @staticmethod
- def disable_callbacks():
- set_memory_at(0x23f2, 0xAF)
- set_memory_at(0x23fe, 0xAF)
-
- @staticmethod
- def get_map_group_id():
- """
- Returns the current map group.
- """
- return get_memory_at(0xdcb5)
-
- @staticmethod
- def get_map_id():
- """
- Returns the map number of the current map.
- """
- return get_memory_at(0xdcb6)
-
- @staticmethod
- def get_map_name():
- """
- Figures out the current map name.
- """
- map_group_id = crystal.get_map_group_id()
- map_id = crystal.get_map_id()
- return map_names[map_group_id][map_id]["name"]
-
- @staticmethod
- def get_xy():
- """
- (x, y) coordinates of player on map.
-
- Relative to top-left corner of map.
- """
- x = get_memory_at(0xdcb8)
- y = get_memory_at(0xdcb7)
- return (x, y)
-
- @staticmethod
- def menu_select(id=1):
- """
- Sets the cursor to the given pokemon in the player's party.
-
- This is under Start -> PKMN. This is useful for selecting a
- certain pokemon with fly or another skill.
-
- This probably works on other menus.
- """
- set_memory_at(0xcfa9, id)
-
- @staticmethod
- def is_in_battle():
- """
- Checks whether or not we're in a battle.
- """
- return (get_memory_at(0xd22d) != 0) or crystal.is_in_link_battle()
-
- @staticmethod
- def is_in_link_battle():
- return get_memory_at(0xc2dc) != 0
-
- @staticmethod
- def unlock_flypoints():
- """
- Unlocks different destinations for flying.
-
- Note: this might start at 0xDCA4 (minus one on all addresses), but not
- sure.
- """
- set_memory_at(0xDCA5, 0xFF)
- set_memory_at(0xDCA6, 0xFF)
- set_memory_at(0xDCA7, 0xFF)
- set_memory_at(0xDCA8, 0xFF)
-
- @staticmethod
- def get_gender():
- """
- Returns 'male' or 'female'.
- """
- gender = get_memory_at(0xD472)
- if gender == 0:
- return "male"
- elif gender == 1:
- return "female"
- else:
- return gender
-
- @staticmethod
- def get_player_name():
- """
- Returns the 7 characters making up the player's name.
- """
- bytez = get_memory_range(0xD47D, 7)
- name = translate_chars(bytez)
- return name
-
- @staticmethod
- def warp(map_group_id, map_id, x, y):
- set_memory_at(0xdcb5, map_group_id)
- set_memory_at(0xdcb6, map_id)
- set_memory_at(0xdcb7, y)
- set_memory_at(0xdcb8, x)
- set_memory_at(0xd001, 0xFF)
- set_memory_at(0xff9f, 0xF1)
- set_memory_at(0xd432, 1)
- set_memory_at(0xd434, 0 & 251)
-
- @staticmethod
- def warp_pokecenter():
- crystal.warp(1, 1, 3, 3)
- crystal.nstep(200)
-
- @staticmethod
- def masterballs():
- # masterball
- set_memory_at(0xd8d8, 1)
- set_memory_at(0xd8d9, 99)
-
- # ultraball
- set_memory_at(0xd8da, 2)
- set_memory_at(0xd8db, 99)
-
- # pokeballs
- set_memory_at(0xd8dc, 5)
- set_memory_at(0xd8dd, 99)
-
- @staticmethod
- def get_text():
- """
- Returns alphanumeric text on the screen.
-
- Other characters will not be shown.
- """
- output = ""
- tiles = get_memory_range(0xc4a0, 1000)
- for each in tiles:
- if each in chars.keys():
- thing = chars[each]
- acceptable = False
-
- if len(thing) == 2:
- portion = thing[1:]
- else:
- portion = thing
-
- if portion in string.printable:
- acceptable = True
-
- if acceptable:
- output += thing
-
- # remove extra whitespace
- output = re.sub(" +", " ", output)
- output = output.strip()
-
- return output
-
- @staticmethod
- def keyboard_apply(button_sequence):
- """
- Applies a sequence of buttons to the on-screen keyboard.
- """
- for buttons in button_sequence:
- press(buttons)
- nstep(2)
- press([])
-
- @staticmethod
- def write(something="TrAiNeR"):
- """
- Types out a word.
-
- Uses a planning algorithm to do this in the most efficient way possible.
- """
- button_sequence = keyboard.plan_typing(something)
- crystal.keyboard_apply([[x] for x in button_sequence])
-
- @staticmethod
- def set_partymon2():
- """
- This causes corruption, so it's not working yet.
- """
- memory = get_memory()
- memory[0xdcd7] = 2
- memory[0xdcd9] = 0x7
-
- memory[0xdd0f] = 0x7
- memory[0xdd10] = 0x1
-
- # moves
- memory[0xdd11] = 0x1
- memory[0xdd12] = 0x2
- memory[0xdd13] = 0x3
- memory[0xdd14] = 0x4
-
- # id
- memory[0xdd15] = 0x1
- memory[0xdd16] = 0x2
-
- # experience
- memory[0xdd17] = 0x2
- memory[0xdd18] = 0x3
- memory[0xdd19] = 0x4
-
- # hp
- memory[0xdd1a] = 0x5
- memory[0xdd1b] = 0x6
-
- # current hp
- memory[0xdd31] = 0x10
- memory[0xdd32] = 0x25
-
- # max hp
- memory[0xdd33] = 0x10
- memory[0xdd34] = 0x40
-
- set_memory(memory)
-
- @staticmethod
- def wait_for_script_running(debug=False, limit=1000):
- """
- Wait until ScriptRunning isn't -1.
- """
- while limit > 0:
- if get_memory_at(0xd438) != 255:
- print "script is done executing"
- return
- else:
- step()
-
- if debug:
- limit = limit - 1
-
- if limit == 0:
- print "limit ran out"
-
- @staticmethod
- def move(cmd):
- """
- Attempt to move the player.
- """
- press(cmd, holdsteps=10, aftersteps=0)
- press([])
-
- memory = get_memory()
- #while memory[0xd4e1] == 2 and memory[0xd042] != 0x3e:
- while memory[0xd043] in [0, 1, 2, 3]:
- #while memory[0xd043] in [0, 1, 2, 3] or memory[0xd042] != 0x3e:
- nstep(10)
- memory = get_memory()
-
-class TestEmulator(unittest.TestCase):
- try:
- state = load_state("cheating-12")
- except:
- if "__name__" == "__main__":
- raise Exception("failed to setup unit tests because no save state found")
-
- def setUp(self):
- load_rom()
- set_state(self.state)
-
- def tearDown(self):
- shutdown()
-
- def test_PlaceString(self):
- call(0, 0x1078)
-
- # where to draw the text
- registers["hl"] = 0xc4a0
-
- # what text to read from
- registers["de"] = 0x1276
-
- nstep(10)
-
- text = crystal.get_text()
-
- self.assertTrue("TRAINER" in text)
-
-class TestWriter(unittest.TestCase):
- def test_very_basic(self):
- button_sequence = keyboard.plan_typing("an")
- expected_result = ["select", "a", "d", "r", "r", "r", "r", "a"]
-
- self.assertEqual(len(expected_result), len(button_sequence))
- self.assertEqual(expected_result, button_sequence)
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/vba/vba_autoplayer.py b/vba/vba_autoplayer.py
deleted file mode 100644
index 9aa8f4a..0000000
--- a/vba/vba_autoplayer.py
+++ /dev/null
@@ -1,495 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-Programmatic speedrun of Pokémon Crystal
-"""
-import os
-
-# bring in the emulator and basic tools
-import vba
-
-def main():
- """
- Start the game.
- """
- vba.load_rom()
-
- # get past the opening sequence
- skip_intro()
-
- # walk to mom and handle her text
- handle_mom()
-
- # walk outside into new bark town
- walk_into_new_bark_town()
-
- # walk to elm and do whatever he wants
- handle_elm("totodile")
-
- new_bark_level_grind(10, skip=False)
-
-def skippable(func):
- """
- Makes a function skippable.
-
- Saves the state before and after the function runs.
- Pass "skip=True" to the function to load the previous save
- state from when the function finished.
- """
- def wrapped_function(*args, **kwargs):
- skip = True
-
- if "skip" in kwargs.keys():
- skip = kwargs["skip"]
- del kwargs["skip"]
-
- # override skip if there's no save
- if skip:
- full_name = func.__name__ + "-end.sav"
- if not os.path.exists(os.path.join(vba.save_state_path, full_name)):
- skip = False
-
- return_value = None
-
- if not skip:
- vba.save_state(func.__name__ + "-start", override=True)
- return_value = func(*args, **kwargs)
- vba.save_state(func.__name__ + "-end", override=True)
- elif skip:
- vba.set_state(vba.load_state(func.__name__ + "-end"))
-
- return return_value
- return wrapped_function
-
-@skippable
-def skip_intro():
- """
- Skip the game boot intro sequence.
- """
-
- # copyright sequence
- vba.nstep(400)
-
- # skip the ditto sequence
- vba.press("a")
- vba.nstep(100)
-
- # skip the start screen
- vba.press("start")
- vba.nstep(100)
-
- # click "new game"
- vba.press("a", holdsteps=50, aftersteps=1)
-
- # skip text up to "Are you a boy? Or are you a girl?"
- vba.crystal.text_wait()
-
- # select "Boy"
- vba.press("a", holdsteps=50, aftersteps=1)
-
- # text until "What time is it?"
- vba.crystal.text_wait()
-
- # select 10 o'clock
- vba.press("a", holdsteps=50, aftersteps=1)
-
- # yes i mean it
- vba.press("a", holdsteps=50, aftersteps=1)
-
- # "How many minutes?" 0 min.
- vba.press("a", holdsteps=50, aftersteps=1)
-
- # "Who! 0 min.?" yes/no select yes
- vba.press("a", holdsteps=50, aftersteps=1)
-
- # read text until name selection
- vba.crystal.text_wait()
-
- # select "Chris"
- vba.press("d", holdsteps=10, aftersteps=1)
- vba.press("a", holdsteps=50, aftersteps=1)
-
- def overworldcheck():
- """
- A basic check for when the game starts.
- """
- return vba.get_memory_at(0xcfb1) != 0
-
- # go until the introduction is done
- vba.crystal.text_wait(callback=overworldcheck)
-
- return
-
-@skippable
-def handle_mom():
- """
- Walk to mom. Handle her speech and questions.
- """
-
- vba.crystal.move("r")
- vba.crystal.move("r")
- vba.crystal.move("r")
- vba.crystal.move("r")
-
- vba.crystal.move("u")
- vba.crystal.move("u")
- vba.crystal.move("u")
-
- vba.crystal.move("d")
- vba.crystal.move("d")
-
- # move into mom's line of sight
- vba.crystal.move("d")
-
- # let mom talk until "What day is it?"
- vba.crystal.text_wait()
-
- # "What day is it?" Sunday
- vba.press("a", holdsteps=10) # Sunday
-
- vba.crystal.text_wait()
-
- # "SUNDAY, is it?" yes/no
- vba.press("a", holdsteps=10) # yes
-
- vba.crystal.text_wait()
-
- # "Is it Daylight Saving Time now?" yes/no
- vba.press("a", holdsteps=10) # yes
-
- vba.crystal.text_wait()
-
- # "AM DST, is that OK?" yes/no
- vba.press("a", holdsteps=10) # yes
-
- # text until "know how to use the PHONE?" yes/no
- vba.crystal.text_wait()
-
- # press yes
- vba.press("a", holdsteps=10)
-
- # wait until mom is done talking
- vba.crystal.text_wait()
-
- # wait until the script is done running
- vba.crystal.wait_for_script_running()
-
- return
-
-@skippable
-def walk_into_new_bark_town():
- """
- Walk outside after talking with mom.
- """
-
- vba.crystal.move("d")
- vba.crystal.move("d")
- vba.crystal.move("d")
- vba.crystal.move("l")
- vba.crystal.move("l")
-
- # walk outside
- vba.crystal.move("d")
-
-@skippable
-def handle_elm(starter_choice):
- """
- Walk to Elm's Lab and get a starter.
- """
-
- # walk to the lab
- vba.crystal.move("l")
- vba.crystal.move("l")
- vba.crystal.move("l")
- vba.crystal.move("l")
- vba.crystal.move("l")
- vba.crystal.move("l")
- vba.crystal.move("l")
- vba.crystal.move("u")
- vba.crystal.move("u")
-
- # walk into the lab
- vba.crystal.move("u")
-
- # talk to elm
- vba.crystal.text_wait()
-
- # "that I recently caught." yes/no
- vba.press("a", holdsteps=10) # yes
-
- # talk to elm some more
- vba.crystal.text_wait()
-
- # talking isn't done yet..
- vba.crystal.text_wait()
- vba.crystal.text_wait()
- vba.crystal.text_wait()
-
- # wait until the script is done running
- vba.crystal.wait_for_script_running()
-
- # move toward the pokeballs
- vba.crystal.move("r")
-
- # move to cyndaquil
- vba.crystal.move("r")
-
- moves = 0
-
- if starter_choice.lower() == "cyndaquil":
- moves = 0
- if starter_choice.lower() == "totodile":
- moves = 1
- else:
- moves = 2
-
- for each in range(0, moves):
- vba.crystal.move("r")
-
- # face the pokeball
- vba.crystal.move("u")
-
- # select it
- vba.press("a", holdsteps=10, aftersteps=0)
-
- # wait for the image to pop up
- vba.crystal.text_wait()
-
- # wait for the image to close
- vba.crystal.text_wait()
-
- # wait for the yes/no box
- vba.crystal.text_wait()
-
- # press yes
- vba.press("a", holdsteps=10, aftersteps=0)
-
- # wait for elm to talk a bit
- vba.crystal.text_wait()
-
- # TODO: why didn't that finish his talking?
- vba.crystal.text_wait()
-
- # give a nickname? yes/no
- vba.press("d", holdsteps=10, aftersteps=0) # move to "no"
- vba.press("a", holdsteps=10, aftersteps=0) # no
-
- # TODO: why didn't this wait until he was completely done?
- vba.crystal.text_wait()
- vba.crystal.text_wait()
-
- # get the phone number
- vba.crystal.text_wait()
-
- # talk with elm a bit more
- vba.crystal.text_wait()
-
- # TODO: and again.. wtf?
- vba.crystal.text_wait()
-
- # wait until the script is done running
- vba.crystal.wait_for_script_running()
-
- # move down
- vba.crystal.move("d")
- vba.crystal.move("d")
- vba.crystal.move("d")
- vba.crystal.move("d")
-
- # move into the researcher's line of sight
- vba.crystal.move("d")
-
- # get the potion from the person
- vba.crystal.text_wait()
- vba.crystal.text_wait()
-
- # wait for the script to end
- vba.crystal.wait_for_script_running()
-
- vba.crystal.move("d")
- vba.crystal.move("d")
- vba.crystal.move("d")
-
- # go outside
- vba.crystal.move("d")
-
- return
-
-@skippable
-def new_bark_level_grind(level):
- """
- Do level grinding in New Bark.
-
- Starting just outside of Elm's Lab, do some level grinding until the first
- partymon level is equal to the given value..
- """
-
- # walk to the grass area
- new_bark_level_grind_walk_to_grass(skip=False)
-
- # TODO: walk around in grass, handle battles
- walk = ["d", "d", "u", "d", "u", "d"]
- for direction in walk:
- vba.crystal.move(direction)
-
- # wait for wild battle to completely start
- vba.crystal.text_wait()
-
- attacks = 5
-
- while attacks > 0:
- # FIGHT
- vba.press("a", holdsteps=10, aftersteps=1)
-
- # wait to select a move
- vba.crystal.text_wait()
-
- # SCRATCH
- vba.press("a", holdsteps=10, aftersteps=1)
-
- # wait for the move to be over
- vba.crystal.text_wait()
-
- hp = ((vba.get_memory_at(0xd218) << 8) | vba.get_memory_at(0xd217))
- print "enemy hp is: " + str(hp)
-
- if hp == 0:
- print "enemy hp is zero, exiting"
- break
- else:
- print "enemy hp is: " + str(hp)
-
- attacks = attacks - 1
-
- while vba.get_memory_at(0xd22d) != 0:
- vba.press("a", holdsteps=10, aftersteps=1)
-
- # wait for the map to finish loading
- vba.nstep(50)
-
- print "okay, back in the overworld"
-
- # move up
- vba.crystal.move("u")
- vba.crystal.move("u")
- vba.crystal.move("u")
- vba.crystal.move("u")
-
- # move into new bark town
- vba.crystal.move("r")
- vba.crystal.move("r")
- vba.crystal.move("r")
- vba.crystal.move("r")
- vba.crystal.move("r")
- vba.crystal.move("r")
- vba.crystal.move("r")
- vba.crystal.move("r")
- vba.crystal.move("r")
- vba.crystal.move("r")
-
- # move up
- vba.crystal.move("u")
- vba.crystal.move("u")
- vba.crystal.move("u")
- vba.crystal.move("u")
- vba.crystal.move("u")
-
- # move to the door
- vba.crystal.move("r")
- vba.crystal.move("r")
- vba.crystal.move("r")
-
- # walk in
- vba.crystal.move("u")
-
- # move up to the healing thing
- vba.crystal.move("u")
- vba.crystal.move("u")
- vba.crystal.move("u")
- vba.crystal.move("u")
- vba.crystal.move("u")
- vba.crystal.move("u")
- vba.crystal.move("u")
- vba.crystal.move("u")
- vba.crystal.move("u")
- vba.crystal.move("l")
- vba.crystal.move("l")
-
- # face it
- vba.crystal.move("u")
-
- # interact
- vba.press("a", holdsteps=10, aftersteps=1)
-
- # wait for yes/no box
- vba.crystal.text_wait()
-
- # press yes
- vba.press("a", holdsteps=10, aftersteps=1)
-
- # TODO: when is healing done?
-
- # wait until the script is done running
- vba.crystal.wait_for_script_running()
-
- # wait for it to be really really done
- vba.nstep(50)
-
- vba.crystal.move("r")
- vba.crystal.move("r")
-
- # move to the door
- vba.crystal.move("d")
- vba.crystal.move("d")
- vba.crystal.move("d")
- vba.crystal.move("d")
- vba.crystal.move("d")
- vba.crystal.move("d")
- vba.crystal.move("d")
- vba.crystal.move("d")
- vba.crystal.move("d")
-
- # walk out
- vba.crystal.move("d")
-
- # check partymon1 level
- if vba.get_memory_at(0xdcfe) < level:
- new_bark_level_grind(level, skip=False)
- else:
- return
-
-@skippable
-def new_bark_level_grind_walk_to_grass():
- """
- Move to just above the grass from outside Elm's lab.
- """
-
- vba.crystal.move("d")
- vba.crystal.move("d")
-
- vba.crystal.move("l")
- vba.crystal.move("l")
-
- vba.crystal.move("d")
- vba.crystal.move("d")
-
- vba.crystal.move("l")
- vba.crystal.move("l")
-
- # move to route 29 past the trees
- vba.crystal.move("l")
- vba.crystal.move("l")
- vba.crystal.move("l")
- vba.crystal.move("l")
- vba.crystal.move("l")
- vba.crystal.move("l")
- vba.crystal.move("l")
- vba.crystal.move("l")
- vba.crystal.move("l")
-
- # move to just above the grass
- vba.crystal.move("d")
- vba.crystal.move("d")
- vba.crystal.move("d")
-
-if __name__ == "__main__":
- main()
diff --git a/vba/vba_config.py b/vba/vba_config.py
deleted file mode 100644
index 4433f16..0000000
--- a/vba/vba_config.py
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/usr/bin/jython
-# -*- encoding: utf-8 -*-
-import os
-
-# by default we assume the user has vba in pokecrystal/extras
-project_path = os.path.abspath(os.path.join(os.path.dirname( __file__ ), '..'))
-
-# save states are in pokecrystal/save-states/
-save_state_path = os.path.join(project_path, "save-states")
-
-# where is your rom?
-rom_path = os.path.join(project_path, "baserom.gbc")
diff --git a/vba/vba_keyboard.py b/vba/vba_keyboard.py
deleted file mode 100644
index 7d57953..0000000
--- a/vba/vba_keyboard.py
+++ /dev/null
@@ -1,562 +0,0 @@
-# -*- encoding: utf-8 -*-
-"""
-This file constructs a networkx.DiGraph object called graph, which can be used
-to find the shortest path of keypresses on the keyboard to type a word.
-"""
-
-import itertools
-import networkx
-
-graph = networkx.DiGraph()
-
-graph_data = """
-A a select
-A B r
-A I l
-A lower-upper-column-1 u
-A J d
-
-B b select
-B A l
-B C r
-B lower-upper-column-2 u
-B K d
-
-C c select
-C D r
-C B l
-C lower-upper-column-3 u
-C L d
-
-D d select
-D E r
-D C l
-D del-upper-column-1 u
-D M d
-
-E e select
-E del-upper-column-2 u
-E N d
-E D l
-E F r
-
-F f select
-F del-upper-column-3 u
-F O d
-F E l
-F G r
-
-G g select
-G end-upper-column-1 u
-G P d
-G F l
-G H r
-
-H h select
-H end-upper-column-2 u
-H Q d
-H G l
-H I r
-
-I i select
-I end-upper-column-3 u
-I R d
-I H l
-I A r
-
-J j select
-J A u
-J S d
-J R l
-J K r
-
-K k select
-K B u
-K T d
-K J l
-K L r
-
-L l select
-L C u
-L U d
-L K l
-L M r
-
-M m select
-M D u
-M V d
-M L l
-M N r
-
-N n select
-N E u
-N W d
-N M l
-N O r
-
-O o select
-O F u
-O X d
-O N l
-O P r
-
-P p select
-P G u
-P Y d
-P O l
-P Q r
-
-Q q select
-Q H u
-Q Z d
-Q P l
-Q R r
-
-R r select
-R I u
-R space-upper-x8-y2 d
-R Q l
-R J r
-
-S s select
-S J u
-S - d
-S space-upper-x8-y2 l
-
-T t select
-T K u
-T ? d
-T S l
-T U r
-
-U u select
-U L u
-U ! d
-U T l
-U V r
-
-V v select
-V M u
-V / d
-V U l
-V W r
-
-W w select
-W N u
-W . d
-W V l
-W X r
-
-X x select
-X O u
-X , d
-X W l
-X Y r
-
-Y y select
-Y P u
-Y space-upper-x6-y3 d
-Y X l
-Y Z r
-
-Z z select
-Z Q u
-Z space-upper-x7-y3 d
-Z Y l
-Z space-upper-x8-y2 r
-
-end-upper-column-1 lower-upper-column-1 r
-end-upper-column-2 lower-upper-column-1 r
-end-upper-column-3 lower-upper-column-1 r
-end-upper-column-1 del-upper-column-1 l
-end-upper-column-2 del-upper-column-1 l
-end-upper-column-3 del-upper-column-1 l
-lower-upper-column-1 end-upper-column-1 l
-lower-upper-column-2 end-upper-column-1 l
-lower-upper-column-3 end-upper-column-1 l
-lower-upper-column-1 del-upper-column-1 r
-lower-upper-column-2 del-upper-column-1 r
-lower-upper-column-3 del-upper-column-1 r
-del-upper-column-1 lower-upper-column-1 l
-del-upper-column-2 lower-upper-column-1 l
-del-upper-column-3 lower-upper-column-1 l
-del-upper-column-1 end-upper-column-1 r
-del-upper-column-2 end-upper-column-1 r
-del-upper-column-3 end-upper-column-1 r
-
-lower-upper-column-1 A d
-lower-upper-column-2 B d
-lower-upper-column-3 C d
-lower-upper-column-1 - u
-lower-upper-column-2 ? u
-lower-upper-column-3 ! u
-
-del-upper-column-1 D d
-del-upper-column-2 E d
-del-upper-column-3 F d
-del-upper-column-1 / u
-del-upper-column-2 . u
-del-upper-column-3 , u
-
-end-upper-column-1 G d
-end-upper-column-2 H d
-end-upper-column-3 I d
-end-upper-column-1 space-upper-x6-y3 u
-end-upper-column-2 space-upper-x7-y3 u
-end-upper-column-3 space-upper-x8-y3 u
-
-space-upper-x8-y2 space-lower-x8-y2 select
-space-upper-x8-y2 R u
-space-upper-x8-y2 space-upper-x8-y3 d
-space-upper-x8-y2 Z l
-space-upper-x8-y2 S r
-
-space-upper-x8-y3 MN select
-space-upper-x8-y3 space-upper-x8-y2 u
-space-upper-x8-y3 end-upper-column-3 d
-space-upper-x8-y3 space-upper-x7-y3 l
-space-upper-x8-y3 - r
-
-space-upper-x7-y3 PK select
-space-upper-x7-y3 Z u
-space-upper-x7-y3 end-upper-column-2 d
-space-upper-x7-y3 space-upper-x6-y3 l
-space-upper-x7-y3 space-upper-x8-y3 r
-
-space-upper-x6-y3 ] select
-space-upper-x6-y3 Y u
-space-upper-x6-y3 end-upper-column-1 d
-space-upper-x6-y3 , l
-space-upper-x6-y3 space-upper-x7-y3 r
-
-end-upper-column-1 end-lower-column-1 select
-end-upper-column-2 end-lower-column-2 select
-end-upper-column-3 end-lower-column-3 select
-lower-upper-column-1 lower-lower-column-1 select
-lower-upper-column-2 lower-lower-column-2 select
-lower-upper-column-3 lower-lower-column-3 select
-del-upper-column-1 del-lower-column-1 select
-del-upper-column-2 del-lower-column-2 select
-del-upper-column-3 del-lower-column-3 select
-
-lower-lower-column-1 × u
-lower-lower-column-2 ( u
-lower-lower-column-3 ) u
-lower-lower-column-1 a d
-lower-lower-column-2 b d
-lower-lower-column-3 c d
-
-end-lower-column-1 ] u
-end-lower-column-2 PK u
-end-lower-column-3 MN u
-end-lower-column-1 g d
-end-lower-column-2 h d
-end-lower-column-3 i d
-
-del-lower-column-1 : u
-del-lower-column-2 ; u
-del-lower-column-3 [ u
-del-lower-column-1 d d
-del-lower-column-2 e d
-del-lower-column-3 f d
-
-- × select
-- S u
-- lower-upper-column-1 d
-- space-upper-x8-y3 l
-- ? r
-
-? ( select
-? T u
-? lower-upper-column-2 d
-? - l
-? ! r
-
-! ) select
-! U u
-! lower-upper-column-3 d
-! ? l
-! / r
-
-/ : select
-/ V u
-/ del-upper-column-1 d
-/ ! l
-/ . r
-
-. ; select
-. W u
-. del-upper-column-2 d
-. / l
-. , r
-
-, [ select
-, X u
-, del-upper-column-3 d
-, . l
-, space-upper-x6-y3 r
-
-× - select
-× s u
-× upper-lower-column-1 d
-× MN l
-× ( r
-
-( ? select
-( t u
-( upper-lower-column-2 d
-( × l
-( ) r
-
-) ! select
-) u u
-) upper-lower-column-3 d
-) ( l
-) : r
-
-: / select
-: v u
-: del-lower-column-1 d
-: ) l
-: ; r
-
-; . select
-; w u
-; del-lower-column-2 d
-; : l
-; [ r
-
-[ , select
-[ x u
-[ del-lower-column-3 d
-[ ; l
-[ ] r
-
-] space-upper-x6-y3 select
-] y u
-] end-lower-column-1 d
-] [ l
-] PK r
-
-PK space-upper-x7-y3 select
-PK z u
-PK end-lower-column-2 d
-PK ] l
-PK MN r
-
-MN space-upper-x8-y3 select
-MN space-lower-x8-y2 u
-MN end-lower-column-3 d
-MN PK l
-MN × r
-
-space-lower-x8-y2 space-upper-x8-y2 select
-space-lower-x8-y2 r u
-space-lower-x8-y2 MN d
-space-lower-x8-y2 z l
-space-lower-x8-y2 s r
-
-a A select
-a upper-lower-column-1 u
-a j d
-a i l
-a b r
-
-b B select
-b upper-lower-column-2 u
-b k d
-b a l
-b c r
-
-c C select
-c upper-lower-column-3 u
-c l d
-c b l
-c d r
-
-d D select
-d del-lower-column-1 u
-d m d
-d c l
-d e r
-
-e E select
-e del-lower-column-2 u
-e n d
-e d l
-e f r
-
-f F select
-f del-lower-column-3 u
-f o d
-f e l
-f g r
-
-g G select
-g end-lower-column-1 u
-g p d
-g f l
-g h r
-
-h H select
-h end-lower-column-2 u
-h q d
-h g l
-h i r
-
-i I select
-i end-lower-column-3 u
-i r d
-i h l
-i a r
-
-j J select
-j a u
-j s d
-j r l
-j k r
-
-k K select
-k b u
-k t d
-k j l
-k l r
-
-l L select
-l c u
-l u d
-l k l
-l m r
-
-m M select
-m d u
-m v d
-m l l
-m n r
-
-n N select
-n e u
-n w d
-n m l
-n o r
-
-o O select
-o f u
-o x d
-o n l
-o p r
-
-p P select
-p g u
-p y d
-p o l
-p q r
-
-q Q select
-q h u
-q z d
-q p l
-q r r
-
-r R select
-r i u
-r space-lower-x8-y2 d
-r q l
-r j r
-
-s S select
-s j u
-s × d
-s space-lower-x8-y2 l
-s t r
-
-t T select
-t k u
-t ( d
-t s l
-t u r
-
-u U select
-u l u
-u ) d
-u t l
-u v r
-
-v V select
-v m u
-v : d
-v u l
-v w r
-
-w W select
-w n u
-w ; d
-w v l
-w x r
-
-x X select
-x o u
-x [ d
-x w l
-x y r
-
-y Y select
-y p u
-y ] d
-y x l
-y z r
-
-z Z select
-z q u
-z PK d
-z y l
-z space-lower-x8-y2 r"""
-
-for line in graph_data.split("\n"):
- if line == "":
- continue
- elif line[0] == "#":
- continue
-
- (node1, node2, edge_name) = line.split(" ")
- graph.add_edge(node1, node2, key=edge_name)
-
- #print "Adding edge ("+edge_name+") "+node1+" -> "+node2
-
-def shortest_path(node1, node2):
- """
- Figures out the shortest list of button presses to move from one letter to
- another.
- """
- buttons = []
- last = None
- path = networkx.shortest_path(graph, node1, node2)
- for each in path:
- if last != None:
- buttons.append(convert_nodes_to_button_press(last, each))
- last = each
- return buttons
- #return [convert_nodes_to_button_press(node3, node4) for (node3, node4) in zip(*(iter(networkx.shortest_path(graph, node1, node2)),) * 2)]
-
-def convert_nodes_to_button_press(node1, node2):
- """
- Determines the button necessary to switch from node1 to node2.
- """
- print "getting button press for state transition: " + node1 + " -> " + node2
- return graph.get_edge_data(node1, node2)["key"]
-
-def plan_typing(text, current="A"):
- """
- Plans a sequence of button presses to spell out the given text.
- """
- buttons = []
- for target in text:
- if target == current:
- buttons.append("a")
- else:
- print "Finding the shortest path between " + current + " and " + target
- more_buttons = shortest_path(current, target)
- buttons.extend(more_buttons)
- buttons.append("a")
- current = target
- return buttons