Drawing Chessboards

2008-03-18, , , , , , , , Comments

I wanted a picture of a chessboard. Rather than boot up some drawing software and cut and paste black and white squares I decided to write a program to create the picture.

If you’d like to know why anyone would ever create work for themselves in this way, skip to the end of this article, where you’ll find justification and a more challenging follow-on problem. Otherwise, please read on from top to bottom in the usual way.

The Python Imaging Library

Chessboard created by PIL

Fredrik Lundh’s Python Imaging Library (commonly known as PIL) must surely rank as one of the most popular Python libraries which doesn’t come as standard1. It’s a fabulous tool which I’ve used to create the graphic above (though note that the double border around this graphic and subsequent ones is applied by a CSS style property). Here’s how.

PIL chessboard
def draw_chessboard(n=8, pixel_width=200):
    "Draw an n x n chessboard using PIL."
    import Image, ImageDraw
    from itertools import cycle
    def sq_start(i):
        "Return the x/y start coord of the square at column/row i."
        return i * pixel_width / n

    def square(i, j):
        "Return the square corners, suitable for use in PIL drawings" 
        return map(sq_start, [i, j, i + 1, j + 1])

    image = Image.new("L", (pixel_width, pixel_width))
    draw_square = ImageDraw.Draw(image).rectangle
    squares = (square(i, j)
               for i_start, j in zip(cycle((0, 1)), range(n))
               for i in range(i_start, n, 2))
    for sq in squares:
        draw_square(sq, fill='white')
    image.save("chessboard-pil.png")

Note:

  • We don’t draw any black squares, instead relying on the default image background being black.
  • The “L” image type (Luminance?) specifies a greyscale image.
  • PIL adopts the usual raster graphics convention, of the origin being in the top-left corner.
  • As we progress down the board row by row, the first white square alternates between being the first and second square of each row. Itertools.cycle((0, 1)) achieves this nicely.
  • A regular 8 x 8 chessboard will, then, have a black square at the bottom left, which is the usual convention. For odd values of n the bottom-left square would be white.
  • There may be rounding problems with this code if the supplied pixel width isn’t an integral multiple of n. It’s probably better to guarantee the image size, rather than round down the board size.
  • It would be better to parametrise the output file name, or even return the created image to clients. For now, we’ll just save to a fixed-name PNG.

ImageMagick

PIL is a general purpose image processing library and it takes a little head-scratching and maths before we can even create something as simple as a chessboard. ImageMagick provides tools to perform a similar job from the command-line, making the chessboard a one-liner.

ImageMagick chessboard
$ N=8
$ PIXEL_WIDTH=200
$ convert -size $((N*15))x$((N*15)) pattern:checkerboard \
  -monochrome -resize $PIXEL_WIDTH chessboard-magick.png 

Chessboard created by ImageMagick

Here, the checkerboard pattern is an ImageMagick built-in which, inspecting its output, happens to generate 15x15 squares (hence the 15’s in the script above). The -monochrome filter renders the pattern in black and white, rather than its native light- on dark-grey. The -size and -resize parameters should need no further explanation. The ((double parentheses)) perform Bash shell arithmetic.

ImageMagick masquerades as a shell tool but really it’s a powerful and fully featured programmer’s imaging tool — a bit like a command-line version of Gimp2. Although well documented, my gut reaction is that it pushes the command-line interface too far. For more advanced image mangling, you’ll probably need a program to generate the one-liner needed to drive convert. Despite this reservation, it does the simple things simply, and it can do complex things too. Recommended!

Google Chart API

For a bit of fun, we can persuade Google to render the chessboard for us — in this case as a scatter plot using a square black markers[3]. We flip the PIL processing around, drawing black squares on the (default) white background, and using the usual plotting convention which places the origin at the bottom left.

