Raspberry Pi Minecraft ISS Tracker

This post will show you how we built a Minecraft map of the world and then used some of our previous python code to track the International Space Station on that map. It was inspired by the fact that there are now two ‘Astro Pi‘ computers in space on the ISS.

Step one is finding a suitable map and converting it into something we can use. I used the ascii art generator at picascii.com to make a text file map of the world from an image of a cylindrical projection. You can get the text file here. Download the file and save it to a folder where you will have your python code.

If you don’t have Minecraft Pi edition already then you should install by running apt-get install minecraft-pi or grab it from the website. Also have a look at this page from the Raspberry Pi website which will give you an idea of what we are doing.

Start Minecraft on your Pi and select a new world [otherwise you will lose everything!] then change desktops and open a new file in IDLE which is the python development environment and run the code below. Note: the code is for python 2.

""" Make a Map in Minecraft"""
__author__ = '@damianmooney'
from mcpi import minecraft as minecraft
from mcpi import block as block
import random


def clearZone( alocx, alocz, blocx, blocz ):
    mc.setBlocks( alocx, 1, alocz, blocx, 128, blocz, block.AIR )
    mc.setBlocks( alocx, -5, alocz, blocx, 0, blocz, block.WATER )

if __name__ == "__main__":
    mc = minecraft.Minecraft.create()
    clearZone( -128, -128, 128, 128 )
    print('Cleared')
    f = open('world3.txt', 'r')  # open your ascii art text file
    mymap = f.read()
    f.close()

    myrows = mymap.split('\n')

    print mymap

    # --start our top corner of world adjust to get 0,0 ok on map
    x = 100
    z = 85

    for i in myrows: #for each line in our map
        #print len(i)
        print i
        z -=1
        x = 100
        y = 0
        for j in i:  # go through each position on the current line
            x -=1
            if j != " ":  # if the map is not empty blank minecraft then place a grass block 
                position = (x, y, z)
                mc.setBlock(position, block.AIR)
                mc.setBlock(position, block.GRASS)
            elif j != " ":  # place water
                position = (x, y, z)
                mc.setBlock(position, block.AIR )
                mc.setBlock(position, block.WATER )


 

This code blanks the whole map, reads in our ascii art text file and then goes through each line and puts either a grass block or a water block depending on the value in that position in the text file. You can use this technique to build all sorts of things.

Hopefully you should end up with something like this.

Next we need to get the current position of the ISS so we will use the code from our previous posts. The api we are using has changed to the one by Bill Shupp and his site is here.

Now we will grab the position of the ISS and convert it to match our map dimensions. We can then update once a minute to see how things work. As we are using web based data your Pi will need an internet connection.

""" Get current ISS position from http://wheretheiss.at/ and map it on
    a raspberry pi with minecraft
"""
__author__ = '@damianmooney'
from mcpi import minecraft as minecraft
from mcpi import block as block
from datetime import datetime
import time
import urllib2
import json


def getiss():
    """ call where the iss at api thanks to Bill Shupp"""
    response = urllib2.urlopen('https://api.wheretheiss.at/v1/satellites/25544')
    mydata = response.read()
    return mydata


def do_coord(longitude):
    """ longitude: convert our longitude to a minecraft co-ordinate"""
    mine_long = longitude * -.55
    return mine_long


if __name__ == "__main__":
    mc = minecraft.Minecraft.create()
    mc.postToChat("   Minecraft ISS Tracker for @naascoderdojo")
    mc.camera.setFollow()
    mc.player.setting("autojump", False)
    mc.player.setPos(6, 20, 50)
    while True:
        iss = getiss()
        pos = json.loads(iss)
        lat = pos['latitude']
        lon = pos['longitude']

        mc.postToChat('   ISS Location Lat: %.2f Long: %.2f' % (lat,lon))
        new_long = do_coord(lon)
        mc.player.setPos(int(new_long),  20, int(lat))
        print('lon %d lat %d' % (new_long, lat))
        time.sleep(60)  # --only update once per minute - don't be greedy with api

