xref: /original-bsd/games/gomoku/main.c (revision deff14a8)
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.2 (Berkeley) 08/04/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 		srand(time(0));
104 #else
105 		srandom(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 == 0) {
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 		replay:
260 			ask("replay? ");
261 			if (getline(buf, sizeof buf) &&
262 			    buf[0] == 'y' || buf[0] == 'Y')
263 				goto again;
264 			if (strcmp(buf, "save") == 0) {
265 				FILE *fp;
266 
267 				ask("save file name? ");
268 				(void)getline(buf, sizeof buf);
269 				if ((fp = fopen(buf, "w")) == NULL) {
270 					log("cannot create save file");
271 					goto replay;
272 				}
273 				for (i = 0; i < movenum - 1; i++)
274 					fprintf(fp, "%s\n",
275 						stoc(movelog[i]));
276 				fclose(fp);
277 				goto replay;
278 			}
279 		}
280 	}
281 	quit();
282 }
283 
284 readinput(fp)
285 	FILE *fp;
286 {
287 	char *cp;
288 	int c;
289 
290 	cp = fmtbuf;
291 	while ((c = getc(fp)) != EOF && c != '\n')
292 		*cp++ = c;
293 	*cp = '\0';
294 	return (ctos(fmtbuf));
295 }
296 
297 #ifdef DEBUG
298 /*
299  * Handle strange situations.
300  */
301 void
302 whatsup(signum)
303 	int signum;
304 {
305 	int i, pnum, n;
306 	struct spotstr *sp;
307 	FILE *fp;
308 	char *str;
309 	struct elist *ep;
310 	struct combostr *cbp;
311 
312 	if (!interactive)
313 		quit();
314 top:
315 	ask("cmd? ");
316 	if (!getline(fmtbuf, 128))
317 		quit();
318 	switch (*fmtbuf) {
319 	case 'q':		/* conservative quit */
320 		quit();
321 	case 'd':		/* set debug level */
322 		debug = fmtbuf[1] - '0';
323 		sprintf(fmtbuf, "Debug set to %d", debug);
324 		dlog(fmtbuf);
325 		sleep(1);
326 	case 'c':
327 		break;
328 	case 'b':		/* back up a move */
329 		if (movenum > 1) {
330 			movenum--;
331 			board[movelog[movenum - 1]].s_occ = EMPTY;
332 			bdisp();
333 		}
334 		goto top;
335 	case 'f':		/* go forward a move */
336 		board[movelog[movenum - 1]].s_occ = movenum & 1 ? BLACK : WHITE;
337 		movenum++;
338 		bdisp();
339 		goto top;
340 	case 'l':		/* print move history */
341 		if (fmtbuf[1] == '\0') {
342 			for (i = 0; i < movenum - 1; i++)
343 				dlog(stoc(movelog[i]));
344 			goto top;
345 		}
346 		if ((fp = fopen(fmtbuf + 1, "w")) == NULL)
347 			goto top;
348 		for (i = 0; i < movenum - 1; i++) {
349 			fprintf(fp, "%s", stoc(movelog[i]));
350 			if (++i < movenum - 1)
351 				fprintf(fp, " %s\n", stoc(movelog[i]));
352 			else
353 				fputc('\n', fp);
354 		}
355 		bdump(fp);
356 		fclose(fp);
357 		goto top;
358 	case 'p':
359 		sp = &board[i = ctos(fmtbuf + 1)];
360 		sprintf(fmtbuf, "V %s %x/%d %d %x/%d %d %d %x", stoc(i),
361 			sp->s_combo[BLACK].s, sp->s_level[BLACK],
362 			sp->s_nforce[BLACK],
363 			sp->s_combo[WHITE].s, sp->s_level[WHITE],
364 			sp->s_nforce[WHITE], sp->s_wval, sp->s_flg);
365 		dlog(fmtbuf);
366 		sprintf(fmtbuf, "FB %s %x %x %x %x", stoc(i),
367 			sp->s_fval[BLACK][0].s, sp->s_fval[BLACK][1].s,
368 			sp->s_fval[BLACK][2].s, sp->s_fval[BLACK][3].s);
369 		dlog(fmtbuf);
370 		sprintf(fmtbuf, "FW %s %x %x %x %x", stoc(i),
371 			sp->s_fval[WHITE][0].s, sp->s_fval[WHITE][1].s,
372 			sp->s_fval[WHITE][2].s, sp->s_fval[WHITE][3].s);
373 		dlog(fmtbuf);
374 		goto top;
375 	case 'P':
376 		sp = &board[i = ctos(fmtbuf + 1)];
377 		for (pnum = BLACK; pnum <= WHITE; pnum++) {
378 			for (ep = sp->s_empty[pnum]; ep; ep = ep->e_next) {
379 				cbp = ep->e_combo;
380 				str = fmtbuf;
381 				sprintf(str, "C%c %s", "BW"[pnum], stoc(i));
382 				str += strlen(str);
383 				if (cbp->c_nframes == 2) {
384 					sprintf(str, " %s%c",
385 						stoc(cbp->c_link[0]->c_vertex),
386 						pdir[cbp->c_link[0]->c_dir]);
387 					str += strlen(str);
388 					sprintf(str, " %s%c %x/%d",
389 						stoc(cbp->c_link[1]->c_vertex),
390 						pdir[cbp->c_link[1]->c_dir],
391 						cbp->c_combo.s, cbp->c_nframes);
392 				} else {
393 					sprintf(str, " %s%c %x/%d",
394 						stoc(cbp->c_vertex),
395 						pdir[ep->e_frame->c_dir],
396 						cbp->c_combo.s, cbp->c_nframes);
397 				}
398 				dlog(fmtbuf);
399 			}
400 		}
401 		goto top;
402 	default:
403 syntax:
404 		dlog("Options are:");
405 		dlog("q    - quit");
406 		dlog("c    - continue");
407 		dlog("d#   - set debug level to #");
408 		dlog("p#   - print values at #");
409 		goto top;
410 	}
411 }
412 #endif /* DEBUG */
413 
414 /*
415  * Display debug info.
416  */
417 dlog(str)
418 	char *str;
419 {
420 
421 	if (debugfp)
422 		fprintf(debugfp, "%s\n", str);
423 	else if (interactive)
424 		dislog(str);
425 	else
426 		fprintf(stderr, "%s\n", str);
427 }
428 
429 log(str)
430 	char *str;
431 {
432 
433 	if (debugfp)
434 		fprintf(debugfp, "%s\n", str);
435 	if (interactive)
436 		dislog(str);
437 	else
438 		printf("%s\n", str);
439 }
440 
441 void
442 quit()
443 {
444 	if (interactive) {
445 		bdisp();		/* show final board */
446 		cursfini();
447 	}
448 	exit(0);
449 }
450 
451 /*
452  * Die gracefully.
453  */
454 panic(str)
455 	char *str;
456 {
457 	fprintf(stderr, "%s: %s\n", prog, str);
458 	fputs("resign\n", stdout);
459 	quit();
460 }
461