xref: /original-bsd/games/gomoku/main.c (revision 0f81f0ee)
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 
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 
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
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  */
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 
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
488 quit()
489 {
490 	if (interactive) {
491 		bdisp();		/* show final board */
492 		cursfini();
493 	}
494 	exit(0);
495 }
496 
497 /*
498  * Die gracefully.
499  */
500 panic(str)
501 	char *str;
502 {
503 	fprintf(stderr, "%s: %s\n", prog, str);
504 	fputs("resign\n", stdout);
505 	quit();
506 }
507