You need to have your minecraft map running first, then switch to a second desktop on your pi and open a command window. Run the python code above and switch back to your first desktop.

Hopefully you should no see something like the image below. Double tap the space bar so your avatar hovers.

Raspberry Pi Minecraft ISS tracker

Raspberry Pi Minecraft ISS tracker

The code itself is pretty simple, we read in the json from the api, extract the latitude and longitude and then convert that to x, y, and z values in our minecraft world. The map itself is rough and ready but it is made out of blocks.

Advertisements

Raspberry PI, Python, Scratch and Minecraft

We were recently lucky enough to win 5 Raspberry PIs from the Coderdojo Foundation so figuring out what to do with them was our first challenge. In this post I will detail how I set them up so that the ninjas at the Naas-Sallins dojo could use them to improve their coding skills. They came with Raspbian installed but instructions for getting started with the PI are on the website. Knowing that the ninjas love minecraft I decided to install the special edition for the PI by following the instructions here.

Typically people use python to control the Pi edition of minecraft via its api and there is some great information on how to do that on the Stuff About Code website but after some digging about I found that it would be possible to use the Scratch extension mechanism to allow ninjas access minecraft on a remote Pi from their laptops.

The comprehensive instructions are here and you should have a read of them but in general you run a python program which talks http with scratch and translates them to instructions that the remote Pi running minecraft will understand. You then load a .s2e file which adds the minecraft blocks to scratch.

So once we got everything working with the mcpi-scratch extension it was time to see how well it works.

Using Scratch with the mcpi-scratch extension.

Using Scratch with the mcpi-scratch extension.

This screen shot shows the minecraft blocks which are found in the more blocks section and it also shows a couple of the custom blocks that are going to draw the letter they are named after in minecraft blocks.

When we run this scratch program with our mcpi-scratch helper application and extension running we get the following result.

This just gives a quick idea of what is possible, but the main advantage is that we can have multiple ninjas working on different laptops connecting to a single Pi running minecraft.

This ability to write helper apps and extensions for scratch open up a wide range of possibilities. I used the mcpi-scratch.py code as the basis for a quick test to allow scratch to tweet. I added the code from our earlier python program which uses the tweepy library.

""" messing about with Scratch2 helper app for twitter thanks to mcpi-scratch for the idea"""
import sys, traceback
import argparse, urllib
from BaseHTTPServer import BaseHTTPRequestHandler
import urlparse
import tweepy
import logging

logging.basicConfig(level=logging.DEBUG)
log = logging.getLogger(__name__)

class GetHandler(BaseHTTPRequestHandler):

    """code to hit twitter"""
    def postToTwitter(self, params):
        tweet = urllib.unquote(params[0])
        api.update_status(status=tweet)
        return ''

    def pollEvents(self, params):
        global pollInc, pollLimit, prevPosStr, posStr
        pollInc += 1
        log.debug('poll: {} {}'.format(pollInc, prevPosStr))
        if (prevPosStr != "") and (pollInc % pollLimit != 0):
            log.debug("don't call mc")
            return prevPosStr

        posStr = ''
        prevPosStr = posStr
        return posStr

    def do_GET(self):
        global api
        cmds = {
            "poll" : self.pollEvents,
            "postToTwitter" : self.postToTwitter,
        }
        parsed_path = urlparse.urlparse(self.path)

        message_parts = []
        message_parts.append('')
        cmdpath = parsed_path[2].split('/')
        print cmdpath
        handler = cmds[cmdpath[1]]
        pollResp = handler(cmdpath[2:])
        log.debug ("pollResp: {0}".format(pollResp))
        message_parts.append(pollResp)
        message = '\r\n'.join(message_parts)
        self.send_response(200)
        self.end_headers()
        self.wfile.write(message)
        return

