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