Process a List in Chunks


Once upon a time, I did this with many more lines of code. I didn’t think to use stepping with slices:

>>> evens = range(2, 18, 2)
>>> evens
[2, 4, 6, 8, 10, 12, 14, 16]
>>> for x, y in zip(evens[::2], evens[1::2]):
...     print x, y
...
2 4
6 8
10 12
14 16
>>> for a, b, c, d in zip(evens[::4], evens[1::4], evens[2::4], evens[3::4]):
...     print a, b, c, d
...
2 4 6 8
10 12 14 16

A general solution with a different approach:

>>> def chunk(the_list, size):
...     return (the_list[i:i+size] for i in xrange(0, len(the_list), size))
>>> for x, y in chunk(evens, 2):
...     print x, y
...
2 4
6 8
10 12
14 16
>>> for a, b, c, d in chunk(evens, 4):
...     print a, b, c, d
...
2 4 6 8
10 12 14 16
>>> for l in chunk(evens, 2):
...     print l
...
[2, 4]
[6, 8]
[10, 12]
[14, 16]

Note that the size argument to chunk() is not being validated.

This was taken from/inspired by a post by bearophilehugs (who always seems to be very helpful) in a wonderful thread on comp.lang.python. I suggest reading the whole thing.

Let’s Write A Pong Clone with Python and Pyglet (Part 2)


Let’s make our Pong clone playable.

Make sure you’ve read Part 1 before reading this. Below is the full source of Part 2, but I’ll only be explaining the new additions.

Please read my disclaimer if you haven’t already. Now, onto the code:

import os
import random
import pyglet
from pyglet.window import key

class Sprite(object):
    def __init__(self, x, y):
        if self.__class__.__name__ == 'Sprite':
            raise NotImplementedError('Don\'t instantiate sprite base class')

        self.x, self.y = x, y
        self.dx, self.dy = 0, 0
        self.image = images[self.__class__.__name__]
        self.w, self.h = self.image.width, self.image.height

    def draw(self):
        self.image.blit(self.x, self.y)

    def update(self):
        self.x, self.y = self.x + self.dx, self.y + self.dy
        self.draw()

class Background(Sprite):
    pass

class Paddle(Sprite):
    def start_moving(self, dy):
        self.dy = dy

    def stop_moving(self):
        self.dy = 0

    def ai(self, ball):
        if ball.y > self.y + self.h:
            self.start_moving(speed)
        elif ball.y < self.y + self.h:
            self.start_moving(-speed)

    def update(self):
        self.y = self.y + self.dy

        if self.y + self.h >= window.height:
            self.y = window.height - self.h

        if self.y <= 0:
            self.y = 0

        self.draw()

class Ball(Sprite):
    def __init__(self, x, y):
        Sprite.__init__(self, x, y)
        self.dx = random.randint(2, 6)
        self.dy = random.randint(2, 6)

    def update(self):
        self.x, self.y = self.x + self.dx, self.y + self.dy

        if collide(self, player) or collide(self, enemy):
            self.dx = -self.dx + random.randint(0, 4)
            self.dy = -self.dy + random.randint(0, 4)

            if self.dx > 6:
                self.dx = 6

            if self.dx < -6:
                self.dx = -6

            if self.dy > 6:
                self.dx > 6

        if self.y + self.h >= window.height or self.y <= 0:
            self.dy = -self.dy

        self.draw()

def load_images():
    images = {}

    for filename in os.listdir('images'):
        key = filename.split('.')[0]
        value = pyglet.image.load(os.sep.join(['images', filename]))

        images[key] = value

    return images

def collide(a, b):
    if a.y + a.h < b.y:
        return False
    if a.y > b.y + b.h:
        return False
    if a.x + a.w < b.x:
        return False
    if a.x > b.x + b.w:
        return False

    return True

def update(dt):
    background.update()
    ball.update()
    player.update()
    enemy.ai(ball)
    enemy.update()

images = load_images()

background = Background(0, 0)
player = Paddle(100, 200)
enemy = Paddle(530, 200)
ball = Ball(120, 214)

speed = 4
move_dirs = {key.UP: speed, key.DOWN: -speed}

window = pyglet.window.Window()

@window.event
def on_key_press(symbol, modifiers):
    if symbol in move_dirs.keys():
        player.start_moving(move_dirs[symbol])

@window.event
def on_key_release(symbol, modifiers):
    if symbol in move_dirs.keys() and player.dy == move_dirs[symbol]:
        player.stop_moving()

pyglet.clock.schedule(update)
pyglet.app.run()

You can download a commented version here or a zip of the whole project so far here.

Won’t you take a walk with me through the new code in Part 2?

        self.dx, self.dy = 0, 0

To make our Sprites move, we are adding velocity variables to our base Sprite’s init method. dx represents the sprite’s speed along the x axis, and dy represents the sprite’s speed along the y axis. Below is the code that makes the sprite move:

        self.x, self.y = self.x + self.dx, self.y + self.dy

