xref: /original-bsd/games/gomoku/main.c (revision 4ba124f7)
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.1 (Berkeley) 07/24/94";
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	*color[]	= { "black", "white", "empty", "border" };
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 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 main(argc, argv)
55 	int argc;
56 	char **argv;
57 {
58 	char buf[128];
59 	int color, curmove, i, ch;
60 	int input[2];
61 	extern void whatsup(), quit();
62 	static char *fmt[2] = {
63 		"%3d %-6s",
64 		"%3d        %-6s"
65 	};
66 
67 	prog = strrchr(argv[0], '/');
68 	if (prog)
69 		prog++;
70 	else
71 		prog = argv[0];
72 
73 	while ((ch = getopt(argc, argv, "bcdD:u")) != EOF) {
74 		switch (ch) {
75 		case 'b':	/* background */
76 			interactive = 0;
77 			break;
78 		case 'd':	/* debugging */
79 			debug++;
80 			break;
81 		case 'D':	/* log debug output to file */
82 			if ((debugfp = fopen(optarg, "w")) == NULL)
83 				err(1, "%s", optarg);
84 			break;
85 		case 'u':	/* testing: user verses user */
86 			test = 1;
87 			break;
88 		case 'c':	/* testing: computer verses computer */
89 			test = 2;
90 			break;
91 		}
92 	}
93 	argc -= optind;
94 	argv += optind;
95 	if (argc) {
96 		if ((inputfp = fopen(*argv, "r")) == NULL)
97 			err(1, "%s", *argv);
98 		test = 3;
99 	}
100 
101 	if (!debug)
102 #ifdef SVR4
103 		srandom(time(0));
104 #else
105 		srand(time(0));
106 #endif
107 	if (interactive)
108 		cursinit();		/* initialize curses */
109 again:
110 	bdinit(board);			/* initialize board contents */
111 
112 	if (interactive) {
113 		plyr[BLACK] = plyr[WHITE] = "???";
114 		bdisp_init();		/* initialize display of board */
115 #ifdef DEBUG
116 		signal(SIGINT, whatsup);
117 #else
118 		signal(SIGINT, quit);
119 #endif
120 
121 		if (test != 3) {
122 			for (;;) {
123 				ask("black or white? ");
124 				getline(buf, sizeof buf);
125 				if (buf[0] == 'b' || buf[0] == 'B') {
126 					color = BLACK;
127 					break;
128 				}
129 				if (buf[0] == 'w' || buf[0] == 'W') {
130 					color = WHITE;
131 					break;
132 				}
133 				move(22, 0);
134 				printw("Black moves first. Please enter `black' or `white'\n");
135 			}
136 			move(22, 0);
137 			clrtoeol();
138 		}
139 	} else {
140 		setbuf(stdout, 0);
141 		getline(buf, sizeof buf);
142 		if (strcmp(buf, "black") == 0)
143 			color = BLACK;
144 		else if (strcmp(buf, "white") == 0)
145 			color = WHITE;
146 		else {
147 			sprintf(fmtbuf,
148 			    "Huh?  Expected `black' or `white', got `%s'\n",
149 			    buf);
150 			panic(fmtbuf);
151 		}
152 	}
153 
154 	switch (test) {
155 	case 0: /* user verses program */
156 		input[color] = USER;
157 		input[!color] = PROGRAM;
158 		break;
159 
160 	case 1: /* user verses user */
161 		input[BLACK] = USER;
162 		input[WHITE] = USER;
163 		break;
164 
165 	case 2: /* program verses program */
166 		input[BLACK] = PROGRAM;
167 		input[WHITE] = PROGRAM;
168 		break;
169 
170 	case 3: /* user verses program */
171 		input[BLACK] = INPUTF;
172 		input[WHITE] = INPUTF;
173 	}
174 	if (interactive) {
175 		plyr[BLACK] = input[BLACK] == USER ? "you" : prog;
176 		plyr[WHITE] = input[WHITE] == USER ? "you" : prog;
177 		bdwho(1);
178 	}
179 
180 	for (color = BLACK; ; color = !color) {
181 		switch (input[color]) {
182 		case INPUTF: /* input comes from a file */
183 			curmove = readinput(inputfp);
184 			if (curmove != ILLEGAL)
185 				break;
186 			input[color] = USER;
187 			input[!color] = PROGRAM;
188 			plyr[color] = "you";
189 			bdwho(1);
190 			/* FALLTHROUGH */
191 
192 		case USER: /* input comes from standard input */
193 		getinput:
194 			if (interactive)
195 				ask("move? ");
196 			if (!getline(buf, sizeof buf)) {
197 				curmove = RESIGN;
198 				break;
199 			}
200 			if (buf[0] == '\0')
201 				goto getinput;
202 			curmove = ctos(buf);
203 			if (interactive) {
204 				if (curmove == SAVE) {
205 					FILE *fp;
206 
207 					ask("save file name? ");
208 					(void)getline(buf, sizeof buf);
209 					if ((fp = fopen(buf, "w")) == NULL) {
210 						log("cannot create save file");
211 						goto getinput;
212 					}
213 					for (i = 0; i < movenum - 1; i++)
214 						fprintf(fp, "%s\n",
215 							stoc(movelog[i]));
216 					fclose(fp);
217 					goto getinput;
218 				}
219 				if (curmove != RESIGN &&
220 				    board[curmove].s_occ != EMPTY) {
221 					log("Illegal move");
222 					goto getinput;
223 				}
224 			}
225 			break;
226 
227 		case PROGRAM: /* input comes from the program */
228 			curmove = pickmove(color);
229 			break;
230 		}
231 		if (interactive) {
232 			sprintf(fmtbuf, fmt[color], movenum, stoc(curmove));
233 			log(fmtbuf);
234 		}
235 		if ((i = makemove(color, curmove)) != MOVEOK)
236 			break;
237 		if (interactive)
238 			bdisp();
239 	}
240 	if (interactive) {
241 		move(22, 0);
242 		switch (i) {
243 		case WIN:
244 			if (input[color] == PROGRAM)
245 				addstr("Ha ha, I won");
246 			else
247 				addstr("Rats! you won");
248 			break;
249 		case TIE:
250 			addstr("Wow! its a tie");
251 			break;
252 		case ILLEGAL:
253 			addstr("Illegal move");
254 			break;
255 		}
256 		clrtoeol();
257 		bdisp();
258 		if (i != RESIGN) {
259 			ask("replay? ");
260 			if (getline(buf, sizeof buf) &&
261 			    buf[0] == 'y' || buf[0] == 'Y')
262 				goto again;
263 		}
264 	}
265 	quit();
266 }
267 
268 readinput(fp)
269 	FILE *fp;
270 {
271 	char *cp;
272 	int c;
273 
274 	cp = fmtbuf;
275 	while ((c = getc(fp)) != EOF && c != '\n')
276 		*cp++ = c;
277 	*cp = '\0';
278 	return (ctos(fmtbuf));
279 }
280 
281 #ifdef DEBUG
282 /*
283  * Handle strange situations.
284  */
285 void
286 whatsup(signum)
287 	int signum;
288 {
289 	int i, pnum, n;
290 	struct spotstr *sp;
291 	FILE *fp;
292 	char *str;
293 	struct elist *ep;
294 	struct combostr *cbp;
295 
296 	if (!interactive)
297 		quit();
298 top:
299 	ask("cmd? ");
300 	if (!getline(fmtbuf, 128))
301 		quit();
302 	switch (*fmtbuf) {
303 	case 'q':		/* conservative quit */
304 		quit();
305 	case 'd':		/* set debug level */
306 		debug = fmtbuf[1] - '0';
307 		sprintf(fmtbuf, "Debug set to %d", debug);
308 		dlog(fmtbuf);
309 		sleep(1);
310 	case 'c':
311 		break;
312 	case 'b':		/* back up a move */
313 		if (movenum > 1) {
314 			movenum--;
315 			board[movelog[movenum - 1]].s_occ = EMPTY;
316 			bdisp();
317 		}
318 		goto top;
319 	case 'f':		/* go forward a move */
320 		board[movelog[movenum - 1]].s_occ = movenum & 1 ? BLACK : WHITE;
321 		movenum++;
322 		bdisp();
323 		goto top;
324 	case 'l':		/* print move history */
325 		if (fmtbuf[1] == '\0') {
326 			for (i = 0; i < movenum - 1; i++)
327 				dlog(stoc(movelog[i]));
328 			goto top;
329 		}
330 		if ((fp = fopen(fmtbuf + 1, "w")) == NULL)
331 			goto top;
332 		for (i = 0; i < movenum - 1; i++) {
333 			fprintf(fp, "%s", stoc(movelog[i]));
334 			if (++i < movenum - 1)
335 				fprintf(fp, " %s\n", stoc(movelog[i]));
336 			else
337 				fputc('\n', fp);
338 		}
339 		bdump(fp);
340 		fclose(fp);
341 		goto top;
342 	case 'p':
343 		sp = &board[i = ctos(fmtbuf + 1)];
344 		sprintf(fmtbuf, "V %s %x/%d %d %x/%d %d %d %x", stoc(i),
345 			sp->s_combo[BLACK].s, sp->s_level[BLACK],
346 			sp->s_nforce[BLACK],
347 			sp->s_combo[WHITE].s, sp->s_level[WHITE],
348 			sp->s_nforce[WHITE], sp->s_wval, sp->s_flg);
349 		dlog(fmtbuf);
350 		sprintf(fmtbuf, "FB %s %x %x %x %x", stoc(i),
351 			sp->s_fval[BLACK][0].s, sp->s_fval[BLACK][1].s,
352 			sp->s_fval[BLACK][2].s, sp->s_fval[BLACK][3].s);
353 		dlog(fmtbuf);
354 		sprintf(fmtbuf, "FW %s %x %x %x %x", stoc(i),
355 			sp->s_fval[WHITE][0].s, sp->s_fval[WHITE][1].s,
356 			sp->s_fval[WHITE][2].s, sp->s_fval[WHITE][3].s);
357 		dlog(fmtbuf);
358 		goto top;
359 	case 'P':
360 		sp = &board[i = ctos(fmtbuf + 1)];
361 		for (pnum = BLACK; pnum <= WHITE; pnum++) {
362 			for (ep = sp->s_empty[pnum]; ep; ep = ep->e_next) {
363 				cbp = ep->e_combo;
364 				str = fmtbuf;
365 				sprintf(str, "C%c %s", "BW"[pnum], stoc(i));
366 				str += strlen(str);
367 				if (cbp->c_nframes == 2) {
368 					sprintf(str, " %s%c",
369 						stoc(cbp->c_link[0]->c_vertex),
370 						pdir[cbp->c_link[0]->c_dir]);
371 					str += strlen(str);
372 					sprintf(str, " %s%c %x/%d",
373 						stoc(cbp->c_link[1]->c_vertex),
374 						pdir[cbp->c_link[1]->c_dir],
375 						cbp->c_combo.s, cbp->c_nframes);
376 				} else {
377 					sprintf(str, " %s%c %x/%d",
378 						stoc(cbp->c_vertex),
379 						pdir[ep->e_frame->c_dir],
380 						cbp->c_combo.s, cbp->c_nframes);
381 				}
382 				dlog(fmtbuf);
383 			}
384 		}
385 		goto top;
386 	default:
387 syntax:
388 		dlog("Options are:");
389 		dlog("q    - quit");
390 		dlog("c    - continue");
391 		dlog("d#   - set debug level to #");
392 		dlog("p#   - print values at #");
393 		goto top;
394 	}
395 }
396 #endif /* DEBUG */
397 
398 /*
399  * Display debug info.
400  */
401 dlog(str)
402 	char *str;
403 {
404 
405 	if (debugfp)
406 		fprintf(debugfp, "%s\n", str);
407 	else if (interactive)
408 		dislog(str);
409 	else
410 		fprintf(stderr, "%s\n", str);
411 }
412 
413 log(str)
414 	char *str;
415 {
416 
417 	if (debugfp)
418 		fprintf(debugfp, "%s\n", str);
419 	if (interactive)
420 		dislog(str);
421 	else
422 		printf("%s\n", str);
423 }
424 
425 void
426 quit()
427 {
428 	if (interactive) {
429 		bdisp();		/* show final board */
430 		cursfini();
431 	}
432 	exit(0);
433 }
434 
435 /*
436  * Die gracefully.
437  */
438 panic(str)
439 	char *str;
440 {
441 	fprintf(stderr, "%s: %s\n", prog, str);
442 	fputs("resign\n", stdout);
443 	quit();
444 }
445