parser = argparse.ArgumentParser(description='scratch_tweet is a Scratch2 extension helper app to allow Scratch programs to manipulate twitter via tweepy')

#enter the corresponding information for your Twitter application:
CONSUMER_KEY = 'sjkfhskjhfkjshfkjdsh'
CONSUMER_SECRET = 'fkslfjskljfklsjflkjsdldfkjslkfjlksjfkls'
ACCESS_KEY = 'sjdfklsjfkljsklfjlskjfklsjfklsjlfkjslkfjskljfkls'
ACCESS_SECRET = 'skfljslkfjskljfklsjflkjslkfjskljflksjflksjfklj'

auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET)
auth.set_access_token(ACCESS_KEY, ACCESS_SECRET)

args = parser.parse_args()
log.info(args)

pollInc = 0
pollLimit = 15
prevPosStr = ""

try:
    api = tweepy.API(auth)
except:
    e = sys.exc_info()[0]
    log.exception('cannot connect to twitter')
    traceback.print_exc(file=sys.stdout)
    sys.exit(0)

from BaseHTTPServer import HTTPServer
server = HTTPServer(('localhost', 4715), GetHandler)
log.info('Starting server, use <Ctrl-C> to stop')
server.serve_forever()</pre>
<pre>

The scratch extension associated with this program is as follows this should be saved as a .s2e file

{
 "extensionName": "scratch_tweet Py",
 "extensionPort": 4715,
 "blockSpecs": [

 [" ", "post tweet %s", "postToTwitter", "Tweet"],
 ],

 }
 }

So now you run the python program, launch scratch, hold down shift and click file and then pick import experimental http extension and open the extension above. The post tweet block should now be available to use.
scratchtweet

scratchtweetxx
This just shows what is possible with the http extension in scratch.

A-maze-in Python

In this post  for the Naas-Sallins Coder Dojo we are going to look at writing a program which will draw a maze. We will then use that code as a map to allow us to build a maze in our minecraft-clone world. So code for a maze is tricky but luckly for us someone has already written some.

The Rosetta Code website is really cool and it attempts to show solutions to common problems in as many different computer programming languages as possible.

from random import shuffle, randrange

def make_maze(w = 16, h = 8):
	vis = [[0] * w + [1] for _ in range(h)] + [[1] * (w + 1)]
	ver = [["|  "] * w + ['|'] for _ in range(h)] + [[]]
	hor = [["+--"] * w + ['+'] for _ in range(h + 1)]

	def walk(x, y):
		vis[y][x] = 1

		d = [(x - 1, y), (x, y + 1), (x + 1, y), (x, y - 1)]
		shuffle(d)
		for (xx, yy) in d:
			if vis[yy][xx]: continue
			if xx == x: hor[max(y, yy)][x] = "+  "
			if yy == y: ver[y][max(x, xx)] = "   "
			walk(xx, yy)

	walk(randrange(w), randrange(h))
	for (a, b) in zip(hor, ver):
		print(''.join(a + ['\n'] + b))

make_maze()

So as you can see its pretty complicated but if we run this piece of code we should get something like

+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|        |     |     |                    |     |
+  +  +  +  +  +  +  +  +--+--+--+--+--+  +--+  +
|  |  |     |  |  |     |     |        |        |
+--+  +--+--+  +  +--+--+--+  +  +--+  +--+--+  +
|     |     |  |  |  |        |     |  |        |
+  +--+  +--+  +  +  +  +  +  +--+  +  +  +--+--+
|  |           |  |     |  |     |  |     |     |
+  +--+  +--+--+  +  +--+  +--+--+  +--+--+  +  +
|     |  |        |     |           |        |  |
+--+  +  +  +--+--+--+  +--+--+--+--+--+--+--+  +
|     |  |  |        |        |           |     |
+  +--+--+  +--+--+  +--+--+  +--+  +--+  +  +  +
|        |        |        |        |     |  |  |
+  +--+  +--+--+--+  +  +--+--+--+--+  +--+  +  +
|     |              |                       |  |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