This line is added to the base Sprite’s update method before draw is called. The Sprite’s position on each axis increased by its dx and dy values. When draw is called, the Sprite will appear in its new position.

    def start_moving(self, dy):
        self.dy = dy

    def stop_moving(self):
        self.dy = 0

These two movement methods are being added to the Paddle class to enable movement along the y axis. Paddles only need to move up and down, so we don’t have to worry about dx.

    def ai(self, ball):
        if ball.y > self.y + self.h:
            self.start_moving(speed)
        elif ball.y < self.y + self.h:
            self.start_moving(-speed)

Once we add this AI method to the Paddle class, we will eventually call it on update to make our opponent come alive. It’s actually a pretty horrible AI, and I am surprised it works as well as it does. It just follows the ball. If you’re wondering about the speed variable, we’ll get to that later.

    def update(self):
        self.y = self.y + self.dy

        if self.y + self.h >= window.height:
            self.y = window.height - self.h

        if self.y <= 0:
            self.y = 0

        self.draw()

Above is Paddle’s new update method. After the Paddle is moved along the y axis, we need to make sure it hasn’t gone out of the screen. This is done by testing it’s y position against the window’s height and 0 for the top and bottom edges, respectively. You’ll notice that when checking for the top bound, we have to add the Paddle’s height to it’s y position. This is because the y position is at the bottom of the Sprite, and we want to make sure that the top doesn’t go out of bounds either. Finally, we draw the Sprite just like in the base class.

    def __init__(self, x, y):
        Sprite.__init__(self, x, y)
        self.dx = random.randint(2, 6)
        self.dy = random.randint(2, 6)

Above we are overriding Ball’s init method to make each new ball float toward the enemy Paddle at a random velocity.

    def update(self):
        self.x, self.y = self.x + self.dx, self.y + self.dy

        if collide(self, player) or collide(self, enemy):
            self.dx = -self.dx + random.randint(0, 4)
            self.dy = -self.dy + random.randint(0, 4)

            if self.dx > 6:
                self.dx = 6

            if self.dx < -6:
                self.dx = -6

            if self.dy > 6:
                self.dx > 6

        if self.y + self.h >= window.height or self.y <= 0:
            self.dy = -self.dy

        self.draw()

Ball’s update needs to change a lot. After moving according to its dx and dy, we check if the Ball is colliding with either Paddle. If a collision is happening, the Ball’s dx and dy are reversed with some random speed added. This creates the reflection or bouncing off effect that happens when the Ball hits a Paddle. We are also bouncing the ball if it passes a y bound.

def collide(a, b):
    if a.y + a.h < b.y:
        return False
    if a.y > b.y + b.h:
        return False
    if a.x + a.w < b.x:
        return False
    if a.x > b.x + b.w:
        return False

    return True

This is a basic rectangle collision function that I use in all of my simple sprite-based games. Pass in two Sprites, and it returns whether or not their rectangles are overlapping (colliding).

def update(dt):
    background.update()
    ball.update()
    player.update()
    enemy.ai(ball)
    enemy.update()

Our main update function is the same except for the line where we call the enemy Paddle’s ai method.

speed = 4
move_dirs = {key.UP: speed, key.DOWN: -speed}

In the main part of our script, we are defining the speed at which our Paddles will move. With that value, we create a dictionary that maps user input (keyboard keys) to speed values. The dict is a shortcut I like to use to save code later on. You’ll notice that from pyglet.window, we imported key at the top of the script. Below, we use this dictionary to move our Paddles.

@window.event
def on_key_press(symbol, modifiers):
    if symbol in move_dirs.keys():
        player.start_moving(move_dirs[symbol])

@window.event
def on_key_release(symbol, modifiers):
    if symbol in move_dirs.keys() and player.dy == move_dirs[symbol]:
        player.stop_moving()

on_key_press and on_key_release are two pyglet.window.Window events. I am decorating their declarations with @window.event, which tells Pyglet to register these events with our instance of pyglet.window.Window (we called it “window”). You can find more about setting event handlers in Pyglet here, and there is a listing of Window’s available events on its page in the Pyglet documentation.

In case you don’t have it already, you can get a copy of Part 2 of this project here.

Run the game, and you can use the UP and DOWN arrows to control your Paddle in a fierce battle against the enemy Paddle. You may notice that collision detection is not perfect and that the game doesn’t keep track of score. Also there are no win/lose conditions or respawning of Balls.

Stay tuned for Part 3.

Countdown to Ludum Dare 12


Ludum Dare 12 is starting in less than 24 hours, and I can’t wait.

For those that don’t know, Ludum Dare is a 48-hour game development competition. A theme is provided when the clock starts, and everyone’s game must adhere to it in some way. Good times.

There’s already quite a bit of motivational insanity going on to get us all ready. You can see my particular insanity here.

You may have seen my first post on the Ludum Dare blog from that last link. It was my final update for my first competition game. The theme was “Versus”.

Let’s Write A Pong Clone with Python and Pyglet (Part 1)


Everybody loves Pong. Shall we create it?

