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