]> git.cameronkatri.com Git - bsdgames-darwin.git/blob - gomoku/main.c
New sentences begin on new lines.
[bsdgames-darwin.git] / gomoku / main.c
1 /* $NetBSD: main.c,v 1.10 2000/05/08 07:56:03 mycroft Exp $ */
2
3 /*
4 * Copyright (c) 1994
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Ralph Campbell.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 */
38
39 #include <sys/cdefs.h>
40 #ifndef lint
41 __COPYRIGHT("@(#) Copyright (c) 1994\n\
42 The Regents of the University of California. All rights reserved.\n");
43 #endif /* not lint */
44
45 #ifndef lint
46 #if 0
47 static char sccsid[] = "@(#)main.c 8.4 (Berkeley) 5/4/95";
48 #else
49 __RCSID("$NetBSD: main.c,v 1.10 2000/05/08 07:56:03 mycroft Exp $");
50 #endif
51 #endif /* not lint */
52
53 #include <curses.h>
54 #include <err.h>
55 #include <signal.h>
56 #include <stdlib.h>
57 #include <string.h>
58 #include <time.h>
59 #include <unistd.h>
60
61 #include "gomoku.h"
62
63 #define USER 0 /* get input from standard input */
64 #define PROGRAM 1 /* get input from program */
65 #define INPUTF 2 /* get input from a file */
66
67 int interactive = 1; /* true if interactive */
68 int debug; /* true if debugging */
69 int test; /* both moves come from 1: input, 2: computer */
70 char *prog; /* name of program */
71 FILE *debugfp; /* file for debug output */
72 FILE *inputfp; /* file for debug input */
73
74 const char pdir[4] = "-\\|/";
75 char fmtbuf[128];
76
77 struct spotstr board[BAREA]; /* info for board */
78 struct combostr frames[FAREA]; /* storage for all frames */
79 struct combostr *sortframes[2]; /* sorted list of non-empty frames */
80 u_char overlap[FAREA * FAREA]; /* true if frame [a][b] overlap */
81 short intersect[FAREA * FAREA]; /* frame [a][b] intersection */
82 int movelog[BSZ * BSZ]; /* log of all the moves */
83 int movenum; /* current move number */
84 const char *plyr[2]; /* who's who */
85
86 int main __P((int, char *[]));
87
88 int
89 main(argc, argv)
90 int argc;
91 char **argv;
92 {
93 char buf[128];
94 int color, curmove, i, ch;
95 int input[2];
96 static const char *const fmt[2] = {
97 "%3d %-6s",
98 "%3d %-6s"
99 };
100
101 /* Revoke setgid privileges */
102 setgid(getgid());
103
104 color = curmove = 0;
105
106 prog = strrchr(argv[0], '/');
107 if (prog)
108 prog++;
109 else
110 prog = argv[0];
111
112 while ((ch = getopt(argc, argv, "bcdD:u")) != -1) {
113 switch (ch) {
114 case 'b': /* background */
115 interactive = 0;
116 break;
117 case 'd': /* debugging */
118 debug++;
119 break;
120 case 'D': /* log debug output to file */
121 if ((debugfp = fopen(optarg, "w")) == NULL)
122 err(1, "%s", optarg);
123 break;
124 case 'u': /* testing: user verses user */
125 test = 1;
126 break;
127 case 'c': /* testing: computer verses computer */
128 test = 2;
129 break;
130 }
131 }
132 argc -= optind;
133 argv += optind;
134 if (argc) {
135 if ((inputfp = fopen(*argv, "r")) == NULL)
136 err(1, "%s", *argv);
137 }
138
139 if (!debug)
140 #ifdef SVR4
141 srand(time(0));
142 #else
143 srandom(time(0));
144 #endif
145 if (interactive)
146 cursinit(); /* initialize curses */
147 again:
148 bdinit(board); /* initialize board contents */
149
150 if (interactive) {
151 plyr[BLACK] = plyr[WHITE] = "???";
152 bdisp_init(); /* initialize display of board */
153 #ifdef DEBUG
154 signal(SIGINT, whatsup);
155 #else
156 signal(SIGINT, quitsig);
157 #endif
158
159 if (inputfp == NULL && test == 0) {
160 for (;;) {
161 ask("black or white? ");
162 getline(buf, sizeof(buf));
163 if (buf[0] == 'b' || buf[0] == 'B') {
164 color = BLACK;
165 break;
166 }
167 if (buf[0] == 'w' || buf[0] == 'W') {
168 color = WHITE;
169 break;
170 }
171 move(22, 0);
172 printw("Black moves first. Please enter `black' or `white'\n");
173 }
174 move(22, 0);
175 clrtoeol();
176 }
177 } else {
178 setbuf(stdout, 0);
179 getline(buf, sizeof(buf));
180 if (strcmp(buf, "black") == 0)
181 color = BLACK;
182 else if (strcmp(buf, "white") == 0)
183 color = WHITE;
184 else {
185 sprintf(fmtbuf,
186 "Huh? Expected `black' or `white', got `%s'\n",
187 buf);
188 panic(fmtbuf);
189 }
190 }
191
192 if (inputfp) {
193 input[BLACK] = INPUTF;
194 input[WHITE] = INPUTF;
195 } else {
196 switch (test) {
197 case 0: /* user verses program */
198 input[color] = USER;
199 input[!color] = PROGRAM;
200 break;
201
202 case 1: /* user verses user */
203 input[BLACK] = USER;
204 input[WHITE] = USER;
205 break;
206
207 case 2: /* program verses program */
208 input[BLACK] = PROGRAM;
209 input[WHITE] = PROGRAM;
210 break;
211 }
212 }
213 if (interactive) {
214 plyr[BLACK] = input[BLACK] == USER ? "you" : prog;
215 plyr[WHITE] = input[WHITE] == USER ? "you" : prog;
216 bdwho(1);
217 }
218
219 for (color = BLACK; ; color = !color) {
220 top:
221 switch (input[color]) {
222 case INPUTF: /* input comes from a file */
223 curmove = readinput(inputfp);
224 if (curmove != ILLEGAL)
225 break;
226 switch (test) {
227 case 0: /* user verses program */
228 input[color] = USER;
229 input[!color] = PROGRAM;
230 break;
231
232 case 1: /* user verses user */
233 input[BLACK] = USER;
234 input[WHITE] = USER;
235 break;
236
237 case 2: /* program verses program */
238 input[BLACK] = PROGRAM;
239 input[WHITE] = PROGRAM;
240 break;
241 }
242 plyr[BLACK] = input[BLACK] == USER ? "you" : prog;
243 plyr[WHITE] = input[WHITE] == USER ? "you" : prog;
244 bdwho(1);
245 goto top;
246
247 case USER: /* input comes from standard input */
248 getinput:
249 if (interactive)
250 ask("move? ");
251 if (!getline(buf, sizeof(buf))) {
252 curmove = RESIGN;
253 break;
254 }
255 if (buf[0] == '\0')
256 goto getinput;
257 curmove = ctos(buf);
258 if (interactive) {
259 if (curmove == SAVE) {
260 FILE *fp;
261
262 ask("save file name? ");
263 (void)getline(buf, sizeof(buf));
264 if ((fp = fopen(buf, "w")) == NULL) {
265 glog("cannot create save file");
266 goto getinput;
267 }
268 for (i = 0; i < movenum - 1; i++)
269 fprintf(fp, "%s\n",
270 stoc(movelog[i]));
271 fclose(fp);
272 goto getinput;
273 }
274 if (curmove != RESIGN &&
275 board[curmove].s_occ != EMPTY) {
276 glog("Illegal move");
277 goto getinput;
278 }
279 }
280 break;
281
282 case PROGRAM: /* input comes from the program */
283 curmove = pickmove(color);
284 break;
285 }
286 if (interactive) {
287 sprintf(fmtbuf, fmt[color], movenum, stoc(curmove));
288 glog(fmtbuf);
289 }
290 if ((i = makemove(color, curmove)) != MOVEOK)
291 break;
292 if (interactive)
293 bdisp();
294 }
295 if (interactive) {
296 move(22, 0);
297 switch (i) {
298 case WIN:
299 if (input[color] == PROGRAM)
300 addstr("Ha ha, I won");
301 else
302 addstr("Rats! you won");
303 break;
304 case TIE:
305 addstr("Wow! its a tie");
306 break;
307 case ILLEGAL:
308 addstr("Illegal move");
309 break;
310 }
311 clrtoeol();
312 bdisp();
313 if (i != RESIGN) {
314 replay:
315 ask("replay? ");
316 if (getline(buf, sizeof(buf)) &&
317 (buf[0] == 'y' || buf[0] == 'Y'))
318 goto again;
319 if (strcmp(buf, "save") == 0) {
320 FILE *fp;
321
322 ask("save file name? ");
323 (void)getline(buf, sizeof(buf));
324 if ((fp = fopen(buf, "w")) == NULL) {
325 glog("cannot create save file");
326 goto replay;
327 }
328 for (i = 0; i < movenum - 1; i++)
329 fprintf(fp, "%s\n",
330 stoc(movelog[i]));
331 fclose(fp);
332 goto replay;
333 }
334 }
335 }
336 quit();
337 /* NOTREACHED */
338 return(0);
339 }
340
341 int
342 readinput(fp)
343 FILE *fp;
344 {
345 char *cp;
346 int c;
347
348 cp = fmtbuf;
349 while ((c = getc(fp)) != EOF && c != '\n')
350 *cp++ = c;
351 *cp = '\0';
352 return (ctos(fmtbuf));
353 }
354
355 #ifdef DEBUG
356 /*
357 * Handle strange situations.
358 */
359 void
360 whatsup(signum)
361 int signum;
362 {
363 int i, pnum, n, s1, s2, d1, d2;
364 struct spotstr *sp;
365 FILE *fp;
366 char *str;
367 struct elist *ep;
368 struct combostr *cbp;
369
370 if (!interactive)
371 quit();
372 top:
373 ask("cmd? ");
374 if (!getline(fmtbuf, sizeof(fmtbuf)))
375 quit();
376 switch (*fmtbuf) {
377 case '\0':
378 goto top;
379 case 'q': /* conservative quit */
380 quit();
381 case 'd': /* set debug level */
382 debug = fmtbuf[1] - '0';
383 sprintf(fmtbuf, "Debug set to %d", debug);
384 dlog(fmtbuf);
385 sleep(1);
386 case 'c':
387 break;
388 case 'b': /* back up a move */
389 if (movenum > 1) {
390 movenum--;
391 board[movelog[movenum - 1]].s_occ = EMPTY;
392 bdisp();
393 }
394 goto top;
395 case 's': /* suggest a move */
396 i = fmtbuf[1] == 'b' ? BLACK : WHITE;
397 sprintf(fmtbuf, "suggest %c %s", i == BLACK ? 'B' : 'W',
398 stoc(pickmove(i)));
399 dlog(fmtbuf);
400 goto top;
401 case 'f': /* go forward a move */
402 board[movelog[movenum - 1]].s_occ = movenum & 1 ? BLACK : WHITE;
403 movenum++;
404 bdisp();
405 goto top;
406 case 'l': /* print move history */
407 if (fmtbuf[1] == '\0') {
408 for (i = 0; i < movenum - 1; i++)
409 dlog(stoc(movelog[i]));
410 goto top;
411 }
412 if ((fp = fopen(fmtbuf + 1, "w")) == NULL)
413 goto top;
414 for (i = 0; i < movenum - 1; i++) {
415 fprintf(fp, "%s", stoc(movelog[i]));
416 if (++i < movenum - 1)
417 fprintf(fp, " %s\n", stoc(movelog[i]));
418 else
419 fputc('\n', fp);
420 }
421 bdump(fp);
422 fclose(fp);
423 goto top;
424 case 'o':
425 n = 0;
426 for (str = fmtbuf + 1; *str; str++)
427 if (*str == ',') {
428 for (d1 = 0; d1 < 4; d1++)
429 if (str[-1] == pdir[d1])
430 break;
431 str[-1] = '\0';
432 sp = &board[s1 = ctos(fmtbuf + 1)];
433 n = (sp->s_frame[d1] - frames) * FAREA;
434 *str++ = '\0';
435 break;
436 }
437 sp = &board[s2 = ctos(str)];
438 while (*str)
439 str++;
440 for (d2 = 0; d2 < 4; d2++)
441 if (str[-1] == pdir[d2])
442 break;
443 n += sp->s_frame[d2] - frames;
444 str = fmtbuf;
445 sprintf(str, "overlap %s%c,", stoc(s1), pdir[d1]);
446 str += strlen(str);
447 sprintf(str, "%s%c = %x", stoc(s2), pdir[d2], overlap[n]);
448 dlog(fmtbuf);
449 goto top;
450 case 'p':
451 sp = &board[i = ctos(fmtbuf + 1)];
452 sprintf(fmtbuf, "V %s %x/%d %d %x/%d %d %d %x", stoc(i),
453 sp->s_combo[BLACK].s, sp->s_level[BLACK],
454 sp->s_nforce[BLACK],
455 sp->s_combo[WHITE].s, sp->s_level[WHITE],
456 sp->s_nforce[WHITE], sp->s_wval, sp->s_flg);
457 dlog(fmtbuf);
458 sprintf(fmtbuf, "FB %s %x %x %x %x", stoc(i),
459 sp->s_fval[BLACK][0].s, sp->s_fval[BLACK][1].s,
460 sp->s_fval[BLACK][2].s, sp->s_fval[BLACK][3].s);
461 dlog(fmtbuf);
462 sprintf(fmtbuf, "FW %s %x %x %x %x", stoc(i),
463 sp->s_fval[WHITE][0].s, sp->s_fval[WHITE][1].s,
464 sp->s_fval[WHITE][2].s, sp->s_fval[WHITE][3].s);
465 dlog(fmtbuf);
466 goto top;
467 case 'e': /* e {b|w} [0-9] spot */
468 str = fmtbuf + 1;
469 if (*str >= '0' && *str <= '9')
470 n = *str++ - '0';
471 else
472 n = 0;
473 sp = &board[i = ctos(str)];
474 for (ep = sp->s_empty; ep; ep = ep->e_next) {
475 cbp = ep->e_combo;
476 if (n) {
477 if (cbp->c_nframes > n)
478 continue;
479 if (cbp->c_nframes != n)
480 break;
481 }
482 printcombo(cbp, fmtbuf);
483 dlog(fmtbuf);
484 }
485 goto top;
486 default:
487 syntax:
488 dlog("Options are:");
489 dlog("q - quit");
490 dlog("c - continue");
491 dlog("d# - set debug level to #");
492 dlog("p# - print values at #");
493 goto top;
494 }
495 }
496 #endif /* DEBUG */
497
498 /*
499 * Display debug info.
500 */
501 void
502 dlog(str)
503 const char *str;
504 {
505
506 if (debugfp)
507 fprintf(debugfp, "%s\n", str);
508 if (interactive)
509 dislog(str);
510 else
511 fprintf(stderr, "%s\n", str);
512 }
513
514 void
515 glog(str)
516 const char *str;
517 {
518
519 if (debugfp)
520 fprintf(debugfp, "%s\n", str);
521 if (interactive)
522 dislog(str);
523 else
524 printf("%s\n", str);
525 }
526
527 void
528 quit()
529 {
530 if (interactive) {
531 bdisp(); /* show final board */
532 cursfini();
533 }
534 exit(0);
535 }
536
537 void
538 quitsig(dummy)
539 int dummy __attribute__((__unused__));
540 {
541 quit();
542 }
543
544 /*
545 * Die gracefully.
546 */
547 void
548 panic(str)
549 const char *str;
550 {
551 fprintf(stderr, "%s: %s\n", prog, str);
552 fputs("resign\n", stdout);
553 quit();
554 }