Google chart chessboard
def chessboard_url(n=8, pixel_width=200):
    "Returns the URL of a chessboard graphic."
    def sq_midpt(i):
        "Return the x/y midpt of a square in column/row i."
        # For text encoding, the graphic's logical width is 100
        return (0.5 + i) * 100. / n

    xys = [(sq_midpt(i), sq_midpt(j))
           for i_start, j in zip(cycle((0, 1)), range(n))
           for i in range(i_start, n, 2)]
    fields = dict(width=pixel_width, sqside=pixel_width/n,
                  xs=",".join("%.02f" % x for x, _ in xys),
                  ys=",".join("%.02f" % y for _, y in xys))
    return (
        "http://chart.apis.google.com/chart?"
        "cht=s&"                        # Draw a scatter graph
        "chd=t:%(xs)s|%(ys)s&"          # using text encoding and
        "chm=s,000000,1,2.0,%(sqside)r&"# square black markers
        "chs=%(width)rx%(width)r"       # at this size.
        ) % fields

Note that we plot our chart on a logical 100 x 100 rectangle, the coordinate space mandated by the encoding we’ve chosen, then resize it to the physical dimensions supplied by the client.

This function actually returns the URL of a PNG which the Google chart API serves up. Paste this URL into your browser address bar to see the graphic, or curl it to a local file.

http://chart.apis.google.com/chart?cht=s&chd=t:6.25,31.25…&chs=200x200

$ url=`python chessboard_url.py`
$ curl $url > chessboard.png

We could embed the image into HTML using the IMG element, which is how I’ve embedded the image which you should see below.

>>> from cgi import escape
>>> img = '<img src="%s" alt="chessboard graphic"/>'
>>> img % escape(chessboard_url())

Chessboard chart

As you can see, we have plenty of options, but unfortunately the image itself isn’t suitable. You can’t get rid of the axes — or at least, I haven’t found a way to — and the rendered chart has some padding to the top and the right. And worse, we’re pretty much at the end of the line for this hack: if we wanted to do something more interesting, such as place pieces on the board, we’re out of luck.

Of course this isn’t a flaw in the Google Chart API: we’ve actually asked it to draw a scatter plot of the centres of black squares on a chessboard, using square black markers, a job it’s done well enough. Some examples showing the proper use of Google charts can be found in an article I wrote about maximum sum subsequences.

ASCII Text

The chart URL might be considered a text encoding of the image; the actual graphic is returned by a server. There are other, more direct, textual representations.

ASCII art chessboard
def outer_join(sep, ss):
    """Like string.join, but encloses the result with outer separators.

    Example:
    >>> outer_join('|', ['1', '2', '3'])
    '|1|2|3|'
    """
    return "%s%s%s" % (sep, sep.join(ss), sep)

def ascii_chessboard(n=8):
    """Draws an ASCII art chessboard.

    Returns a string representation of an n x n board.
    """
    from itertools import islice, cycle
    divider = outer_join("+", "-" * n) + "\n"
    row0 = outer_join("|", islice(cycle(" B"), n)) + "\n"
    row1 = outer_join("|", islice(cycle("B "), n)) + "\n"
    return outer_join(divider, islice(cycle([row0, row1]), n))

I suspect this code was easier for me to write than it is for you to read! It treats the chessboard as a sequence of alternating rows of alternating squares, which are then joined together for output.

>>> print ascii_chessboard(8)
+-+-+-+-+-+-+-+-+
| |B| |B| |B| |B|
+-+-+-+-+-+-+-+-+
|B| |B| |B| |B| |
+-+-+-+-+-+-+-+-+
| |B| |B| |B| |B|
+-+-+-+-+-+-+-+-+
|B| |B| |B| |B| |
+-+-+-+-+-+-+-+-+
| |B| |B| |B| |B|
+-+-+-+-+-+-+-+-+
|B| |B| |B| |B| |
+-+-+-+-+-+-+-+-+
| |B| |B| |B| |B|
+-+-+-+-+-+-+-+-+
|B| |B| |B| |B| |
+-+-+-+-+-+-+-+-+

Not pretty, but such graphics may be useful in source code, which is typically viewed in a plain-text editor, and where ASCII art provides a way of embedding pictures right where they’re needed.

