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