1 /* $Header: /home/jcb/MahJong/newmj/RCS/game.h,v 12.1 2012/02/01 14:10:41 jcb Rel $
2  * game.h
3  * This file contains the game data structure and associated definitions,
4  * and prototypes for some functions that work on it.
5  */
6 /****************** COPYRIGHT STATEMENT **********************
7  * This file is Copyright (c) 2000 by J. C. Bradfield.       *
8  * Distribution and use is governed by the LICENCE file that *
9  * accompanies this file.                                    *
10  * The moral rights of the author are asserted.              *
11  *                                                           *
12  ***************** DISCLAIMER OF WARRANTY ********************
13  * This code is not warranted fit for any purpose. See the   *
14  * LICENCE file for further information.                     *
15  *                                                           *
16  *************************************************************/
17 
18 #ifndef GAME_H_INCLUDED
19 #define GAME_H_INCLUDED 1
20 
21 #include "tiles.h"
22 #include "player.h"
23 
24 /* At this point, we should have option definitions. However,
25    they're needed by the protocol, and therefore included in
26    protocol.h, not this file.
27 */
28 
29 #include "protocol.h"
30 
31 /* A game is a finite state machine. This type gives the states. */
32 
33 typedef enum {
34   HandComplete = 0, /* a hand has been finished, scored, and scores settled,
35 		   but the deal has not yet rotated. The player member
36 		   contains the seat of the player who went mah jong,
37 		   or -1 if the hand was drawn.
38 		   This is also the initial state (with seat -1) after
39 		   a Game message is handled.
40 		   The claims array is used to note which
41 		   players have requested to start the next hand.
42 		    */
43   Dealing = 1, /* the deal is in progress */
44   DeclaringSpecials = 2, /* the deal is complete, and we are declaring
45 			flowers and seasons. The player member
46 			contains the seat (NB) of the player due to declare */
47   Discarding = 3, /* the current player is due to discard.
48                  The player member contains the current
49 		 player as a seat.
50 		 The tile member notes the tile that was drawn.
51 		 The whence member tells where the extra tile
52 		 obtained by the player came from:
53 		 FromWall, FromDiscard, FromLoose, FromRobbedKong.
54 		 If it was FromDiscard, the supplier holds
55 		 the *seat* of the discarder. This is needed for
56 		 scoring systems that punish such people.
57 		 The needs records if the player needs to draw
58 		 another tile, because of, say, declaring specials
59 		 or kongs. It is FromNone, FromWall, or FromLoose.
60 		 The konging records if the player has just
61 		 melded to a pung (or declared a concealed kong)
62 		 which is potentially robbable. It is
63 		 NotKonging (unset), AddingToPung, DeclaringKong; if it is
64 		 set, then tile is the tile of the kong.
65 		 The claims record may contain MahJongClaims to indicate
66 		 a desire to rob the kong.
67 	      */
68   Discarded = 4,  /* the current player has just discarded; other players are
69 		 making claims. The info record contains the following
70 		 members:
71 		 player the player that has discarded
72 		 tile   the tile that was discarded
73 		 serial  serial number of this discard
74 		 claims[seats]  contains
75 		   Discard/Chow/Pung/Kong/MahJong/NoClaim accordingly, or 0
76 		   if no claim has yet been received.
77 		 cpos  the ChowPosition, if the right hand player
78                    has made a chow claim
79 		 chowpending  true if an unspecified chow claim has been
80 		          granted, but no specified claim has yet
81                           been received.
82 	      */
83   MahJonging = 5, /* the current player has  mah jong (which we've verified) and we
84                  are declaring the hands
85                  The info record contains the following members:
86                  player  the player going mah jong
87 		 whence  where did the mahjong tile come from
88 		 supplier  if a discard/kong, who discarded (a seat)
89 		 tile    the tile that completed the hand
90 		 mjpending  if true, the mahjong was claimed
91 		          from a discard or robbed kong, but the discard
92 			  has not yet been declared in a set
93 		 chowpending mjpending, and the player has declared
94 		          a chow without specifying the position.
95 	      */
96 } GameState;
97 
98 /* This is how we index arrays of the players in the current game.
99    We used to have  noseat  #defined to be (seats)-1.
100    However, negative enums are allowed, so use them! */
101 
102 typedef enum { east = 0, south = 1, west = 2, north = 3, noseat = -1 } seats;
103 #define NUM_SEATS 4
104 
105 /* typedef for where the extra tile came from */
106 typedef enum { FromNone = 0, FromWall = 1, FromDiscard = 2,
107 	       FromLoose = 3, FromRobbedKong = 4 } Whence;
108 
109 /* typedef for robbing kong info */
110 typedef enum { NotKonging = 0, AddingToPung = 1, DeclaringKong = 2 } Konging;
111 
112 /* this typedef represents the possible claims on a discard */
113 /* It is defined that these are in priority order up to MahJong claim,
114    since these are the claims that can be made during the game.
115    The remaining values are for use during the claim of the last discard,
116    after the MahJong has been granted.
117 */
118 typedef enum { UnknownClaim = 0, NoClaim = 1, ChowClaim = 2,
119 	       PungClaim = 3, KongClaim = 4, MahJongClaim = 5,
120 	       PairClaim = 6, SpecialSetClaim = 7
121 } Claims;
122 
123 /* this is a bunch of miscellaneous flags used to keep track of
124    stuff used in scoring. They are all zeroed at start of hand */
125 typedef enum {
126   /* these two flags are used to detect kong-upon-kong. They are
127      both cleared on every discard; Kong is set upon a kong being
128      made, and KongUponKong upon a kong being made with Kong set */
129   GFKong, GFKongUponKong,
130   /* the following two flags relate to letting off a cannon.
131      If checking is on, they are set by the routines that check
132      for dangerous discards. Otherwise, they should be set in
133      response to a dangerousdiscard message from the controller.
134   */
135   GFDangerousDiscard, /* cleared on discard, and set if the discard
136 			 is dangerous and claimed */
137   GFNoChoice /* likewise, set if the dangerous discarder had no choice */
138 } GameFlags;
139 
140 /* given a pointer to game, test the flag. This returns a boolean. */
141 #define game_flag(g,f) ((g->flags & (1 << f)) && 1)
142 /* set, clear */
143 #define game_setflag(g,f) (g->flags |= (1 << f))
144 #define game_clearflag(g,f) (g->flags &= ~(1 << f))
145 
146 /* define a game option table */
147 typedef struct {
148   GameOptionEntry *options;
149   int numoptions;
150 } GameOptionTable;
151 
152 /* This structure represents an active game.
153    This is like a protocol GameMsg, plus some other stuff.
154 */
155 typedef struct _Game {
156   PlayerP players[NUM_SEATS]; /* the players */
157   TileWind round; /* wind of the current round */
158   int hands_as_east; /* number of hands completed with this dealer
159 		      (excluding current hand, except in state
160 		      HandComplete) */
161   int firsteast; /* id of player who was east in first hand of game */
162   GameState state; /* the state (see above) of the game */
163   /* state dependent extra information */
164   int active; /* players may not move unless the game is active */
165   char *paused; /* This also stops moves; but it is a pause waiting
166 		   for players' permission to receive. The non-NULL
167 		   value is the reason for the pause.
168 		   If this is set, the ready array records
169 		   who we're still waiting for */
170   /* The next fields are used for lots of auxiliary state information */
171   seats player; /* the player doing something */
172   Whence whence; /* where did the player's last tile come from? */
173   seats supplier; /* and if from a discard, who supplied it? */
174   Tile tile; /* and what was it? */
175   Whence needs; /* where does the player need to get a tile from? */
176   int serial; /* serial number of current discard/kong */
177   Claims claims[NUM_SEATS]; /* who's claimed for the current discard */
178   ChowPosition cpos; /* if a chow has been claimed, for which position? */
179   int chowpending; /* is a chow in progress? */
180   int mjpending; /* is a mah-jong from discard in progress? */
181   Konging konging; /* is a kong in progress? */
182   int ready[NUM_SEATS]; /* who is ready in a pause ? */
183   unsigned int flags; /* misc flags. This will be zeroed at start of hand */
184   /* This represents the wall.
185      There is a hard-wired array, which needs to be big enough
186      to accommodate all walls we might see.
187      The  live_used  member gives the number of tiles used from the
188      live wall; the live_end gives the end of the live wall;
189      and the dead_end gives the end of the dead wall.
190      Thus the live wall goes from live_used to (live_end-1)
191      and the dead wall from live_end to (dead_end-1).
192      Game options (will) determine how these are changed.
193      The current setting is a fixed 16-tile kong box.
194   */
195   struct {
196     Tile tiles[MAX_WALL_SIZE]; /* the tiles */
197     int live_used; /* number of live tiles drawn */
198     int live_end; /* start of dead wall */
199     int dead_end; /* end of wall */
200     int size; /* size of wall as dealt */
201   } wall;
202   /* This is a convenience to track the number of tiles of each value
203      displayed on the table. It is (always) maintained by handle_cmsg. */
204   Tile exposed_tile_count[MaxTile];
205   /* This is the same, but tracks only discards */
206   Tile discarded_tile_count[MaxTile];
207   /* the following can be set to 1 to make the handle_cmsg
208      function check the legality of all the messages.
209      Otherwise, it will apply them blindly.
210      (So client programs using this module will probably leave it zero.)
211   */
212   int cmsg_check;
213   /* This is used by handle_cmsg to return error messages
214      when it fails. */
215   char *cmsg_err;
216   int protversion; /* protocol version level for this game */
217   int manager; /* id of the player who owns this game and
218 		  can set the game options. By default, 0,
219 		  in which case any player can set options.
220 		  In that case, any player can claim ownership, first
221 		  come first served.
222 		  Can be set to -1 to prohibit any use of
223 		  managerial functions.
224 	       */
225   /* option table. */
226   GameOptionTable option_table;
227   int fd; /* for use by client programs */
228   int cseqno; /* for use by the client_ routines */
229   void *userdata; /* for client extensions */
230 } Game;
231 
232 /* game_id_to_player: return the player with the given id in the given game */
233 /* N.B. If passed an id of zero, will return the first free player
234    structure. This is a feature. */
235 PlayerP game_id_to_player(Game *g,int id);
236 
237 /* game_id_to_seat: convert an id to a seat position */
238 /* N.B. If passed an id of zero, will return the seat of the first
239    free player structure. This is a feature. */
240 seats game_id_to_seat(Game *g, int id);
241 
242 /* game_draw_tile: draw a tile from the game's live wall.
243    Return ErrorTile if no wall.
244    If the wall contents are unknown to us, this function
245    returns HiddenTile (assuming the game's wall is correctly
246    initialized!).
247 */
248 Tile game_draw_tile(Game *g);
249 
250 /* game_peek_tile: as above, but just returns the next tile
251    without actually updating the wall */
252 Tile game_peek_tile(Game *g);
253 
254 /* game_draw_loose_tile: draw one of the loose tiles,
255    or ErrorTile if no wall. Returns HiddenTile if we don't know
256    the wall.
257 */
258 Tile game_draw_loose_tile(Game *g);
259 
260 /* game_peek_loose_tile: look at loose tile
261    or ErrorTile if no wall. Returns HiddenTile if we don't know
262    the wall.
263 */
264 Tile game_peek_loose_tile(Game *g);
265 
266 /* game_handle_cmsg: takes a CMsg, and updates the game to implement
267    the CMsg. There are some important things to note:
268    The function only checks the legality of moves if the
269    game's cmsg_check field is positive. In this case,
270    this function enforces the rules of the game, at considerable
271    cost. There is no point in doing this (or trying to do this)
272    in a game structure where we don't have full knowledge; hence
273    client programs should not check cmsgs. Much of the logic
274    that used to be in the controller program has migrated into
275    this file, to avoid some code duplication.
276    The return value is a convenience:
277    the id of the affected player, for messages that affect one player;
278    0, for messages that affect all or no players;
279    -1 on legality error.
280    If there is an error, the game's cmsg_err field points
281    to a human readable error message; and the game is
282    guaranteed to be unchanged.
283    -2 on consistency errors. These are "this can't happen"
284    errors. In this case the game state is not guaranteed to
285    be unchanged, but it was inconsistent before.
286 */
287 
288 int game_handle_cmsg(Game *g, CMsgMsg *m);
289 
290 /* game_has_started: returns true if the game has started
291    (i.e. dealing of first hand has started), false otherwise */
292 int game_has_started(Game *g);
293 
294 /* This is mainly for the server. Clients should
295    query the server to determine the available options */
296 extern GameOptionTable game_default_optiontable; /* the default
297 						     option table */
298 
299 /* game_clear_option_table: clear an option table, freeing
300    the storage */
301 int game_clear_option_table(GameOptionTable *t);
302 
303 /* game_copy_option_table: copy old option table into new.
304    Will refuse to work on new table with existing data.
305 */
306 int game_copy_option_table(GameOptionTable *newt, GameOptionTable *oldt);
307 
308 /* game_set_options_from_defaults: set the option table to be
309    a copy of the default, freeing any existing table; mark options
310    enabled according to the value of g->protversion */
311 int game_set_options_from_defaults(Game *g);
312 
313 /* find an option entry in an option table, searching by integer (if known)
314    or name */
315 GameOptionEntry *game_get_option_entry_from_table(GameOptionTable *t, GameOption option, char *name);
316 /* find an option entry in the game table, searching by integer (if known)
317    or name */
318 GameOptionEntry *game_get_option_entry(Game *g, GameOption option, char *name);
319 
320 /* find an option entry in the default table, searching by integer (if known)
321    or name */
322 GameOptionEntry *game_get_default_option_entry(GameOption option, char *name);
323 
324 /* get an option value. First look in the game table; if that fails,
325    look in the default table; if that fails return the default default.
326 */
327 
328 GameOptionValue game_get_option_value(Game *g, GameOption option, char *name);
329 
330 /* set an option in table. Function will allocate space as required */
331 int game_set_option_in_table(GameOptionTable *t, GameOptionEntry *e);
332 /* set an option. Function will allocate space as required */
333 int game_set_option(Game *g, GameOptionEntry *e);
334 
335 /* debugging function: return a (possibly static) buffer holding a
336    textual dump of the game state. Second argument returns number
337    of spare bytes in the returned buffer
338 */
339 char *game_print_state(Game *g, int *bytes_left);
340 
341 /* include enum parsing options */
342 #include "game-enums.h"
343 
344 #endif /* GAME_H_INCLUDED */
345