# HG changeset patch # User Simon Cross # Date 1282462944 -7200 # Node ID f2c3b516741b9a4058dc9f1c041607956f4f59bd Theme is 'Caught'. Start with Skellington 1.9. diff -r 000000000000 -r f2c3b516741b README.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/README.txt Sun Aug 22 09:42:24 2010 +0200 @@ -0,0 +1,40 @@ +Your Game Title +=============== + +Entry in PyWeek #4 +Team: YOUR TEAM NAME (leave the "Team: bit") +Members: YOUR TEAM MEMBERS (leave the "Members: bit") + + +DEPENDENCIES: + +You might need to install some of these before running the game: + + Python: http://www.python.org/ + PyGame: http://www.pygame.org/ + PyOpenGL: http://pyopengl.sf.net/ + + + +RUNNING THE GAME: + +On Windows or Mac OS X, locate the "run_game.pyw" file and double-click it. + +Othewise open a terminal / console and "cd" to the game directory and run: + + python run_game.py + + + +HOW TO PLAY THE GAME: + +Move the cursor around the screen with the mouse. + +Press the left mouse button to fire the ducks. + + + +LICENSE: + +This game skellington is placed in the Public Domain. + diff -r 000000000000 -r f2c3b516741b create-upload.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/create-upload.py Sun Aug 22 09:42:24 2010 +0200 @@ -0,0 +1,63 @@ +#! /usr/bin/env python +'''Helper script for bundling up a game in a ZIP file. + +This script will bundle all game files into a ZIP file which is named as +per the argument given on the command-line. The ZIP file will unpack into a +directory of the same name. + +The script ignores: + +- CVS or SVN subdirectories +- any dotfiles (files starting with ".") +- .pyc and .pyo files + +''' + +import sys +import os +import zipfile + +if len(sys.argv) != 2: + print '''Usage: python %s + +eg. python %s my_cool_game-1.0'''%(sys.argv[0], sys.argv[0]) + sys.exit() + +base = sys.argv[1] +zipname = base + '.zip' + +try: + package = zipfile.ZipFile(zipname, 'w', zipfile.ZIP_DEFLATED) +except RuntimeError: + package = zipfile.ZipFile(zipname, 'w') + +# core files +for name in 'README.txt run_game.py'.split(): + package.write(name, os.path.join(base, name)) +package.write('run_game.py', os.path.join(base, 'run_game.pyw')) + +# utility for adding subdirectories +def add_files(generator): + for dirpath, dirnames, filenames in generator: + for name in list(dirnames): + if name == 'CVS' or name.startswith('.'): + dirnames.remove(name) + + for name in filenames: + if name.startswith('.'): continue + suffix = os.path.splitext(name)[1] + if suffix in ('.pyc', '.pyo'): continue + if name[0] == '.': continue + filename = os.path.join(dirpath, name) + package.write(filename, os.path.join(base, filename)) + +# add the lib and data directories +add_files(os.walk('gamelib')) +add_files(os.walk('data')) + +# calculate MD5 +import hashlib +d = hashlib.md5() +d.update(file(zipname, 'rb').read()) +print 'Created', zipname +print 'MD5 hash:', d.hexdigest() diff -r 000000000000 -r f2c3b516741b data/REMOVE_ME.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/data/REMOVE_ME.txt Sun Aug 22 09:42:24 2010 +0200 @@ -0,0 +1,3 @@ +This is a sentinel to make a simplistic packaging system work. + +Feel free to remove this and the "sample.txt" from your game. diff -r 000000000000 -r f2c3b516741b data/sample.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/data/sample.txt Sun Aug 22 09:42:24 2010 +0200 @@ -0,0 +1,1 @@ +This is just a sample "data" file in your data directory. diff -r 000000000000 -r f2c3b516741b gamelib/__init__.py diff -r 000000000000 -r f2c3b516741b gamelib/data.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gamelib/data.py Sun Aug 22 09:42:24 2010 +0200 @@ -0,0 +1,24 @@ +'''Simple data loader module. + +Loads data files from the "data" directory shipped with a game. + +Enhancing this to handle caching etc. is left as an exercise for the reader. +''' + +import os + +data_py = os.path.abspath(os.path.dirname(__file__)) +data_dir = os.path.normpath(os.path.join(data_py, '..', 'data')) + +def filepath(filename): + '''Determine the path to a file in the data directory. + ''' + return os.path.join(data_dir, filename) + +def load(filename, mode='rb'): + '''Open a file in the data directory. + + "mode" is passed as the second arg to open(). + ''' + return open(os.path.join(data_dir, filename), mode) + diff -r 000000000000 -r f2c3b516741b gamelib/main.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gamelib/main.py Sun Aug 22 09:42:24 2010 +0200 @@ -0,0 +1,13 @@ +'''Game main module. + +Contains the entry point used by the run_game.py script. + +Feel free to put all your game code here, or in other modules in this "gamelib" +package. +''' + +import data + +def main(): + print "Hello from your game's main()" + print data.load('sample.txt').read() diff -r 000000000000 -r f2c3b516741b pyweek-upload.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pyweek-upload.py Sun Aug 22 09:42:24 2010 +0200 @@ -0,0 +1,198 @@ +''' +Upload script specifically engineered for the PyWeek challenge. + +Handles authentication and gives upload progress feedback. +''' +import sys, os, httplib, cStringIO, socket, time, getopt + +class Upload: + def __init__(self, filename): + self.filename = filename + +boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254' +sep_boundary = '\n--' + boundary +end_boundary = sep_boundary + '--' + +def mimeEncode(data, sep_boundary=sep_boundary, end_boundary=end_boundary): + '''Take the mapping of data and construct the body of a + multipart/form-data message with it using the indicated boundaries. + ''' + ret = cStringIO.StringIO() + for key, value in data.items(): + # handle multiple entries for the same name + if type(value) != type([]): value = [value] + for value in value: + ret.write(sep_boundary) + if isinstance(value, Upload): + ret.write('\nContent-Disposition: form-data; name="%s"'%key) + filename = os.path.basename(value.filename) + ret.write('; filename="%s"\n\n'%filename) + value = open(os.path.join(value.filename), "rb").read() + else: + ret.write('\nContent-Disposition: form-data; name="%s"'%key) + ret.write("\n\n") + value = str(value) + ret.write(str(value)) + if value and value[-1] == '\r': + ret.write('\n') # write an extra newline + ret.write(end_boundary) + return ret.getvalue() + +class Progress: + def __init__(self, info, data): + self.info = info + self.tosend = len(data) + self.total = self.tosend/1024 + self.data = cStringIO.StringIO(data) + self.start = self.now = time.time() + self.sent = 0 + self.num = 0 + self.stepsize = self.total / 100 or 1 + self.steptimes = [] + self.display() + + def __iter__(self): return self + + def next(self): + self.num += 1 + if self.sent >= self.tosend: + print self.info, 'done', ' '*(75-len(self.info)-6) + sys.stdout.flush() + raise StopIteration + + chunk = self.data.read(1024) + self.sent += len(chunk) + #print (self.num, self.stepsize, self.total, self.sent, self.tosend) + + if self.num % self.stepsize: + return chunk + self.display() + return chunk + + def display(self): + # figure how long we've spent - guess how long to go + now = time.time() + steptime = now - self.now + self.steptimes.insert(0, steptime) + if len(self.steptimes) > 5: + self.steptimes.pop() + steptime = sum(self.steptimes) / len(self.steptimes) + self.now = now + eta = steptime * ((self.total - self.num)/self.stepsize) + + # tell it like it is (or might be) + if now - self.start > 3: + M = eta / 60 + H = M / 60 + M = M % 60 + S = eta % 60 + if self.total: + s = '%s %2d%% (ETA %02d:%02d:%02d)'%(self.info, + self.num * 100. / self.total, H, M, S) + else: + s = '%s 0%% (ETA %02d:%02d:%02d)'%(self.info, H, M, S) + elif self.total: + s = '%s %2d%%'%(self.info, self.num * 100. / self.total) + else: + s = '%s %d done'%(self.info, self.num) + sys.stdout.write(s + ' '*(75-len(s)) + '\r') + sys.stdout.flush() + +class progressHTTPConnection(httplib.HTTPConnection): + def progress_send(self, str): + """Send `str' to the server.""" + if self.sock is None: + self.connect() + + p = Progress('Uploading', str) + for chunk in p: + sent = 0 + while sent != len(chunk): + try: + sent += self.sock.send(chunk) + except socket.error, v: + if v[0] == 32: # Broken pipe + self.close() + raise + p.display() + +class progressHTTP(httplib.HTTP): + _connection_class = progressHTTPConnection + def _setup(self, conn): + httplib.HTTP._setup(self, conn) + self.progress_send = self._conn.progress_send + +def http_request(data, server, port, url): + h = progressHTTP(server, port) + + data = mimeEncode(data) + h.putrequest('POST', url) + h.putheader('Content-type', 'multipart/form-data; boundary=%s'%boundary) + h.putheader('Content-length', str(len(data))) + h.putheader('Host', server) + h.endheaders() + + h.progress_send(data) + + errcode, errmsg, headers = h.getreply() + + f = h.getfile() + response = f.read().strip() + f.close() + + print '%s %s'%(errcode, errmsg) + if response: print response + +def usage(): + print '''This program is to be used to upload files to the PyWeek system. +You may use it to upload screenshots or code submissions. + +REQUIRED ARGUMENTS: + -u username + -p password + -d description of file + -c file to upload + -e entry short name + +OPTIONAL ARGUMENTS: + -s file is a screenshot + -f file is FINAL submission + -h override default host name (www.pyweek.org) + -P override default host port (80) + +In order to qualify for judging at the end of the challenge, you MUST +upload your source and check the "Final Submission" checkbox. +''' + + +if __name__ == '__main__': + try: + optlist, args = getopt.getopt(sys.argv[1:], 'e:u:p:sfd:h:P:c:') + except getopt.GetoptError, message: + print message + usage() + sys.exit(1) + host = 'www.pyweek.org' + port = 80 + data = dict(version=2) + optional = {} + url = None + for opt, arg in optlist: + if opt == '-u': data['user'] = arg + elif opt == '-p': data['password'] = arg + elif opt == '-s': optional['is_screenshot'] = 'yes' + elif opt == '-f': optional['is_final'] = 'yes' + elif opt == '-d': data['description'] = arg + elif opt == '-c': data['content_file'] = Upload(arg) + elif opt == '-e': url = '/e/%s/oup/'%arg + elif opt == '-h': host = arg + elif opt == '-P': port = int(arg) + + if len(data) < 4 or url is None: + print 'Required argument missing' + usage() + sys.exit(1) + + data.update(optional) + http_request(data, host, port, url) + diff -r 000000000000 -r f2c3b516741b run_game.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/run_game.py Sun Aug 22 09:42:24 2010 +0200 @@ -0,0 +1,4 @@ +#! /usr/bin/env python + +from gamelib import main +main.main()