This document is intended to describe the process of adding new game and AI
modules to the GGZCards module.

Contents
	1.  An overview of ggzcards
	2.  The basic protocol
	3.  Preparation
	4.  Adding a new type of deck
	5.  Players and seats
	6.  The extra game code
	7.  The game-specific code
	8.  Other advice


1.  An overview of ggzcards.

First, a word about the structure.  The current incarnation of GGZ Cards is
designed to play any sort of trick-taking card game.  The server handles
absolutely everything that is game-specific; the client is basically a dumb
terminal on which the server writes its output.  Thus, adding a new game is as
simple as adding code to the ggzcards server module and installing the new code
on your favorite server.  For the user everything should "just work".

At the server end, the game-specific code is separated into its own files.  
Each game has its own file and a collection of functions, and runtime binding
(object-oriented style, using c) is used to select the proper functions for
each game.  The common code does pretty much what you'd expect it do do: 
every trick-taking game follows the same basic structure, and this structure 
is all handled by the common code.  The game-specific code just deals with 
specific turning points in the game, basically guiding the common code in the 
proper direction.

Similarly, the ai code is separated into its own files.  Each ai has its own
file and a collection of functions, and again runtime binding is used to select
the proper functions for each AI type.  The common code calls these AI
functions as the proper times.

At the client end, there is no game-specific code.  However, the client is
designed to be able to handle a large variety of different options for games.

All of the code needed for a new game should go into six files in the server
code: cards.[ch], games.[ch], and games/<game>.[ch].

All of the code needed for a new AI module should go into four files in
the server code: ai.[ch] and ai/<ai>.[ch].


2.  The basic protocol.

At the heart of ggzcards is the game-independent nature of its communication
protocol.  This nature has its drawbacks, but at this time it seems like by
far the best thing to do.

- Bidding: the client knows nothing about different types of bids, all it
knows how to do is receive a list of possible bids and let the player pick
one of them.  The server sends the client a fixed list of text messages, each 
of which is a possible bid (for instance, in Spades this could be "nil" "0" 
"1" ... "13").  The client pops up a dialog window, from which the user picks 
one of these bids.  The client then returns the index of the bid, which the 
server uses to figure out which bid the client has made.  Most of this is 
done automatically by the common code; all that the game code has to do is 
assemble the list of bids, and interpret the bid that is returned by the 
player.

- Playing: the server sends the client a play request, requesting a play.  This
is made more complicated because in some cases a player may not play from their
own hand (for instance, playing the dummy hand in Bridge).  Thus, the server
tells the client which hand to play from.  The client then allows the player
to pick a card from that hand, and returns this card to the server.  The server
may either accept this play and send a verification message out to all clients,
or reject it and send a rejection message (along with text information about
why the play was rejected) back to the client.

- Messages: this is the most tricky part of the system, and what allows the
client to be completely game-independent.  In most server-client card games,
the server sends encoded information to the client, for instance specifically
telling the client that player X made a bid of Y.  In ggzcards, this data is
completely unencoded.  Each player gets a "message" that the server sends to
the client and the client displays prominently.  For instance, a player's
message in Spades might be "Score: 132\nBags: 2\nBid: 3\nTricks: 2".  The
client does not have to (or get to, depending on how you look at it) decide how
to come up with and display this information, it is all done by the server's
game-dependent code.

- Global messages: In addition to the player messages, there are global 
messages.  A message is sent to the client, and marked with another string.  
This other string is like the index of the message (hash-style).  Some index 
strings have special significance: for instance, the "" string marks the 
_global_ global message, which is displayed prominently; the "game" string 
marks the name of the game.  In Bridge, common examples here would be 
"" => "Contract: 6 clubs" and "game" => "Bridge".  Although these two messages 
are handled in specialized ways by the client, other messages are
intended for general display.  The idea is that there is a "message" menu, 
with one entry per marker string.  Each menu item will pop up a dialog window
which displays that message.  (This is just how the GTK client handles it;
other clients could do something different.)

- Options: options are handled very similarly to bids, but the structure is
slightly more complex.  The server sends the client a list of options, each as
multiple-choice or boolean in the form of a list.  The client pops up a dialog
window for the user to choose the options they desire, and returns a list of
indices representing their choices.  Server-side, the common code handles most
of the work.

- Etc: there's a bit more, but these are the complicated bits.


3.  Preparation.

Before you add a game, the most important thing is that you have a fundamental
understanding of the way that game works.  When I added the game Bridge, it
took under an hour because I knew what was going on, and exactly what was
needed.  In part this was because I had already implemented a very similar
game (Suaro), but I also am very familiar with the rules.  Later, when I tried
to implement Euchre (which is also very similar), things were much more
difficult because I am relatively unfamiliar with the rules of the game.  In
summary, I recommend you play the game a lot before you try to add it.

Secondly, you may wish to become familiar with the workings of GGZCards as a
whole before you start.  You might want to read through this document, take a
look at the code, and then go out and play a lot of GGZCards games.

Of course, all of this is up to you.


