MAT 364 Project Files (Combinatorial Game Theory)

Other plugins

Background

For now, until we can stablize the plugin framework and build system, the plugins need to be written in C, not C++. This is a limitation of the DLL/Shared object mechanism on all platforms. However, network clients can be written in any language. Non-network clients (sandbox clients) can be written in any language that can call C functions (which is almost all modern languages) because they need to interface directly with the plugins, which are written in C.

FilesDescription
plugin-reference.txt Information needed to write a server-side plugin. Often refered to as the rule set or validator. This text document describes the interface that plugins must support. Clients communicate with the server via this interface.
protocol-reference.txt Describes the text-based protocol (commands) that are sent between the clients and the server.
server-implementations.txt The logic behind the server implementation.
didcgaf.zip Server and sample client code. To compile and run the server you must have the GNU development tools (gcc, make, etc.) installed on your computer. Linux and Mac will likely have these by default. Windows will need to have the Cygwin utilities installed. The appropriate Cygwin tools that are installed on the Digipen computers can be downloaded from here.
libevent-1.4.14b-stable.tar.gz The networking framework. It's a nice cross-platform library, There are newer versions available (2.x), but the Windows version is a little behind the Linux and Mac versions so we have to use the 1.4 version. This isn't a problem because the server doesn't need any of the newer features. Check the main website for more information here.

Creating the Plugin (ruleset)

Since it is impossible to anticipate any and all games that the server might need to support (now and in the future), the server has been made extensible by implementing a plugin architecture. This allows for new games to be added without requiring any modification to the server code itself. In fact, the server itself has no knowledge of any games at all. It's primary job is to essentially send and receive messages (via networking) between clients and the game plugin.

The plugin is the interface between the client and the game. Since every game is different, each one will implement the plugin differently. For example, some games will only have 2 players, while others can have 3, 4, or more. How many players a game can have is captured within the plugin. The interface to this is via the AddPlayer function. The clients call this function to request entry into an existing game. The plugin will determine if there is an open spot in the game. If there is, the client will now be "in the game". If the game is full, the plugin will return a message along those lines.

Another advantage of the plugin architecture is development time. By factoring out the plugin's implementation from the server, the plugin can be developed independently from the server. Not only will this make testing and debugging simpler, it will allow you to run many more tests (i.e. test more games) because there is no networking, which can be the bottleneck when playing or testing a game.

Most of the functions are straight-forward and simple to implement. Likely, the most complex function to implement is the ValidateMove function. This function takes a player's move and validates it. This ensures that the client can't make illegal moves (either accidentally or attempting to cheat). Very simple games may have a simple set of rules, whereas complex games may have a complex set of rules.

Writing and Testing Your First Plugin (Tic-Tac-Toe Example)

Writing plugins is generally the simplest step in the process, whereas writing the AI in a client can take a very long time and require significant understanding of the rules of the game. However, in order to test the plugin, you will have to write some kind of client that will exercise the code, to make sure that the ruleset is implemented correctly. As was stated earlier, the plugin can be developed independently from the server, so that you can do all of your development and testing on a local machine (in a sandbox environment) without regards to a server and network code. Once the plugin has been thoroughly tested, it can be deployed unchanged to the server. Take note of the word unchanged. That is the goal of the sandbox environment. You want to create an environment where you can test and debug the same code that will be deployed to the server. As long as your test clients use the same interface that a networked client will use, this should happen automatically.

This example shows how you can create your first plugin without requiring the server or networking code. It's a complete, stand-alone project. Essentially, you need to create a driver to test your plugin code. The idea is that the driver will use the same interface on your plugin that the real game server would use.

The plugin and driver files:

