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