4.  Adding a new type of deck.

The first thing to consider when adding a new game is what deck it will use.
In the file cards.h, there is an enumeration of different types of deck.  If
your game uses an existing deck (such as a standard 52-card deck), you don't
need to do anything.  If you need a specialized deck, you should add an
enumeration for the type of deck you are going to create to cards.h, and then
in cards_create_deck(...) in cards.c add code to create this deck.  You should
be able to modify the existing code in the first half of this function in a
fairly straightforward manner.

Later, you will set game.deck_type to point to the type of deck the game uses.

In principle, the card_t structure is designed so that any type of card is
possible, including Jokers, etc.  However, the client only recognizes the
standard 52 cards at this time.  For more information about reserved card
values, see the protocol document.

A final note about cards: the "deck" itself doesn't include any information
about card ordering, except with respect to the ace.  Either ACE_HIGH or
ACE_LOW are valid card face values, and both will be interpreted properly by 
the client.  All current games use ACE_HIGH so that the ace is the high card
 by default; however, it would be easy enough to use ACE_LOW instead.  This 
doesn't technically determine the order of cards (either for sorting or for 
winning tricks), since there is game-specific code to do this.  However, this 
game-specific code defaults into taking the standard ordering of the cards and
suits.


5.  Players and seats.

Here I will describe one of the key tricky parts/innovations in the server 
code: the difference between "players" and "seats".

Specifically, a player is a person (or robot) who is physically playing the
game.  Each player has an entry in the game.players structure, and an entry
in the ggz_seats ggz-related structure (yes, a GGZ seat is really a player!).
Each player also has an assigned seat.  There is one player per client (and
vice versa).

Each seat is a spot at the table.  Most seats may be occupied by players, but
in some games some seats will not!  For instance, in Spades there are 2 players
and 2 extra hands.  These extra hands occupy two extra seats at the table.
Thus, there is one hand of cards per seat (and vice versa).  Now (and here's
the cool part) the client doesn't know anything about players.  The client
only knows about seats.  For instance, if you have a 4-player game with 6 
seats, as far as the client knows it's just a 6-player/seat game.

Although this sounds tricky, there are conventions in the code to make it
followable.  Not following them has caused bugs in the past!  There are two
data types, player_t and seat_t, that hold the ID number (index) of a player 
and of a seat.  There is a game.players and game.seats, which hold the 
information about the players and seats themselves.  There is a 
game.num_players and game.num_seats which contain the number of players and
seats in the game.  Finally, the variable "p" will be used for players and "s"
for seats (or something similar if necessary).  By following these conventions,
it should be easy enough to avoid mixing them up.


6.  The meta-game code

This code is used to track the different games, and link up each game with its
data.  This code goes in games.[ch].

In games.h there is an enumeration of different game types.  Add your game to
this enumeration.

At the top of games.c, you'll need to add an declatation for the function set
your game will use, as well as an entry into the data structure for the "data"
of your game.

7.  The game-specific code

Next, you need to add game-specific code to control the flow of the program.
All of the game-specific code is in game.[ch] and games/<game>.[ch].

Note: game.[ch] includes the *default* functions and data for all 
game-specific code.  You'll write your own functions and data and probably 
end up using a lot of the default functions; all of this will go into
games/<game>.[ch].  You'll assemble a struct of function pointers, each 
pointing to the appropriate function for your game.

First, though, you should take a look at the game structure defined in 
common.h.  Everything about the game is contained within this structure.  Near
the top of the structure, there are several flags that represent the game's
options.  By setting these appropriately, you can have the common code or
default code deal with these aspects.  At the bottom, you'll see an arbitrary
pointer.  This is intended to point to the game-specific data, which resides
in a structure declared within games/<game>.h.  Take a look at game functions
and structures for other games (in games/<game>.[ch]), and consider how your
game will be similar or different (Suaro is a good game to look at here, since
it's the most complete).

Now, you're probably ready to create your game files.  These files are 
games/<game>.c and games/<game>.h, and will contain by far the bulk of the 
code you will write.  In game.c, there are a large
number of functions.  You will write replacements for each function that needs
replacing, and place these new functions into games/<game>.c.  Each function
has a fairly self-descriptive name, and a comment describing what it does.

First, copy over the game function pointers (game_funcs) from game.c into your
file.  Rename them to <game>_funcs, which you should already have 
referenced in games.c.  At this point, the program should compile and run a 
little bit just by using the default functions.

Now, for each function, take a look at the default function 
game_<function_name> in game.c.  If that function is okay for your game, you 
don't have to do anything.  If not, then make your own function 
<game>_<function_name> in games/<game>.c and replace the function function in
the function pointer set at the top of the file.  (You'll notice that this
is entirely object-oriented, and we're basically duplicating the work of
creating different classes using just C.)


8.  Other advice.

Okay, I have no other advice.  However, if and when you get stuck please let
me know, and hopefully I can help.

Also, if any of this document seems inaccurate or unclear, tell me how I can
improve it.


--jason short
jdorje@users.sourceforge.net
June 26, 2001
