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