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