Our aim now is to take our main.py from our earlier minecraft clone and integerate this maze code into it. We will replace the section of code that sets up the initial landscape with our maze generation code. Step one is to make a new folder called dojomaze and copy your main.py and texture.png file to it. So if we look at the main.py we are going to change our def _initialize function to insert our maze code

def _initialize(self):
    """ Initialize the world by placing all the blocks."""

    n = 21 # make the world small enough
    s = 1 # step size
    y = 0 # initial y height
    for x in xrange(-n, n + 1, s):
        for z in xrange(-n, n + 1, s):
            # create a layer stone everywhere.
            self.add_block((x, y - 3, z), STONE, immediate=False)
            if x in (-n, n) or z in (-n, n):
                # create outer walls.
                for dy in xrange(-2, 3):
                    self.add_block((x, y + dy, z), STONE, immediate=False)
    ##---now put our maze on top-------------------------------------------------------------------
    def make_maze(w = 13, h = 19):
        vis = [[0] * w + [1] for _ in range(h)] + [[1] * (w + 1)]
        ver = [["| "] * w + ['|'] for _ in range(h)] + [[]]
        hor = [["+--"] * w + ['+'] for _ in range(h + 1)]

        def walk(x, y):
            vis[y][x] = 1
            d = [(x - 1, y), (x, y + 1), (x + 1, y), (x, y - 1)]
            random.shuffle(d)
            for (xx, yy) in d:
                if vis[yy][xx]: continue
                if xx == x: hor[max(y, yy)][x] = "+ "
                if yy == y: ver[y][max(x, xx)] = " "
                walk(xx, yy)

        walk(random.randrange(w), random.randrange(h))
        for (a, b) in zip(hor, ver):
            #--build up our map line by line
            self.mazemap = self.mazemap + (''.join(a+ ['\n'] +b + ['\n']))

make_maze()

myrows = self.mazemap.split('\n')
#--start in the corner of our would
x = -20
z = -20
for i in myrows: #for each line in our map
    z +=1
    x = -20
    for j in i: #go through each position on the current line
        x +=1
        if j != " ": #if the map is not blank in this position build a wall 3 high
            position = (x, -0, z)
            self.add_block(position,GRASS, immediate=False)
            position = (x, -1, z)
            self.add_block(position,STONE, immediate=False)
            position = (x, -2, z)
            self.add_block(position,STONE, immediate=False)
 #place treasure - our texture is adjusted to have a treasure block in it
 self.treasureposition = (18, -2, 18)
 self.add_block(self.treasureposition,TREASURE, immediate=False)

I have put these changes along with the new textures in this zip file which you can download. Have a look and we can go through the code at the next session. If you run the code you should end up with something like

Untitled

The object of the game is to navigate the maze and find the treasure. The aim of this post was just to demonstrate how we could adapt the code that we had in order to end up with something new.

Python Minecraft II – Hello World

So in this post  for the Naas-Sallins Coder Dojo we are going to look at writing a program which will allow us to alter the state of the python minecraft world which we looked at in the last post. The first thing we need to do is amend the saveModule.py file in our pymc folder to allow for the two new blocks we added. If we look at lines 9 and 11 we have the following

        self.coordDictSave = { str(main.GRASS):'GRASS', str(main.SAND):'SAND', str(main.BRICK):'BRICK', str(main.STONE):'STONE' }

        self.coordDictLoad = { 'GRASS':main.GRASS, 'SAND':main.SAND, 'BRICK':main.BRICK, 'STONE':main.STONE }

