Home | History | Annotate | Line # | Download | only in backgammon
      1 /*	$NetBSD: move.c,v 1.13 2012/10/13 19:39:57 dholland Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1980, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. Neither the name of the University nor the names of its contributors
     16  *    may be used to endorse or promote products derived from this software
     17  *    without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  * SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 #ifndef lint
     34 #if 0
     35 static char sccsid[] = "@(#)move.c	8.1 (Berkeley) 5/31/93";
     36 #else
     37 __RCSID("$NetBSD: move.c,v 1.13 2012/10/13 19:39:57 dholland Exp $");
     38 #endif
     39 #endif /* not lint */
     40 
     41 #include <assert.h>
     42 
     43 #include "back.h"
     44 #include "backlocal.h"
     45 
     46 #ifdef DEBUG
     47 FILE   *trace;
     48 static char tests[20];
     49 #endif
     50 
     51 struct BOARD {			/* structure of game position */
     52 	int     b_board[26];	/* board position */
     53 	int     b_in[2];	/* men in */
     54 	int     b_off[2];	/* men off */
     55 	int     b_st[4], b_fn[4];	/* moves */
     56 
     57 	struct BOARD *b_next;	/* forward queue pointer */
     58 };
     59 
     60 static struct BOARD *freeq = 0;
     61 static struct BOARD *checkq = 0;
     62 
     63  /* these variables are values for the candidate move */
     64 static int ch;			/* chance of being hit */
     65 static int op;			/* computer's open men */
     66 static int pt;			/* comp's protected points */
     67 static int em;			/* farthest man back */
     68 static int frc;			/* chance to free comp's men */
     69 static int frp;			/* chance to free pl's men */
     70 
     71  /* these values are the values for the move chosen (so far) */
     72 static int chance;		/* chance of being hit */
     73 static int openmen;		/* computer's open men */
     74 static int points;		/* comp's protected points */
     75 static int endman;		/* farthest man back */
     76 static int barmen;		/* men on bar */
     77 static int menin;		/* men in inner table */
     78 static int menoff;		/* men off board */
     79 static int oldfrc;		/* chance to free comp's men */
     80 static int oldfrp;		/* chance to free pl's men */
     81 
     82 static int cp[5];		/* candidate start position */
     83 static int cg[5];		/* candidate finish position */
     84 
     85 static int race;		/* game reduced to a race */
     86 
     87 
     88 static int bcomp(struct BOARD *, struct BOARD *);
     89 static struct BOARD *bsave(struct move *);
     90 static void binsert(struct move *, struct BOARD *);
     91 static void boardcopy(struct move *, struct BOARD *);
     92 static void makefree(struct BOARD *);
     93 static void mvcheck(struct move *, struct BOARD *, struct BOARD *);
     94 static struct BOARD *nextfree(void);
     95 static void trymove(struct move *, int, int);
     96 static void pickmove(struct move *);
     97 static void movcmp(struct move *);
     98 static int movegood(void);
     99 
    100 
    101 /* zero if first move */
    102 void
    103 move(struct move *mm, int okay)
    104 {
    105 	int     i;		/* index */
    106 	int     l;		/* last man */
    107 
    108 	l = 0;
    109 	if (okay) {
    110 		/* see if comp should double */
    111 		if (gvalue < 64 && dlast != cturn && dblgood()) {
    112 			writel(*Colorptr);
    113 			dble();	/* double */
    114 			/* return if declined */
    115 			if (cturn != 1 && cturn != -1)
    116 				return;
    117 		}
    118 		roll(mm);
    119 	}
    120 	race = 0;
    121 	for (i = 0; i < 26; i++) {
    122 		if (board[i] < 0)
    123 			l = i;
    124 	}
    125 	for (i = 0; i < l; i++) {
    126 		if (board[i] > 0)
    127 			break;
    128 	}
    129 	if (i == l)
    130 		race = 1;
    131 
    132 	/* print roll */
    133 	if (tflag)
    134 		curmove(cturn == -1 ? 18 : 19, 0);
    135 	writel(*Colorptr);
    136 	writel(" rolls ");
    137 	writec(mm->D0 + '0');
    138 	writec(' ');
    139 	writec(mm->D1 + '0');
    140 	/* make tty interruptable while thinking */
    141 	if (tflag)
    142 		cline();
    143 	fixtty(&noech);
    144 
    145 	/* find out how many moves */
    146 	mm->mvlim = movallow(mm);
    147 	if (mm->mvlim == 0) {
    148 		writel(" but cannot use it.\n");
    149 		nexturn();
    150 		fixtty(&raw);
    151 		return;
    152 	}
    153 	/* initialize */
    154 	for (i = 0; i < 4; i++)
    155 		cp[i] = cg[i] = 0;
    156 
    157 	/* strategize */
    158 	trymove(mm, 0, 0);
    159 	pickmove(mm);
    160 
    161 	/* print move */
    162 	writel(" and moves ");
    163 	for (i = 0; i < mm->mvlim; i++) {
    164 		if (i > 0)
    165 			writec(',');
    166 		wrint(mm->p[i] = cp[i]);
    167 		writec('-');
    168 		wrint(mm->g[i] = cg[i]);
    169 		makmove(mm, i);
    170 
    171 		/*
    172 		 * This assertion persuades gcc 4.5 that the loop
    173 		 * doesn't result in signed overflow of i. mvlim
    174 		 * isn't, or at least shouldn't be, changed by makmove
    175 		 * at all.
    176 		 */
    177 		assert(mm->mvlim >= 0 && mm->mvlim <= 5);
    178 	}
    179 	writec('.');
    180 
    181 	/* print blots hit */
    182 	if (tflag)
    183 		curmove(20, 0);
    184 	else
    185 		writec('\n');
    186 	for (i = 0; i < mm->mvlim; i++)
    187 		if (mm->h[i])
    188 			wrhit(mm->g[i]);
    189 	/* get ready for next move */
    190 	nexturn();
    191 	if (!okay) {
    192 		buflush();
    193 		sleep(3);
    194 	}
    195 	fixtty(&raw);		/* no more tty interrupt */
    196 }
    197 
    198 /* 	mvnum   == number of move (rel zero) */
    199 /* 	swapped == see if swapped also tested */
    200 static void
    201 trymove(struct move *mm, int mvnum, int swapped)
    202 {
    203 	int     pos;		/* position on board */
    204 	int     rval;		/* value of roll */
    205 
    206 	/* if recursed through all dice values, compare move */
    207 	if (mvnum == mm->mvlim) {
    208 		binsert(mm, bsave(mm));
    209 		return;
    210 	}
    211 	/* make sure dice in always same order */
    212 	if (mm->d0 == swapped)
    213 		mswap(mm);
    214 	/* choose value for this move */
    215 	rval = mm->dice[mvnum != 0];
    216 
    217 	/* find all legitimate moves */
    218 	for (pos = bar; pos != home; pos += cturn) {
    219 		/* fix order of dice */
    220 		if (mm->d0 == swapped)
    221 			mswap(mm);
    222 		/* break if stuck on bar */
    223 		if (board[bar] != 0 && pos != bar)
    224 			break;
    225 		/* on to next if not occupied */
    226 		if (board[pos] * cturn <= 0)
    227 			continue;
    228 		/* set up arrays for move */
    229 		mm->p[mvnum] = pos;
    230 		mm->g[mvnum] = pos + rval * cturn;
    231 		if (mm->g[mvnum] * cturn >= home) {
    232 			if (*offptr < 0)
    233 				break;
    234 			mm->g[mvnum] = home;
    235 		}
    236 		/* try to move */
    237 		if (makmove(mm, mvnum))
    238 			continue;
    239 		else
    240 			trymove(mm, mvnum + 1, 2);
    241 		/* undo move to try another */
    242 		backone(mm, mvnum);
    243 	}
    244 
    245 	/* swap dice and try again */
    246 	if ((!swapped) && mm->D0 != mm->D1)
    247 		trymove(mm, 0, 1);
    248 }
    249 
    250 static struct BOARD *
    251 bsave(struct move *mm)
    252 {
    253 	int     i;		/* index */
    254 	struct BOARD *now;	/* current position */
    255 
    256 	now = nextfree();	/* get free BOARD */
    257 
    258 	/* store position */
    259 	for (i = 0; i < 26; i++)
    260 		now->b_board[i] = board[i];
    261 	now->b_in[0] = in[0];
    262 	now->b_in[1] = in[1];
    263 	now->b_off[0] = off[0];
    264 	now->b_off[1] = off[1];
    265 	for (i = 0; i < mm->mvlim; i++) {
    266 		now->b_st[i] = mm->p[i];
    267 		now->b_fn[i] = mm->g[i];
    268 	}
    269 	return (now);
    270 }
    271 
    272 /* new == item to insert */
    273 static void
    274 binsert(struct move *mm, struct BOARD *new)
    275 {
    276 	struct BOARD *qp = checkq;	/* queue pointer */
    277 	int     result;		/* comparison result */
    278 
    279 	if (qp == 0) {		/* check if queue empty */
    280 		checkq = qp = new;
    281 		qp->b_next = 0;
    282 		return;
    283 	}
    284 	result = bcomp(new, qp);	/* compare to first element */
    285 	if (result < 0) {	/* insert in front */
    286 		new->b_next = qp;
    287 		checkq = new;
    288 		return;
    289 	}
    290 	if (result == 0) {	/* duplicate entry */
    291 		mvcheck(mm, qp, new);
    292 		makefree(new);
    293 		return;
    294 	}
    295 	while (qp->b_next != 0) {/* traverse queue */
    296 		result = bcomp(new, qp->b_next);
    297 		if (result < 0) {	/* found place */
    298 			new->b_next = qp->b_next;
    299 			qp->b_next = new;
    300 			return;
    301 		}
    302 		if (result == 0) {	/* duplicate entry */
    303 			mvcheck(mm, qp->b_next, new);
    304 			makefree(new);
    305 			return;
    306 		}
    307 		qp = qp->b_next;
    308 	}
    309 	/* place at end of queue */
    310 	qp->b_next = new;
    311 	new->b_next = 0;
    312 }
    313 
    314 static int
    315 bcomp(struct BOARD *a, struct BOARD *b)
    316 {
    317 	int    *aloc = a->b_board;	/* pointer to board a */
    318 	int    *bloc = b->b_board;	/* pointer to board b */
    319 	int     i;		/* index */
    320 	int     result;		/* comparison result */
    321 
    322 	for (i = 0; i < 26; i++) {	/* compare boards */
    323 		result = cturn * (aloc[i] - bloc[i]);
    324 		if (result)
    325 			return (result);	/* found inequality */
    326 	}
    327 	return (0);		/* same position */
    328 }
    329 
    330 static void
    331 mvcheck(struct move *mm, struct BOARD *incumbent, struct BOARD *candidate)
    332 {
    333 	int     i;
    334 	int     result;
    335 
    336 	for (i = 0; i < mm->mvlim; i++) {
    337 		result = cturn * (candidate->b_st[i] - incumbent->b_st[i]);
    338 		if (result > 0)
    339 			return;
    340 		if (result < 0)
    341 			break;
    342 	}
    343 	if (i == mm->mvlim)
    344 		return;
    345 	for (i = 0; i < mm->mvlim; i++) {
    346 		incumbent->b_st[i] = candidate->b_st[i];
    347 		incumbent->b_fn[i] = candidate->b_fn[i];
    348 	}
    349 }
    350 
    351 void
    352 makefree(struct BOARD *dead)
    353 {
    354 	dead->b_next = freeq;	/* add to freeq */
    355 	freeq = dead;
    356 }
    357 
    358 static struct BOARD *
    359 nextfree(void)
    360 {
    361 	struct BOARD *new;
    362 
    363 	if (freeq == 0) {
    364 		new = (struct BOARD *) calloc(1, sizeof(struct BOARD));
    365 		if (new == 0) {
    366 			writel("\nOut of memory\n");
    367 			getout(0);
    368 		}
    369 	} else {
    370 		new = freeq;
    371 		freeq = freeq->b_next;
    372 	}
    373 
    374 	new->b_next = 0;
    375 	return (new);
    376 }
    377 
    378 static void
    379 pickmove(struct move *mm)
    380 {
    381 	/* current game position */
    382 	struct BOARD *now = bsave(mm);
    383 	struct BOARD *next;	/* next move */
    384 
    385 #ifdef DEBUG
    386 	if (trace == NULL)
    387 		trace = fopen("bgtrace", "w");
    388 	fprintf(trace, "\nRoll:  %d %d%s\n", D0, D1, race ? " (race)" : "");
    389 	fflush(trace);
    390 #endif
    391 	do {			/* compare moves */
    392 		boardcopy(mm, checkq);
    393 		next = checkq->b_next;
    394 		makefree(checkq);
    395 		checkq = next;
    396 		movcmp(mm);
    397 	} while (checkq != 0);
    398 
    399 	boardcopy(mm, now);
    400 }
    401 
    402 static void
    403 boardcopy(struct move *mm, struct BOARD *s)
    404 {
    405 	int     i;		/* index */
    406 
    407 	for (i = 0; i < 26; i++)
    408 		board[i] = s->b_board[i];
    409 	for (i = 0; i < 2; i++) {
    410 		in[i] = s->b_in[i];
    411 		off[i] = s->b_off[i];
    412 	}
    413 	for (i = 0; i < mm->mvlim; i++) {
    414 		mm->p[i] = s->b_st[i];
    415 		mm->g[i] = s->b_fn[i];
    416 	}
    417 }
    418 
    419 static void
    420 movcmp(struct move *mm)
    421 {
    422 	int     i;
    423 
    424 #ifdef DEBUG
    425 	if (trace == NULL)
    426 		trace = fopen("bgtrace", "w");
    427 #endif
    428 
    429 	odds(0, 0, 0);
    430 	if (!race) {
    431 		ch = op = pt = 0;
    432 		for (i = 1; i < 25; i++) {
    433 			if (board[i] == cturn)
    434 				ch = canhit(i, 1);
    435 			op += abs(bar - i);
    436 		}
    437 		for (i = bar + cturn; i != home; i += cturn)
    438 			if (board[i] * cturn > 1)
    439 				pt += abs(bar - i);
    440 		frc = freemen(bar) + trapped(bar, cturn);
    441 		frp = freemen(home) + trapped(home, -cturn);
    442 	}
    443 	for (em = bar; em != home; em += cturn)
    444 		if (board[em] * cturn > 0)
    445 			break;
    446 	em = abs(home - em);
    447 #ifdef DEBUG
    448 	fputs("Board: ", trace);
    449 	for (i = 0; i < 26; i++)
    450 		fprintf(trace, " %d", board[i]);
    451 	if (race)
    452 		fprintf(trace, "\n\tem = %d\n", em);
    453 	else
    454 		fprintf(trace,
    455 		    "\n\tch = %d, pt = %d, em = %d, frc = %d, frp = %d\n",
    456 		    ch, pt, em, frc, frp);
    457 	fputs("\tMove: ", trace);
    458 	for (i = 0; i < mvlim; i++)
    459 		fprintf(trace, " %d-%d", p[i], g[i]);
    460 	fputs("\n", trace);
    461 	fflush(trace);
    462 	strcpy(tests, "");
    463 #endif
    464 	if ((cp[0] == 0 && cg[0] == 0) || movegood()) {
    465 #ifdef DEBUG
    466 		fprintf(trace, "\t[%s] ... wins.\n", tests);
    467 		fflush(trace);
    468 #endif
    469 		for (i = 0; i < mm->mvlim; i++) {
    470 			cp[i] = mm->p[i];
    471 			cg[i] = mm->g[i];
    472 		}
    473 		if (!race) {
    474 			chance = ch;
    475 			openmen = op;
    476 			points = pt;
    477 			endman = em;
    478 			barmen = abs(board[home]);
    479 			oldfrc = frc;
    480 			oldfrp = frp;
    481 		}
    482 		menin = *inptr;
    483 		menoff = *offptr;
    484 	}
    485 #ifdef DEBUG
    486 	else {
    487 		fprintf(trace, "\t[%s] ... loses.\n", tests);
    488 		fflush(trace);
    489 	}
    490 #endif
    491 }
    492 
    493 static int
    494 movegood(void)
    495 {
    496 	int     n;
    497 
    498 	if (*offptr == 15)
    499 		return (1);
    500 	if (menoff == 15)
    501 		return (0);
    502 	if (race) {
    503 #ifdef DEBUG
    504 		strcat(tests, "o");
    505 #endif
    506 		if (*offptr - menoff)
    507 			return (*offptr > menoff);
    508 #ifdef DEBUG
    509 		strcat(tests, "e");
    510 #endif
    511 		if (endman - em)
    512 			return (endman > em);
    513 #ifdef DEBUG
    514 		strcat(tests, "i");
    515 #endif
    516 		if (menin == 15)
    517 			return (0);
    518 		if (*inptr == 15)
    519 			return (1);
    520 #ifdef DEBUG
    521 		strcat(tests, "i");
    522 #endif
    523 		if (*inptr - menin)
    524 			return (*inptr > menin);
    525 		return (rnum(2));
    526 	} else {
    527 		n = barmen - abs(board[home]);
    528 #ifdef DEBUG
    529 		strcat(tests, "c");
    530 #endif
    531 		if (abs(chance - ch) + 25 * n > rnum(150))
    532 			return (n ? (n < 0) : (ch < chance));
    533 #ifdef DEBUG
    534 		strcat(tests, "o");
    535 #endif
    536 		if (*offptr - menoff)
    537 			return (*offptr > menoff);
    538 #ifdef DEBUG
    539 		strcat(tests, "o");
    540 #endif
    541 		if (abs(openmen - op) > 7 + rnum(12))
    542 			return (openmen > op);
    543 #ifdef DEBUG
    544 		strcat(tests, "b");
    545 #endif
    546 		if (n)
    547 			return (n < 0);
    548 #ifdef DEBUG
    549 		strcat(tests, "e");
    550 #endif
    551 		if (abs(endman - em) > rnum(2))
    552 			return (endman > em);
    553 #ifdef DEBUG
    554 		strcat(tests, "f");
    555 #endif
    556 		if (abs(frc - oldfrc) > rnum(2))
    557 			return (frc < oldfrc);
    558 #ifdef DEBUG
    559 		strcat(tests, "p");
    560 #endif
    561 		if (abs(n = pt - points) > rnum(4))
    562 			return (n > 0);
    563 #ifdef DEBUG
    564 		strcat(tests, "i");
    565 #endif
    566 		if (*inptr - menin)
    567 			return (*inptr > menin);
    568 #ifdef DEBUG
    569 		strcat(tests, "f");
    570 #endif
    571 		if (abs(frp - oldfrp) > rnum(2))
    572 			return (frp > oldfrp);
    573 		return (rnum(2));
    574 	}
    575 }
    576