First, make sure you have recent versions of Python and Pyglet. This tutorial was written with Python 2.5.1 and Pyglet 1.1 Beta 2 on Mac OS 10.5. I suppose you’ll need an understanding of object-oriented programming and python to really understand what’s going on here. Post any questions in the comments.

If you are unfamiliar with Pyglet, you should be able to follow along just fine, but I suggest you read the programming guide.

We’ll need a few images to recreate Pong. These include a ball, a paddle, and the background image (black with a net).

This is my reference. Below are the images I will use:

Ball Ball

Paddle Paddle

Background Background

As you can see, I chose a dark red color for these images. Dark red is brutal.

Shall we dive in, readers? First, be sure to read my disclaimer.

Here’s the code we will be working with in this part of the tutorial:

import os
import pyglet

class Sprite(object):
    def __init__(self, x, y):
        if self.__class__.__name__ == 'Sprite':
            raise NotImplementedError('Don\'t instantiate sprite base class')

        self.x, self.y = x, y
        self.image = images[self.__class__.__name__]
        self.w, self.h = self.image.width, self.image.height

    def draw(self):
        self.image.blit(self.x, self.y)

    def update(self):
        self.draw()

class Paddle(Sprite):
    pass

class Ball(Sprite):
    pass

class Background(Sprite):
    pass

def load_images():
    images = {}

    for filename in os.listdir('images'):
        key = filename.split('.')[0]
        value = pyglet.image.load(os.sep.join(['images', filename]))

        images[key] = value

    return images

def update(dt):
    background.update()
    player.update()
    enemy.update()
    ball.update()

images = load_images()

background = Background(0, 0)
player = Paddle(100, 200)
enemy = Paddle(530, 200)
ball = Ball(120, 214)

window = pyglet.window.Window()

pyglet.clock.schedule(update)
pyglet.app.run()

You can download a commented version here or zip of the whole project so far here.

Thit code will give us a window with our game objects (paddles, ball, background) blitted to the screen, but they will be stationary for this part of the tutorial. It should look like this when run:

Part 1 Outcome

Let’s walk through the code…

class Sprite(object):
    def __init__(self, x, y):
        if self.__class__.__name__ == 'Sprite':
            raise NotImplementedError('Don\'t instantiate sprite base class')

        self.x, self.y = x, y
        self.image = images[self.__class__.__name__]
        self.w, self.h = self.image.width, self.image.height

    def draw(self):
        self.image.blit(self.x, self.y)

    def update(self):
        self.draw()

This is our Sprite base class. First, I am checking that this base class is not being instantiated directly. The only reason Sprite is implemented is so that our real game objects (Paddle, Ball, and Background) can inherit the same basic functionality from it.

Next, some variables are set that have meaning in the game. x and y represent this sprite’s position on the screen starting from the bottom-left (0, 0). These values are passed into __init__, so we simply set them. The sprite’s image is set from the images dict (more about this later). Lastly, width and height are derived from the image we just set.

The draw method is a simple, single-frame blit to the screen. In this simple game, our sprites only have one static image, so we don’t have to worry about animation frames.

Finally, we call draw in the sprite’s update method. I think it’s fairly standard to implement an update method in all objects that need to be updated in the game loop. That’s how I do it, at least.

class Paddle(Sprite):
    pass

class Ball(Sprite):
    pass

class Background(Sprite):
    pass

These are our game objects. In this part of the tutorial, they will be stationary on the screen. All of the functionality required to sit on the screen is inherited from the Sprite base class.

def load_images():
    images = {}

    for filename in os.listdir('images'):
        key = filename.split('.')[0]
        value = pyglet.image.load(os.sep.join(['images', filename]))

        images[key] = value

    return images

load_images gathers our image assets into a dict keyed by sprite classname. This is a bit of convention over configuration. I expect our images (and nothing else) to be in a directory called ‘images’ and for each image to be appropriately named. This pretty basic Python except that I am calling pyglet.image.load to get a pyglet.image.ImageData object from each png. ImageData objects have the blit method that is being called by each sprite’s draw method.*

def update(dt):
    background.update()
    player.update()
    enemy.update()
    ball.update()

This is the update function that our game loop will call each frame. Everything on the screen needs to be updated each time the loop goes around.

images = load_images()

background = Background(0, 0)
player = Paddle(100, 200)
enemy = Paddle(530, 200)
ball = Ball(120, 214)

In this bit, we are loading our images and instantiating our game objects. Each constructor takes an x position and a y position (inherited from Sprite). I think I got pretty close to the original Pong as far as positioning goes. ;)

window = pyglet.window.Window()

pyglet.clock.schedule(update)
pyglet.app.run()

Finally, we init pyglet’s Window object, schedule our update function, and start the event loop. I am using pyglet.clock.schedule to run update on every clock tick, but I could have used pyglet.clock.schedule_interval to provide an interval to run update at. We don’t need that kind of control though.

By the end of Part 2, we will be able to play Pong! Until then, enjoy your stationary pong screen!

Continue to Part 2


*I hope you find the integration between load_images and Sprite.__init__ as elegant as I do. Any suggestions for alternate ways of doing this (or anything) are welcome.