If I have anything like ‘regular readers’ (I’m not certain from the traffic patterns on the blog whether or not that’s true), you’re probably wondering where I’ve been. The answer is, basically, the same as it ever is: writing code.
I’ve also been playing a lot of Go, and doing some tabletop roleplaying. My latest programming projects are related to those hobbies. Today I want to talk about pygo, my new Go game client.
There are already a tremendous number of game clients out there. So, why would I want to create Yet Another One? There’s always the excuse of ‘it is a learning experience’, but I also try to make things that I hope will be useful to me personally. And the problem with all of the existing Go clients is that they come in one of two styles:
- Desktop clients that are timed, and expect you to play an entire game in one brief sitting. Of these, cgoban3 is by far my favorite client (although it can only connect to its own kgs server).
- Web-based clients that expect your games to take a long time - usually you make a move, and come back later to see what your opponent has done.
I wanted a client for medium-length games: a game that unfolds over the course of an afternoon, or maybe a couple days, while the players are simultaneously doing other things. So it needs these features:
- Untimed - infinite thinking time allowed
- It is possible to put it down (close the program) and pick it back up later
- Desktop-based. Being on a website makes me feel like I should play just one move and check back much later, and I want to avoid that mentality
- Ability to play multiple simultaneous games
I couldn’t find a client that met all of these requirements, so I decided to build this one.
First steps - pygame
My first implementation of the game used pygame. Pygame is a pythonic layer on top of SDL (which I’ve talked about before, with some convenience libraries added for games. Unfortunately, this really means ‘games’ in a much more ‘modern video game’ sense, and this library felt less and less like a good fit the longer I worked with it. When I started implementing network play, it really fell apart; getting pygame to work with either threads or existing networking libraries (like Twisted) is painful. Adding widgets like buttons or menus requires adding third-party libraries, and theming them is an additional layer of work.
Here is what the pygames version looked like before I scrapped it. This represents a long weekend’s worth of very casual hacking (maybe 6-8 total hours of distraction- and interruption-filled programming):
[caption id="attachment_728” align="alignnone” width="480” caption="This looks okay, but those buttons are an eyesore, and just feel like bad UI”][/caption]
Note the fairly ugly buttons along the side; several of those buttons (Quit, Join Game, Listen) would be better off in a menu. But menus (especially via a menu bar) are non-trivial with pygame.
Now with more GTK
With pygame scrapped, I decided to use a widgeting toolkit that wasn’t aimed for games, because I don’t really need anything graphically sophisticated. GTK is an obvious choice, because I’ve used it extensively before. It was the first widgeting toolkit that I used, and it is still, in my mind, how such toolkits “should work” (I realize there are toolkits out there that may be better, but this one feels like the natural way because it is what I learned first). Python’s GTK bindings, pyGTK, are really good.
So, in much less time than it took me to create the previous version of the game, I had re-implemented it in GTK. To be fair, I didn’t have to re-implement any of the actual Go logic, because that was encapsulated in a GUI-element-free class (good programming technique pays off). I also haven’t started working on the networking code again yet, but I’m pretty sure Twisted can integrate into GTK’s event loop seamlessly, giving me sensible threads-free networking.
Anyway, here is what we have now:
[caption id="attachment_729” align="alignnone” width="480” caption="Notice the menu bar and the nicer-looking buttons."][/caption]
Much prettier. We even have a menu bar, with all of the cruft unrelated to a specific game hidden away. Even better, with Glade laying out and drawing that menu is free - it doesn’t require me to write a single line of code. I just tell glade what function to call when each menu item is clicked, and it handles all of the boring GUI stuff.
The biggest problem I’ve run into with the GTK version was also a problem I had with pygame - the board graphics take a long time to update. With GTK it is especially problematic when I try to redraw the board.
So, I modified the Goban class (which has all of the Go game logic) to return a list of positions that should be re-checked for new information. Then, in GTK, I only redraw the parts of the board that may have changed. This makes the game perfectly responsive - no detectable delay. And using python’s list data type makes this beautifully easy and elegant.
There’s still a lot of work to do here. I plan on having direct peer-to-peer network connections, as well as having a server that players can connect to. Playing multiple games simultaneously isn’t implemented yet (although with GTK, this should be almost trivial). I may implement timed games as an option, and alternate board sizes, komi, etc. still need to be possible. The code can’t do scoring.
Now that the project is in pretty good starting shape, it’s also available on github.