1 /*
2
3 3Dc, a game of 3-Dimensional Chess
4 Copyright (C) 1995 Paul Hicks
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
20 E-Mail: paulh@euristix.ie
21 */
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <sys/types.h>
27 #include <sys/time.h>
28 #include <X11/X.h>
29 #include <X11/Intrinsic.h>
30
31 #include "machine.h"
32
33 #include "3Dc.h"
34
35 #define MAX_RETRIES 100 /* Number of times to guess a tricky move */
36
37 Colour bwToMove = WHITE;
38 Local Colour computer = NOCOL;
39 Local Boolean gamePaused = FALSE;
40
41 Local Boolean SetupAutoplay(char *);
42 Local void DoMain3DcLoop(void);
43
44 int
main(int argc,char ** argv)45 main(int argc, char **argv)
46 {
47 int argNum;
48
49 printf("3Dc version %s, Copyright (C) 1995,1996 Paul Hicks\n", VERSION);
50 printf("3Dc comes with ABSOLUTELY NO WARRANTY: see the GPL file for details\n");
51 printf("This is free software: you are welcome to redistribute it\n");
52 printf(" under certain conditions (see the GPL file).\n");
53
54 Init3Dc();
55 if (Init3DcGFX(argc, argv) == FALSE)
56 return 1;
57
58 for (argNum = 1; argNum < argc; ++argNum)
59 {
60 if (!strcmp(argv[argNum], "-play"))
61 {
62 if (++argNum >= argc)
63 {
64 fprintf(stderr,
65 "%s: -play requires a colour (black or white)\n",
66 argv[0]);
67 return 1;
68 }
69
70 if (SetupAutoplay(argv[argNum]) == FALSE)
71 {
72 fprintf(stderr,
73 "%s: %s is not a colour (must be black or white)\n",
74 argv[0], argv[argNum]);
75 return 1;
76 }
77 } /* End autoplay setup */
78 else if (!strcmp(argv[argNum], "-altdisplay") ||
79 !strcmp(argv[argNum], "-ad"))
80 {
81 /* If no more params or next param is a new option */
82 if ((++argNum == argc) || argv[argNum][0] == '-')
83 {
84 fprintf(stderr,
85 "%s: option %s requires a display name parameter\n",
86 argv[0], argv[argNum -1]);
87 return 1;
88 }
89 else
90 {
91 Open2ndDisplay(argv[argNum]);
92 }
93 } /* End net setup */
94 else /* The help option */
95 {
96 fprintf(stderr, "Usage:\n");
97 fprintf(stderr, "\
98 %s ; play 3Dc, two humans on one display\n\
99 %s -ad|-altdisplay [display] ; black plays on display `display'\n\
100 %s -play colour ; play against the computer, which plays colour\n",
101 argv[0], argv[0], argv[0]);
102 return 1;
103 }
104 } /* Finish parameters */
105
106 DoMain3DcLoop();
107
108 return 0;
109 }
110
111 /* Set up the computer intelligence and all that */
112 Local Boolean
SetupAutoplay(char * colourName)113 SetupAutoplay(char *colourName)
114 {
115 if (!strcmp(colourName, "black"))
116 computer = BLACK;
117 else if (!strcmp(colourName, "white"))
118 computer = WHITE;
119 else
120 {
121 return FALSE;
122 }
123 return TRUE;
124 }
125
126 Local void
DoMain3DcLoop(void)127 DoMain3DcLoop(void)
128 {
129 Move *automove;
130 XEvent event;
131 Local Boolean retry = FALSE;
132
133 while (firstGFX->mainWindow)
134 {
135 /* First thing to do: check for end of game! */
136 if (IsGameFinished() && !gamePaused)
137 FinishGame((bwToMove == BLACK) ? WHITE : BLACK);
138
139 if ( (bwToMove == computer) && !gamePaused)
140 {
141 if (((retry == FALSE) && GenMove(computer, &automove) == TRUE) ||
142 ((retry == TRUE) && GenAltMove(computer, &automove) == TRUE))
143 {
144 if ( automove == NULL )
145 {
146 /*
147 * Give up, it's too hard for me..
148 */
149 PauseGame();
150 /* Can we delay after this? */
151 Err3Dc(firstGFX, "Gaah! I give up.", TRUE);
152 XFlush( XtDisplay( firstGFX->mainWindow ));
153 FinishGame((computer == BLACK) ? WHITE : BLACK);
154 }
155 /*** This assertion fails with stack size of 1---or at least it used to */
156 else if ( (Board[ automove->xyzBefore.zLevel ]
157 [ automove->xyzBefore.yRank ]
158 [ automove->xyzBefore.xFile ] == NULL ) ||
159 (!CHECK( PieceMove( Board[ automove->xyzBefore.zLevel ]
160 [ automove->xyzBefore.yRank ]
161 [ automove->xyzBefore.xFile ],
162 automove->xyzAfter.xFile,
163 automove->xyzAfter.yRank,
164 automove->xyzAfter.zLevel ) )) )
165 {
166 /* The move was illegal for some reason
167 * (in the future I plan to eliminate all
168 * possibility of getting in here) */
169 D( printf( "Can't move from (%i,%i,%i) to (%i,%i,%i)\n",
170 automove->xyzBefore.xFile,
171 automove->xyzBefore.yRank,
172 automove->xyzBefore.zLevel,
173 automove->xyzAfter.xFile,
174 automove->xyzAfter.yRank,
175 automove->xyzAfter.zLevel ) );
176
177 retry = TRUE;
178 }
179 else /* Move is legit: do it */
180 {
181 retry = FALSE;
182 PrintMove( automove );
183
184 bwToMove = ((computer == WHITE) ? BLACK : WHITE);
185 } /* End 'found computer move' */
186 } /* Still finding computer's move? */
187 } /* End computer's move */
188
189 if (XtAppPending(XtWidgetToApplicationContext(firstGFX->mainWindow)))
190 {
191 XtAppNextEvent(XtWidgetToApplicationContext(firstGFX->mainWindow),
192 &event);
193 XtDispatchEvent(&event);
194 }
195
196 if ((secondGFX != NULL) &&
197 (XtAppPending(XtWidgetToApplicationContext(secondGFX->mainWindow))))
198 {
199 XtAppNextEvent(XtWidgetToApplicationContext(secondGFX->mainWindow),
200 &event);
201 XtDispatchEvent(&event);
202 }
203
204 } /* End game loop */
205
206 return;
207 }
208
209 /*************************************************************/
210 /* Utility functions */
211 Global int
MusterIdx(const Title name,const int nth)212 MusterIdx(const Title name, const int nth)
213 {
214 int i, count = 0;
215
216 for (i = 0; i != name && i < TITLES; ++i)
217 count += titleCount[i];
218
219 if (i == TITLES)
220 return 47; /* 47 is a hack; it is a legal array index that is only
221 * valid for pawns */
222
223 if (nth < titleCount[name])
224 {
225 return count + nth;
226 }
227 /* else */
228 return 47;
229 }
230
Piece2String(Piece * piece)231 Global char *Piece2String( Piece *piece )
232 {
233 static char *names[] =
234 {
235 "King", "Queen", "Bishop", "Knight", "Rook",
236 "Prince", "Princess", "Abbey", "Cannon", "Galley",
237 "Pawn", ""
238 };
239
240 return names[piece->nName];
241 }
242
243 Global Colour
Computer(void)244 Computer(void)
245 {
246 return computer;
247 }
248
249 Global void
PauseGame(void)250 PauseGame(void)
251 {
252 gamePaused = TRUE;
253 return;
254 }
255
256 Global void
ResumeGame(void)257 ResumeGame(void)
258 {
259 gamePaused = FALSE;
260 return;
261 }
262
263 Global Boolean
IsGamePaused(void)264 IsGamePaused(void)
265 {
266 return gamePaused;
267 }
268
269 Global Boolean
IsGameFinished(void)270 IsGameFinished(void)
271 {
272 Boolean
273 blackKingVisible, whiteKingVisible,
274 blackFirstPrinceVisible, whiteFirstPrinceVisible,
275 blackSecondPrinceVisible, whiteSecondPrinceVisible;
276
277 blackKingVisible = Muster[BLACK][MusterIdx(king, 0)]->bVisible;
278 whiteKingVisible = Muster[WHITE][MusterIdx(king, 0)]->bVisible;
279 blackFirstPrinceVisible = Muster[BLACK][MusterIdx(prince, 0)]->bVisible;
280 whiteFirstPrinceVisible = Muster[WHITE][MusterIdx(prince, 0)]->bVisible;
281 blackSecondPrinceVisible = Muster[BLACK][MusterIdx(prince, 1)]->bVisible;
282 whiteSecondPrinceVisible = Muster[WHITE][MusterIdx(prince, 1)]->bVisible;
283
284 if ((!whiteKingVisible ||
285 (!whiteFirstPrinceVisible && !whiteSecondPrinceVisible)) ||
286 (!blackKingVisible ||
287 (!blackFirstPrinceVisible && !blackSecondPrinceVisible)))
288 {
289 return TRUE;
290 }
291
292 return FALSE;
293 }
294
295 Global void
FinishGame(const Colour bwWinner)296 FinishGame(const Colour bwWinner)
297 {
298 char winString[19];
299
300 gamePaused = TRUE;
301 sprintf(winString, "%s player wins!",
302 (bwWinner == BLACK) ? "Black" : "White");
303
304 XtSetSensitive(firstGFX->undo, FALSE);
305 Err3Dc(firstGFX, winString, TRUE);
306
307 if (secondGFX != NULL)
308 {
309 XtSetSensitive(secondGFX->undo, FALSE);
310 Err3Dc(secondGFX, winString, TRUE);
311 }
312 }
313
314 Global void
PrintMove(const Move * move)315 PrintMove( const Move *move )
316 {
317 char *moveString = NULL;
318
319 if (move != NULL)
320 moveString = (char *)malloc(26);
321
322 /* moveString is TRUE only if move != NULL too */
323 if (moveString)
324 {
325 Piece *piece, *enemy;
326 Coord pos;
327
328 piece = Board[ move->xyzAfter.zLevel]
329 [ move->xyzAfter.yRank ]
330 [ move->xyzAfter.xFile ];
331
332 CHECK( piece != NULL );
333
334 enemy = Muster[(piece->bwSide == WHITE) ? BLACK : WHITE]
335 [ MusterIdx(king, 0) ];
336 pos = enemy->xyzPos;
337
338 sprintf( moveString, "%s %c%c%c to %c%c%c%s",
339 Piece2String( piece ),
340 move->xyzBefore.zLevel + 'X',
341 move->xyzBefore.xFile + 'a',
342 move->xyzBefore.yRank + '1',
343 move->xyzAfter.zLevel + 'X',
344 move->xyzAfter.xFile + 'a',
345 move->xyzAfter.yRank + '1',
346 IsKingChecked( piece->bwSide ) ? " check!" : "");
347
348 /* Display the move: beep if
349 * 1) the computer or
350 * 2) the other player in a network game
351 * moved or if
352 * 3) the move resulted in a check
353 * This is now changed so that there's no beep when the computer
354 * moves 'cos it's so fast. */
355 Err3Dc( firstGFX, moveString,
356 (/* (Computer() == bwToMove) || */
357 ( (secondGFX != NULL) && (bwToMove == BLACK) ) ||
358 ( IsKingChecked( piece->bwSide ))) ?
359 TRUE : FALSE );
360 if ( secondGFX != NULL )
361 {
362 Err3Dc( secondGFX, moveString, (bwToMove == WHITE) ?
363 TRUE : FALSE );
364 }
365
366 /* I think that this isn't allowed becase the string is
367 * still needed by the label widget but it hasn't caused
368 * any problems so far.. */
369 free(moveString);
370 }
371 else
372 {
373 /* Print something, even if out of memory.. */
374 if ( (Computer() == bwToMove) ||
375 ( (secondGFX != NULL) && (bwToMove == BLACK)))
376 Err3Dc(firstGFX, "Opponent has moved", TRUE);
377 else if ( (secondGFX != NULL) && (bwToMove == WHITE) )
378 Err3Dc(secondGFX, "Opponent has moved", TRUE);
379 }
380 }
381