On which point: if you’re working through “Structure and Interpretation of Computer Programs” you may like to know the book is available in Texinfo format, with the pictures all rendered in ASCII art. So you can split your editor window and run the code on one side, while browsing the book on the other. Here’s one of the figures:

*Figure 4.6:* The `or' combination of two queries is produced by
operating on the stream of frames in parallel and merging the
results.

            +---------------------------+
            |          (or A B)         |
            |    +---+                  |
 input      | +->| A |------------+     |  output
 stream of  | |  +---+            V     |  stream of
 frames     | |    ^          +-------+ |  frames
 -------------*    |          | merge +--------------->
            | |    |          +-------+ |
            | |    |              ^     |
            | |    |   +---+      |     |
            | +------->| B +------+     |
            |      |   +---+            |
            |      |     ^              |
            |      |     |              |
            |      +--*--+              |
            +---------|-----------------+
                      |
                  data base

Even though I own a copy of the book and the full text is available on-line, this primitive info version has become my preferred format when actually running the code examples and exercises.

Unicode Block Elements

Most programming languages may be stuck in ASCII, but we needn’t restict ourselves in this way. I found some block elements in the Geometrical Symbols section of the Unicode code charts (Unicode Block Elements (PDF)). Here’s a pre-rendered block of text composed of the light and dark shade block characters, U+2591 LIGHT SHADE and U+2593 DARK SHADE.

░▓░▓░▓░▓
▓░▓░▓░▓░
░▓░▓░▓░▓
▓░▓░▓░▓░
░▓░▓░▓░▓
▓░▓░▓░▓░
░▓░▓░▓░▓
▓░▓░▓░▓░

And more

I can think of plenty of other ways to draw a chessboard. My favourite drawing environments are the pencil and paper, and the pen and whiteboard; combine the former with a scanner and the latter with a digital camera and you’ve got an easy route to an electronic version of your design.

For an HTML document I suspect SVG would be a good choice, but I don’t know enough about SVG to state this with confidence. I bet you could go a long way with CSS too. Wikipedia’s chess board is a table built on top of two small images, a light and a dark square, which I guess saves on bandwidth.

Why?

Why ever bother programming when all we want is a simple graphic?

Well, for one thing, there’s not that much programming. The actual work of pushing pixels around is done by Google, or PIL, or ImageMagick.

Once we’ve got a program written, it should be easy to adapt it. We’ve already put in hooks to specify the number of squares and the image dimensions. It’s equally easy to, for example, write out a JPEG rather than a PNG, or use different colours.

A programmatic solution is dynamic. Google’s chart API generates pictures on the fly, based on data points, ranges etc. which clients choose as and when. It’s rather like lazy-evaluation: pre-rendering all possibilities isn’t just expensive, it’s out of the question.

Teaser

Lurid chessboard

That’s quite enough pixels and characters for now, so this article will have to appear in two parts. If I’ve still not convinced you of the merits of creating images programmatically, please consider the following puzzle.

How would you draw a position reached in a game of chess, showing both the board and the pieces?

And if I have convinced you, this exercise makes for a good workout.

Some Q&A’s.

  • Q: What position, exactly?
  • A: Any!
  • Q: How will the position be described?
  • A: Your choice — it’s an interesting part of the puzzle.

A great starting point would be to solve the puzzle using an ASCII art representation.

You can find my solution in this follow-up article.

Thanks

Thanks to Marius Gedminas and Johannes Hoff for their help bug-fixing this article.


1 I’m confused about where exactly PIL belongs; the official homepage seems to be on the PythonWare website (http://www.pythonware.com/library/pil/handbook/), but I usually head for the Effbot site, http://effbot.org/imagingbook/. I think the sites mirror the same information, so it boils down to whether you prefer a blue or green theme, and how off-putting you find all the ads-by-google.

2 Actually, you can use Gimp from the command-line, and it comes with some tools for creating and editing batch files, and indeed for creating a personal suite of image processing scripts. I’ve never used Gimp in this way, so I can’t say much more about this.

[3] In theory you could use the Google Chart API to render any image in a pointillist manner: just plot enough pixels in the right places.