1 /*
2  *   XFrisk - The classic board game for X
3  *   Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com)
4  *
5  *   This program is free software; you can redistribute it and/or modify
6  *   it under the terms of the GNU General Public License as published by
7  *   the Free Software Foundation; either version 2 of the License, or
8  *   (at your option) any later version.
9  *
10  *   This program is distributed in the hope that it will be useful,
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *   GNU General Public License for more details.
14  *
15  *   You should have received a copy of the GNU General Public License
16  *   along with this program; if not, write to the Free Software
17  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  *   $Id: aiController.c,v 1.4 1999/11/13 21:58:30 morphy Exp $
20  */
21 
22 #include "aiController.h"
23 #include "aiClient.h"
24 #include "client.h"
25 #include "riskgame.h"
26 #include "game.h"
27 #include "debug.h"
28 
29 /* Prototypes */
30 Int32  CLNT_GetCommLinkOfClient(Int32 iThisClient);
31 
32 /* Externs */
33 extern void  *(*__AI_Callback)(void *, Int32, void *);
34 extern void  *pvContext[MAX_PLAYERS];
35 extern Int32  iState, iCurrentPlayer;
36 extern Flag   fGameStarted;
37 
38 /* Globals */
39 Flag          fPlayerFortified;
40 
41 
42 /************************************************************************
43  *  FUNCTION: AI_Init
44  *  HISTORY:
45  *     04.23.95  ESF  Created.
46  *  PURPOSE:
47  *  NOTES:
48  ************************************************************************/
AI_Init(void)49 void AI_Init(void)
50 {
51   fPlayerFortified=FALSE;
52   fGameStarted = FALSE;
53   fGetsCard=FALSE;
54 }
55 
56 
57 /************************************************************************
58  *  FUNCTION: AI_CheckCards
59  *  HISTORY:
60  *     03.31.95  ESF  Created.
61  *     28.08.95  JC   If the computerized must exchange cards then do.
62                       (copy of ExchangeCards)
63  *  PURPOSE:
64  *  NOTES:
65  ************************************************************************/
AI_CheckCards(void)66 void AI_CheckCards(void)
67 {
68   Int32 i, j, nb, typ, piCards[4], nbCards[4], piCardValues[MAX_CARDS];
69   Flag  fOptimal;
70 
71   if (RISK_GetNumCardsOfPlayer (iCurrentPlayer) <= 4)
72     return;
73 #ifdef ENGLISH
74   printf("AI: Error -- Checking cards.\n");
75 #endif
76 #ifdef FRENCH
77   printf("IA: Erreur -- V�rification des cartes.\n");
78 #endif
79 
80   nb = RISK_GetNumCardsOfPlayer(iCurrentPlayer);
81   do
82     {
83       piCards[0]=piCards[1]=piCards[2]=piCards[3]=-1;
84       nbCards[0]=nbCards[1]=nbCards[2]=nbCards[3]=0;
85       fOptimal = FALSE;
86       for (i=0; i<nb; i++)
87         {
88           piCardValues[i] = RISK_GetCardOfPlayer(iCurrentPlayer, i);
89           /* Set the type of the card */
90           if (piCardValues[i]<NUM_COUNTRIES)
91             {
92               typ = piCardValues[i] % 3;
93               nbCards[typ]++;
94               if (RISK_GetOwnerOfCountry(piCardValues[i]) == iCurrentPlayer)
95                   piCards[typ] = i;
96               else if (piCards[typ] == -1)
97                   piCards[typ] = i;
98             }
99           else  /* Joker */
100             {
101 	      piCards[3] = i;
102 	      nbCards[3]++;
103 	    }
104         }
105       if ((nbCards[0]>0)&&(nbCards[1]>0)&&(nbCards[2]>0))
106         {
107           AI_ExchangeCards(piCards);
108           fOptimal = TRUE;
109         }
110       else if (nb >= 5)
111         {
112           if ((nbCards[0]>0)&&(nbCards[1]>0)&&(nbCards[3]>0))
113               piCards[2] = piCards[3];
114           else if ((nbCards[0]>0)&&(nbCards[3]>0)&&(nbCards[2]>0))
115               piCards[1] = piCards[3];
116           else if ((nbCards[3]>0)&&(nbCards[1]>0)&&(nbCards[2]>0))
117               piCards[0] = piCards[3];
118           else if (nbCards[0]>=3)
119             {
120               j = 0;
121               for (i=0; i<nb; i++)
122                   if ((piCardValues[i] % 3) == 0)
123                       piCards[j++]=i;
124             }
125           else if (nbCards[1]>=3)
126             {
127               j = 0;
128               for (i=0; i<nb; i++)
129                   if ((piCardValues[i] % 3) == 1)
130                       piCards[j++]=i;
131             }
132           else if (nbCards[2]>=3)
133             {
134               j = 0;
135               for (i=0; i<nb; i++)
136                   if ((piCardValues[i] % 3) == 2)
137                       piCards[j++]=i;
138             }
139           else
140             {
141               piCards[0] = 0;
142               piCards[1] = 1;
143               piCards[2] = 2;
144             }
145           AI_ExchangeCards(piCards);
146         }
147       nb = RISK_GetNumCardsOfPlayer(iCurrentPlayer);
148     }
149   while ((fOptimal && (nb >= 3)) || (nb >= 5));
150 }
151 
152 
153 /************************************************************************
154  *  FUNCTION: AI_CheckFortification
155  *  HISTORY:
156  *     03.31.95  ESF  Created.
157  *  PURPOSE:
158  *  NOTES:
159  ************************************************************************/
AI_CheckFortification(void)160 void AI_CheckFortification(void)
161 {
162   /* If the player hasn't fortified yet, do it */
163   if (!fPlayerFortified)
164     {
165       Int32 i;
166 
167 #ifdef ENGLISH
168       printf("AI: Error -- Checking fortification.\n");
169 #endif
170 #ifdef FRENCH
171       printf("IA: Erreur -- V�rification de la fortification.\n");
172 #endif
173 
174       /* Place an army in the first country we find */
175       for (i=0; i!=NUM_COUNTRIES; i++)
176 	if (RISK_GetOwnerOfCountry(i) == iCurrentPlayer)
177 	  {
178 	    AI_Place(i, 1);
179 	    return;
180 	  }
181 
182       D_Assert(FALSE, "Player didn't own any countries??");
183     }
184 }
185 
186 
187 /************************************************************************
188  *  FUNCTION: AI_CheckPlacement
189  *  HISTORY:
190  *     03.31.95  ESF  Created.
191  *  PURPOSE:
192  *  NOTES:
193  ************************************************************************/
AI_CheckPlacement(void)194 void AI_CheckPlacement(void)
195 {
196   if (RISK_GetNumArmiesOfPlayer(iCurrentPlayer) != 0)
197     {
198       Int32 i;
199 
200 #ifdef ENGLISH
201       printf("AI: Error -- Checking placement.\n");
202 #endif
203 #ifdef FRENCH
204       printf("IA: Erreur -- V�rification du placement.\n");
205 #endif
206       /* Dump the armies on the first country */
207       for (i=0; i!=NUM_COUNTRIES; i++)
208 	if (RISK_GetOwnerOfCountry(i) == iCurrentPlayer)
209 	  {
210 	    AI_Place(i, RISK_GetNumArmiesOfPlayer(iCurrentPlayer));
211 	    return;
212 	  }
213 
214       D_Assert(FALSE, "Player didn't own any countries??");
215     }
216 }
217 
218 
219 /************************************************************************
220  *  FUNCTION: AI_Place
221  *  HISTORY:
222  *     03.31.95  ESF  Created.
223  *     21.08.95  JC   AI_CheckCards if game is started.
224  *     28.08.95  JC   No AI_CheckCards.
225  *  PURPOSE:
226  *  NOTES:
227  ************************************************************************/
AI_Place(Int32 iCountry,Int32 iNumArmies)228 Flag AI_Place(Int32 iCountry, Int32 iNumArmies)
229 {
230   if (GAME_ValidPlaceDst(iCountry) &&
231       iNumArmies <= RISK_GetNumArmiesOfPlayer(iCurrentPlayer) &&
232       ((iState == STATE_FORTIFY && iNumArmies == 1) ||
233        iState != STATE_FORTIFY))
234     {
235       GAME_PlaceArmies(iCountry, iNumArmies);
236 
237       /* Player has fortified if in fortification stage */
238       fPlayerFortified = TRUE;
239 
240       return TRUE;
241     }
242   else
243     {
244 #ifdef ENGLISH
245       printf("AI: Error -- illegal place (%d, %d)\n", iCountry, iNumArmies);
246 #endif
247 #ifdef FRENCH
248       printf("IA: Erreur -- placement ill�gal (%d, %d)\n", iCountry, iNumArmies);
249 #endif
250       return FALSE;
251     }
252 }
253 
254 
255 /************************************************************************/
256 
257 Int32 iMoveMode;
258 
259 
260 /************************************************************************
261  *  FUNCTION: AI_Attack
262  *  HISTORY:
263  *     03.31.95  ESF  Created.
264  *     23.08.95  JC   Corrected a bug if iSrcCountry or iDstCountry are
265  *                    totally invalid.
266  *                    If ARMIES_MOVE_MANUAL, conserve NumArmiesOfPlayer.
267  *     30.08.95  JC   Do the move immediatly.
268  *  PURPOSE:
269  *  NOTES:
270  ************************************************************************/
AI_Attack(Int32 iSrcCountry,Int32 iDstCountry,Int32 iAttack,Int32 iDice,Int32 iMoveSelectMode)271 Flag AI_Attack(Int32 iSrcCountry, Int32 iDstCountry, Int32 iAttack,
272 	       Int32 iDice, Int32 iMoveSelectMode)
273 {
274   Int32 iAttackMode, iDiceMode;
275   char  *srcName, *dstName;
276 
277   iMoveMode = iMoveSelectMode;
278   /* Set the modes for the attack */
279   switch (iDice)
280     {
281     case DICE_ONE:
282       iDiceMode   = ATTACK_ONE;
283       break;
284     case DICE_TWO:
285       iDiceMode   = ATTACK_TWO;
286       break;
287     case DICE_THREE:
288       iDiceMode   = ATTACK_THREE;
289       break;
290     case DICE_MAXIMUM:
291       iDiceMode   = ATTACK_AUTO;
292       break;
293     default:
294 #ifdef ENGLISH
295       printf("AI: Error -- choosing dice mode for attack.\n");
296 #endif
297 #ifdef FRENCH
298       printf("IA: Erreur -- choix du mode des d�s pour combattre.\n");
299 #endif
300       return FALSE;
301     }
302 
303   switch (iAttack)
304     {
305     case ATTACK_ONCE:
306       iAttackMode = ACTION_ATTACK;
307       break;
308     case ATTACK_DOORDIE:
309       iAttackMode = ACTION_DOORDIE;
310       break;
311     default:
312 #ifdef ENGLISH
313       printf("AI: Error -- choosing attack mode for attack.\n");
314 #endif
315 #ifdef FRENCH
316       printf("IA: Erreur -- choix du mode d'attaque pour combattre.\n");
317 #endif
318       return FALSE;
319     }
320 
321   RISK_SetAttackModeOfPlayer(iCurrentPlayer, iAttackMode);
322   RISK_SetDiceModeOfPlayer(iCurrentPlayer, iDiceMode);
323 
324   /* BUG -- return true if victory? */
325 
326   if (GAME_ValidAttackSrc(iSrcCountry, TRUE) &&
327       GAME_ValidAttackDst(iSrcCountry, iDstCountry, TRUE) &&
328       GAME_ValidAttackDice(iDiceMode, iSrcCountry))
329     {
330       GAME_Attack(iSrcCountry, iDstCountry);
331       return TRUE;
332     }
333   else
334     {
335       if ((iSrcCountry>=0) && (iSrcCountry<NUM_COUNTRIES))
336           srcName = RISK_GetNameOfCountry(iSrcCountry);
337       else
338           srcName = "";
339       if ((iDstCountry>=0) && (iDstCountry<NUM_COUNTRIES))
340           dstName = RISK_GetNameOfCountry(iDstCountry);
341       else
342           dstName = "";
343 #ifdef ENGLISH
344       printf("AI: Error -- illegal attack (%s --> %s)\n",
345 #endif
346 #ifdef FRENCH
347       printf("IA: Erreur -- ill�gall attaque (%s --> %s)\n",
348 #endif
349 	     srcName, dstName);
350       return FALSE;
351     }
352 }
353 
354 
355 /************************************************************************
356  *  FUNCTION: AI_Move
357  *  HISTORY:
358  *     03.31.95  ESF  Created.
359  *     23.08.95  JC   Don't check Cards and placement
360  *                    if state <> STATE_MOVE.
361  *  PURPOSE:
362  *  NOTES:
363  ************************************************************************/
364 Flag AI_Move(Int32 iSrcCountry, Int32 iDstCountry, Int32 iNumArmies)
365 {
366   if (GAME_ValidMoveSrc(iSrcCountry) &&
367       GAME_ValidMoveDst(iSrcCountry, iDstCountry) &&
368       RISK_GetNumArmiesOfCountry(iSrcCountry) >= iNumArmies+1)
369     {
370       GAME_MoveArmies(iSrcCountry, iDstCountry, iNumArmies);
371       return TRUE;
372     }
373   else
374     {
375 #ifdef ENGLISH
376       printf("AI: Error -- illegal move (%s --> %s)\n",
377 #endif
378 #ifdef FRENCH
379       printf("IA: Erreur -- mouvement ill�gal (%s --> %s)\n",
380 #endif
381 	     RISK_GetNameOfCountry(iSrcCountry),
382 	     RISK_GetNameOfCountry(iDstCountry));
383       return FALSE;
384     }
385 }
386 
387 
388 /************************************************************************
389  *  FUNCTION: AI_ExchangeCards
390  *  HISTORY:
391  *     03.31.95  ESF  Created.
392  *  PURPOSE:
393  *  NOTES:
394  ************************************************************************/
395 Flag AI_ExchangeCards(Int32 *piCards)
396 {
397   GAME_ExchangeCards(piCards);
398   return TRUE;
399 }
400 
401 
402 /************************************************************************
403  *  FUNCTION: AI_SendMessage
404  *  HISTORY:
405  *     03.31.95  ESF  Created.
406  *  PURPOSE:
407  *  NOTES:
408  ************************************************************************/
409 Flag AI_SendMessage(Int32 iMessDest, CString strMessage)
410 {
411   MsgMessagePacket mess;
412 
413   mess.strMessage = strMessage;
414   mess.iFrom      = iCurrentPlayer;
415   mess.iTo        = iMessDest;
416   (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()),
417 			 MSG_MESSAGEPACKET, &mess);
418   return TRUE;
419 }
420 
421 
422 /************************************************************************
423  *  FUNCTION: AI_EndTurn
424  *  HISTORY:
425  *     03.31.95  ESF  Created.
426  *     21.08.95  JC   Added fGetsCard.
427  *     23.08.95  JC   Added test the mission.
428  *  PURPOSE:
429  *  NOTES:
430  ************************************************************************/
431 Flag AI_EndTurn(void)
432 {
433   /* Get the player a card if he or she needs one */
434   if (fGetsCard)
435     {
436       MsgRequestCard msg;
437 
438       fGetsCard = FALSE;
439       msg.iPlayer = iCurrentPlayer;
440       (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()),
441 			     MSG_REQUESTCARD, &msg);
442     }
443 
444   if (fGameStarted)
445       fCanExchange = TRUE;
446   else
447       fPlayerFortified = FALSE;
448 
449   /* Actually end the turn */
450   (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()),
451 			 MSG_ENDTURN, NULL);
452 
453   return TRUE;
454 }
455