Got.angry? geekery

Why I wrote this game?

The game is due to a bet. Me and a colleague of mine were studying for the exams for an university course, called Logic Programming. A more proper name for it would have been "Mathematical Logic and a bit of Prolog". Anyways, a very boring course, if you ask me, and we were browsing some Prolog Examples (they shipped with Strawberry Prolog). One of the examples was a 2-D version of this game, with some primitive graphics and essentially the same gameplay.

Now, if one asks any Prolog-loving teacher about Prolog, he can be sure the teacher will praise the language for its brevity and conciseness. Also, the guys at the Strawberry Prolog were trying to show us, with this GUI game, that Prolog can be used outside the scope of boring logical problems or stupid list-manipulation stuff. But, as you can imagine, any code containing GUI is cursed to be anything but concise, and that prolog source is no exception. Moreover, the source is extemely obscure, which contradicts with the other frequently stated praise for Prolog, that goes like, "bla bla, logic programs are very intuitive". Not to mention the third drawback of Prolog, its modest speed, which is enough for THIS game, but I would love to see a good playing chess game in Prolog (e.g. one that could actually beat me).

The bet

So, the bet was, that I could implement the same game in C++, with 3D graphics and similar gameplay, in no more than 6 coding hours. No other restrictions were placed. To be honest, I was not able to cope with the bet in 6 hours (I could have been, if I implemented the Pawn primitive differently, but more on that - later), but 12 hours were sufficient. I have the snapshot of the 12-hour work on this game, which is essentially the same, without the fancy animation, slower, and without player chooser (the Prolog game didn't have that, too). The product here is, thus, a slight improvement of a 12-hour work on implementing a realtime raytracing 3D game.

Game's internals

How is this possible? Especially, if you take look at the source code, you'd be convinced it is not physically possible to be done in such a short time. The key is in code reuse. The game actually consists of a few large chunks of code I borrowed from other projects, simply glued together. From fract I borrowed most of the rendering ideas, the vista buffer code, the Vector and Matrix classes, the Camera class, etc. The pawn object is actually a SOR (surface of revolution). The surface is defined by cubic splines. The idea to use SORs for the pawns is borrowed from POV-Ray (I was browsing the POV-Ray's docs and noticed the SOR primitive, and quickly came with an idea how to implement such a primitive. Later, when browsing the POV-Ray's source code, it turned out my approach was equivallent with what they were doing). A bits of code were used from the GNU Scientific Project and the GNU Libc as well. This is yet another fact against Prolog: the availability of reuseable Prolog sources, available for free around the net, is close to none. A Prolog-ish 3D implementation of the game would have taken inordinate amounts of time to write, test and debug. Not to mention, it would require a supercomputer to actually play it.

A major target when creating the renderer was to make everything procedural: the board, the dice, the pawns (since they are not made of polygons, they are infinitely precise). The board's texture is actially a procedural one, but when running the game with the default settings, the texture is rasterized to a lookup-based texture, for performance reasons. In fact, the only thing, that is not procedural, is the "New game" button :)

Applying directly the fract's approach to rendering, the renderer is multithreaded. However, the SMP speedup is quite modest, since the small data sets and thread activation granularities heavily degrade SMP performance. The renderer's capabilities can be seen when the focal blur is enabled: the framerate drops to a few seconds per frame (even on the fastest machines), and threads' usage is close to optimal, with all CPU's getting almost 100% usage.

Porting the game was a child's play. I was using KDevelop for the whole development and so the "home OS", so to say, is Linux. I sent the source to a friend, so he could test it on his Linux, without realising, he had a 64-bit one. The source compiled and the game ran without glitches, so the 64-bit port was actually done without any efforts on my side.
The Mac OS X port took some good 8 minutes. The Win32 port took another 15 minutes. So, porting is not so hard, having SDL and well-written utilities (my cxxptl, for example).

The final probable question from you: Why not OpenGL? The OpenGL implementation will be a hell lot faster, it will probably look better, and adds a great deal of flexibility?
The answer is, it would have taken more time. I don't have some similar OGL sources around, and even readily available engines like OGRE or Irrlicht take time to learn. If I rolled my own implementation (which would not be very hard), I would have had portability problems. The OpenGL itself is portable, but the support for pixel shaders is not (or at least wasn't when I last looked at it). It would have been different if I had a framework like humus's.


The game is straightforward to compile on Linux and Mac OS X. The source, provided on this site is a standard .tar.gz with configure, make and make install steps (thanks, autotools). Things get a bit more difficult on Win32, here is what you need to do with Visual Studio 2003:

  1. Install SDL. Put the headers in your Visual Studio's include folder, with the name "SDL". E.g. if your compiler is installed in E:\VS2003, you should have E:\VS2003\Vc7\include\SDL folder, and the file SDL.h should be in E:\VS2003\Vc7\include\SDL\SDL.h.
  2. Create a new, empty, Win32 C++ console project. After Visual Studio creates the folder, copy the contents of the gotangry-1.0.tar.gz there. (E.g. if you had E:\projects\gotangry folder and E:\projects\gotangry\gotangry.vcproj project file inside it, you should have then E:\projects\gotangry\src\gotangry.cpp ).
  3. Add all .cpp files from the src/ folder to the project as sources. Similarly, add all .h files to the project as headers
  4. Copy SDL.lib, SDLmain.lib and SDL.dll in gotangry's folder
  5. Add SDL.lib and SDLmain.lib files to the project (use "add existing items" and choose "any file" to be able to add them. Be sure to add them under the "gotangry" entity, not under "sources", "headers" or "resources").
  6. Compile and have fun! Logo