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