we can see the structure of the save and load lines. We don’t really need to know everything the code does to guess that we can extend it to add our 2 blocks DOJO & DOJO2 so we get

        self.coordDictSave = { str(main.GRASS):'GRASS', str(main.SAND):'SAND', str(main.BRICK):'BRICK', str(main.STONE):'STONE',str(main.DOJO):'DOJO',str(main.DOJO2):'DOJO2' }

        self.coordDictLoad = { 'GRASS':main.GRASS, 'SAND':main.SAND, 'BRICK':main.BRICK, 'STONE':main.STONE, 'DOJO':main.DOJO, 'DOJO2':main.DOJO2 }

Now when we run our main.py program we can save the world by pressing F5. This creates a file called savegame.sav in our pymc folder.

This file has the following structure.

[-8, -3, 21]=>STONE
[52, -2, -39]=>GRASS
[66, -2, 19]=>GRASS

each line in the file represents the coordinates and texture of every block in our world. We can think of these numbers as the x, y and z of our world, where x is length, y is height and z is depth. Once we know the structure of our save file it gives the opportunity to write code to change the file and the world itself.

Our first step is to make a copy of the save file which we will call savegame.bak, this is so that we can start with a default state as we test our code. In our pymc folder create and edit a new file called world.py and add the following code

import shutil

shutil.copyfile('savegame.bak','savegame.sav')
world=open('savegame.sav','a')
world.close()

In this snippet we import the shutil library which allows us to perform operations on files on our computer. Our next line simply copies our default world state from our backup savegame.bak to savegame.sav . We then show how to open and close that file. The ‘a’ in the open statement says that we are going to open the file for append, which just means that we are going to add on to the end of the file.

Next we are going to alter our world by adding lines to the savegame.sav file. In this example we are going to create a large ‘hello world’ message in blocks. So we are going to create a function which will draw each letter.


def do_h(startx,starth,starty,texture):
    """ draw the letter H """
    myletter = []
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth+1,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth+2,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth+3,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth+4,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+1,starth+2,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+2,starth+2,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+3,starth,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+3,starth+1,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+3,starth+2,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+3,starth+3,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+3,starth+4,starty,texture))
    return(myletter)

This function is different than the ones we had in earlier posts, if we look at the first line we can see that we have some values in between the brackets after our name do_h. These values are called parameters and they represent the variables that we want this function to do its work on. In this case they are startx, starth, starty, texture which represent the beginning coordinates of the first block we want to place in our world along with the texture we want to use. After that we create a new list called myletter and then begin to create the lines which will draw our letter H. We do this by adding onto the beginning position of our first block. For example if we want to add a block on top of our first (which will be part of our first leg of the letter H) we have

startx,starth+1,starty,texture

so you can see that all we are changing  is the height of the block by one in comparison to the first. To explain the rest of the line, mylist.append simply means that we add onto our list. The next bit

("[%d,%d,%d]=>%s\n" % (startx+3,starth+4,starty,texture))

says to replace the placeholders (%d for digits and %s for words) with the following variables. Really all this is saying is that we want to create a line that will have the same structure as our savegame.sav file. In general our function creates a list of the lines we want to add to our file given a start position and texture. In order to actually add this letter H to our world we need to call the function so our code becomes

import shutil
def do_h(startx,starth,starty,texture):
    """ draw the letter H """
    myletter = []
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth+1,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth+2,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth+3,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth+4,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+1,starth+2,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+2,starth+2,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+3,starth,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+3,starth+1,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+3,starth+2,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+3,starth+3,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+3,starth+4,starty,texture))
    return(myletter)

shutil.copyfile('savegame.bak','savegame.sav')
world=open('savegame.sav','a')

nextletter = do_h(20,4,-8,'DOJO2')
for i in nextletter:
    world.write(i)

world.close()

Here we can see that in order to create our H we call the function do_h and send it our values for startx, starty, startz and texture. The values passed to our function when we call it need to be in the format and order that our function expects in order for it to work. By changing these values we can alter where the letter will be placed in our world.   The variable next letter takes on the value returned by our function and we then loop through that list writing the details to our world file. If we run this program we will then be able to see our floating letter when we run our world using main.py. All that is required to spell out Hello World is to define a function for each letter and then call it with the correct starting coordinates.
helloworld