Helper files The driver accepts one argument on the command line. It is the number of games to play. For example, this command
random-ttt 1000
would cause the driver to play 1000 games of Tic-Tac-Toe. The flow of the driver code is as follows:
  1. Read the count from the command line.
  2. Until the count is 0
    1. Create a new game by calling CreateGame in the plugin.
    2. Add the first player to the game by calling AddPlayer in the plugin.
    3. Add a second player to the game by calling AddPlayer in the plugin a second time.
    4. Call StartGame in the plugin to let the plugin know the game has started.
    5. Set the current player to 1.
    6. Until there is a win (three in a row) or a draw
      1. Pick an unoccupied random square on the board to move to.
      2. Call ValidateMove in the plugin to ensure this is a legal move. (It will be valid because the driver has already validated it, but your code could be different.)
      3. Mark that square as in-use by the current player
      4. If the game is over, either a win or draw, goto step 7
      5. Toggle the current player to the next player
    7. Call DestroyGame in the plugin.
    8. Decrement game counter
    9. Goto step B
  3. Display statistics for the games played.
This is just an overview. There are other details that you need to deal with. The source code for the test driver shows everything you need to know. Incidentally, the test driver can be written in any language you like, as long as it can call C code. This means that you can easily write your test drivers in C++. I have a GUI example below that uses C++ for the clients.

Doxygen HTML This is a good way to browse the source code.

Compiled Help File This is the Windows .chm for the project.

Tic-Tac-Toe Refactored for Real World Use

While the example above demonstrates almost everything you need to know to create a plugin and test driver, it is monolithic; all of the code for each "player" lives in the driver. It would be better to factor out the player code into separate files. This way, one person (or team) could implement one of the player's "intelligence". This makes it trivial to have one implementation play against another, possibly better, implementation. Each person (or team) would only have to supply the compiled C file (object file) for the other person (or team) to play against.

With this approach, the plugin (a.k.a ruleset) lives in one file, both players' code live in its respective file, and the test driver lives in yet another:

FilesDescription
Tic-Tac-Toe plugin (Text) This is the plugin (ruleset) for the game.
Player 1 code (Text) This is the "AI" for player 1. Currently it uses a simple brute-force approach to checking for wins and blocks.
Player 2 code (Text) This is the "AI" for player 2. Currently it uses a simple brute-force approach to checking for wins and blocks.
Driver (Text) This is the driver (or the glue) that links the plugin and the two players in a game.
Makefile A simple makefile to build the project.
ttt-dual.zip All of the necessary files in a .zip file.
The implementation for player 1 and player 2 are identical, except for the exchanging of "X" and "O" or "1" and "2" in the code. However, a few levels of intelligence are enabled via #ifdef directives.
  1. Random. No intelligence. (no #define)
  2. If the the middle square is open, take it. (#define SMART_CENTER)
  3. If the player has two-in-a-row and can make three, take the square for a win. (#define SMART_WIN)
  4. If the opponent has two-in-a-row and can make three, take the square for a block. (#define SMART_BLOCK)
See the code for more details. You should experiment with them to see how it all works and you should model your clients like this.

Another Example: Domineering

Domineering

Getting the Source Code and Building the Server and Plugins

The source code is in Digipen's subversion repository. In addition to the standard GNU build tools, you will also need cmake and subversion to be installed. If you're using Windows and Cygwin (the version from Digipen), then you already have these installed and ready to go. If you're running Linux, you may need to install them. See the Linux instructions below.

Windows

To build the projects under Windows, you must use the GNU gcc compiler and Cygwin development tools. All of the command lines below expect you to be in a bash shell, not a Windows (command prompt) shell.

Linux

Building the project under Linux is just like Windows, except if you need to install some pre-requisites, the installation is slightly different. Under Linux, you should be using the bash shell.

Automated downloading and building with a script

This is a simple bash script called install_gameserver that will do all of the steps outlined above. It works in Cygwin and in Linux. It assumes you have the proper Cygwin environment (as described above). It will also check to see if cmake and subversion are installed in Linux.

The output from running the script will look something like this: install_output.txt.

Windows Network Components

My networking components of choice are the Internet Direct (Indy) Components. They've been around for years and work very well. I gave a demonstration on using them to build a simple client/server chat program. I used these components to add the networking to this GUI Tic-Tac-Toe client:

Other Plugins