Its a fair bit to take in but once you get the hang of it you can create all sorts of objects by code alone. The full Hello world code is below. Note how once we have defined the letter, we only need to change the coordinates to position it somewhere else.

import shutil

def do_e(startx,starth,starty,texture):
    """ draw the letter E """
    myletter = []
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth+1,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth+2,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth+3,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth+4,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+1,starth+2,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+2,starth+2,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+1,starth,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+2,starth,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+1,starth+4,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+2,starth+4,starty,texture))
    return(myletter)
def do_h(startx,starth,starty,texture):
    """ draw the letter H """
    myletter = []
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth+1,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth+2,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth+3,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth+4,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+1,starth+2,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+2,starth+2,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+3,starth,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+3,starth+1,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+3,starth+2,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+3,starth+3,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+3,starth+4,starty,texture))
    return(myletter)
def do_l(startx,starth,starty,texture):
    """ draw the letter L """
    myletter = []
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth+1,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth+2,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth+3,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth+4,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+1,starth,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+2,starth,starty,texture))
    return(myletter)
def do_o(startx,starth,starty,texture):
    """ draw the letter O """
    myletter = []
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth+1,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth+2,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth+3,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth+4,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+1,starth,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+2,starth,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+1,starth+4,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+2,starth+4,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+3,starth,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+3,starth+1,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+3,starth+2,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+3,starth+3,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+3,starth+4,starty,texture))
    return(myletter)
def do_w(startx,starth,starty,texture):
    """ draw the letter W """
    myletter = []
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+1,starth,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+3,starth,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth+1,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+2,starth+1,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+4,starth+1,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth+2,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+2,starth+2,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+4,starth+2,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth+3,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+2,starth+3,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+4,starth+3,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth+4,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+4,starth+4,starty,texture))
    return(myletter)
def do_r(startx,starth,starty,texture):
    """ draw the letter R """
    myletter = []
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth+1,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth+2,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth+3,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth+4,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+1,starth+4,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+2,starth+4,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+3,starth+3,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+2,starth+2,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+1,starth+2,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+3,starth+1,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+3,starth,starty,texture))
    return(myletter)
def do_d(startx,starth,starty,texture):
    """ draw the letter O """
    myletter = []
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth+1,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth+2,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth+3,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx,starth+4,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+1,starth,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+2,starth,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+1,starth+4,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+2,starth+4,starty,texture))
    #myletter.append("[%d,%d,%d]=>%s\n" % (startx+3,starth,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+3,starth+1,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+3,starth+2,starty,texture))
    myletter.append("[%d,%d,%d]=>%s\n" % (startx+3,starth+3,starty,texture))
    return(myletter)

shutil.copyfile('savegame.bak','savegame.sav')
world=open('savegame.sav','a')

nextletter = do_h(20,4,-8,'DOJO2')
for i in nextletter:
    world.write(i)
nextletter = do_e(25,4,-8,'DOJO2')
for i in nextletter:
    world.write(i)
nextletter = do_l(29,4,-8,'DOJO2')
for i in nextletter:
    world.write(i)
nextletter = do_l(33,4,-8,'DOJO2')
for i in nextletter:
    world.write(i)
nextletter = do_o(37,4,-8,'DOJO2')
for i in nextletter:
    world.write(i)
nextletter = do_w(43,4,-8,'DOJO2')
for i in nextletter:
    world.write(i)
nextletter = do_o(49,4,-8,'DOJO2')
for i in nextletter:
    world.write(i)
nextletter = do_r(54,4,-8,'DOJO2')
for i in nextletter:
    world.write(i)
nextletter = do_l(59,4,-8,'DOJO2')
for i in nextletter:
    world.write(i)
nextletter = do_d(63,4,-8,'DOJO2')
for i in nextletter:
    world.write(i)
world.close()