BSD 4_4 development
[unix-history] / .ref-6294d633e80db8e89697db796e6f6025d5af0cae / usr / src / games / backgammon / common_source / backgammon.c
CommitLineData
07d1919e 1/*-
e0719df9
KB
2 * Copyright (c) 1991, 1993
3 * The Regents of the University of California. All rights reserved.
07d1919e
KB
4 *
5 * %sccs.include.redist.c%
6 */
c4c2d2dc 7
07d1919e 8#ifndef lint
e0719df9 9static char sccsid[] = "@(#)backgammon.c 8.1 (Berkeley) %G%";
07d1919e 10#endif /* not lint */
c4c2d2dc
KM
11
12/*
13** The game of Backgammon
14*/
15
16#include <stdio.h>
17
18#define WHITE 0
19#define BROWN 1
20#define NIL (-1)
21#define MAXGMOV 10
22#define MAXIMOVES 1000
23#define RULES "/usr/games/lib/backrules"
24
25char level; /*'b'=beginner, 'i'=intermediate, 'e'=expert*/
26
27int die1;
28int die2;
29int i;
30int j;
31int l;
32int m;
33int pflg = 1;
34int nobroll = 0;
35int count;
36int imoves;
37int goodmoves[MAXGMOV];
38int probmoves[MAXGMOV];
39
40int brown[] = { /* brown position table */
41 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5,
42 0, 0, 0, 0, 3, 0, 5, 0, 0, 0, 0, 0,
43 0, 0, 0, 0, 0, 0
44};
45
46int white[] = { /* white position table */
47 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5,
48 0, 0, 0, 0, 3, 0, 5, 0, 0, 0, 0, 0,
49 0, 0, 0, 0, 0, 0
50};
51
52int probability[] = {
53 0, 11, 12, 13, 14, 15, 16,
54 06, 05, 04, 03, 02, 01
55};
56
57struct {
58 int pos[4];
59 int mov[4];
60} moves[MAXIMOVES];
61
62main()
63{
64 int go[5], tvec[2];
65 int k, n, pid, ret, rpid, t;
66 char s[100];
67
68 srand(time(0));
69 go[5] = NIL;
70 fprintf(stdout, "Instructions? ");
71 gets(s);
72 if(*s == 'y')
73 instructions();
74 putchar('\n');
75 fprintf(stdout, "Opponent's level: b - beginner,\n");
76 fprintf(stdout, "i - intermediate, e - expert? ");
77 level='e';
78 gets(s);
79 if(*s == 'b')
80 level = 'b';
81 else if(*s == 'i')
82 level = 'i';
83 putchar('\n');
84 fprintf(stdout, "You will play brown.\n\n");
85 fprintf(stdout, "Would you like to roll your own dice? ");
86 gets(s);
87 putchar('\n');
88 if(*s == 'y')
89 nobroll = 1;
90 fprintf(stdout, "Would you like to go first? ");
91 gets(s);
92 putchar('\n');
93 if(*s == 'y')
94 goto nowhmove;
95whitesmv:
96 roll(WHITE);
97 fprintf(stdout, "white rolls %d, %d\n", die1, die2);
98 fprintf(stdout, "white's move is:");
99 if(nextmove(white, brown) == NIL)
100 goto nowhmove;
101 if(piececount(white, 0, 24) == 0){
102 fprintf(stdout, "White wins");
103 if(piececount(brown, 0, 6) != 0)
104 fprintf(stdout, " with a Backgammon!\n");
105 else if (piececount(brown, 0, 24) == 24)
106 fprintf(stdout, " with a Gammon.\n");
107 else
108 fprintf(stdout, ".\n");
109 exit(0);
110 }
111nowhmove:
112 if(pflg)
113 prtbrd();
114 roll(BROWN);
115retry:
116 fprintf(stdout, "\nYour roll is %d %d\n", die1, die2);
117 fprintf(stdout, "Move? ");
118 gets(s);
119 switch(*s) {
120 case '\0': /* empty line */
121 fprintf(stdout, "Brown's move skipped.\n");
122 goto whitesmv;
123
124 case 'b': /* how many beared off? */
125 fprintf(stdout, "Brown: %d\n", piececount(brown, 0, 24) - 15);
126 fprintf(stdout, "White: %d\n", piececount(white, 0, 24) - 15);
127 goto retry;
128
129 case 'p': /* print board */
130 prtbrd();
131 goto retry;
132
133 case 's': /* stop auto printing of board */
134 pflg = 0;
135 goto retry;
136
137 case 'r': /* resume auto printing */
138 pflg = 1;
139 goto retry;
140
141 case 'm': /* print possible moves */
142 pmoves();
143 goto retry;
144
145 case 'q': /* i give up */
146 exit(0);
147
148 case '!': /* escape to Shell */
149 if(s[1] != '\0')
150 system(s+1);
151 else if((pid = fork()) == 0) {
152 execl("/bin/sh", "sh", "-", 0);
153 fprintf(stderr, "back: cannot exec /bin/sh!\n");
154 exit(2);
155 }
156 while((rpid = wait(&ret)) != pid && rpid != -1)
157 ;
158 goto retry;
159
160 case '?': /* well, what can i do? */
161 fprintf(stdout, "<newline> skip this move\n");
162 fprintf(stdout, "b number beared off\n");
163 fprintf(stdout, "p print board\n");
164 fprintf(stdout, "q quit\n");
165 fprintf(stdout, "r resume auto print of board\n");
166 fprintf(stdout, "s stop auto print of board\n");
167 fprintf(stdout, "! escape to Shell\n");
168 goto retry;
169 }
170 n = sscanf(s,"%d%d%d%d%d",&go[0],&go[1],&go[2],&go[3],&go[4]);
171 if((die1 != die2 && n > 2) || n > 4){
172 fprintf(stdout, "Too many moves.\n");
173 goto retry;
174 }
175 go[n] = NIL;
176 if(*s=='-'){
177 go[0]= -go[0];
178 t=die1;
179 die1=die2;
180 die2=t;
181 }
182 for(k = 0; k < n; k++){
183 if(0 <= go[k] && go[k] <= 24)
184 continue;
185 else{
186 fprintf(stdout, "Move %d illegal.\n", go[k]);
187 goto retry;
188 }
189 }
190 if(play(brown, white, go))
191 goto retry;
192 if(piececount(brown, 0, 24) == 0){
193 fprintf(stdout, "Brown wins");
194 if(piececount(white, 0, 6) != 0)
195 fprintf(stdout, " with a Backgammon.\n");
196 else if(piececount(white, 0, 24) == 24)
197 fprintf(stdout, " with a gammon.\n");
198 else
199 fprintf(stdout, ".\n");
200 exit(0);
201 }
202 goto whitesmv;
203}
204
205play(player,playee,pos)
206int *player,*playee,pos[];
207{
208 int k, n, die, ipos;
209
210 for(k=0; k < player[0]; k++){ /*blots on player[0] must be moved first*/
211 if(pos[k] == NIL)
212 break;
213 if(pos[k] != 0){
214 fprintf(stdout, "Stone on bar must be moved first.\n");
215 return(NIL);
216 }
217 }
218 for(k = 0; (ipos=pos[k]) != NIL; k++){
219 die = k?die2:die1;
220 n = 25-ipos-die;
221 if(player[ipos] == 0)
222 goto badmove;
223 if(n > 0 && playee[n] >= 2)
224 goto badmove;
225 if(n <= 0){
226 if(piececount(player,0,18) != 0)
227 goto badmove;
228 if((ipos+die) != 25 && piececount(player,19,24-die)!=0)
229 goto badmove;
230 }
231 player[ipos]--;
232 player[ipos+die]++;
233 }
234 for(k = 0; pos[k] != NIL; k++){
235 die = k?die2:die1;
236 n = 25-pos[k]-die;
237 if(n>0 && playee[n]==1){
238 playee[n]=0;
239 playee[0]++;
240 }
241 }
242 return(0);
243
244badmove:
245 fprintf(stdout, "Move %d illegal.\n", ipos);
246 while(k--){
247 die=k?die2:die1;
248 player[pos[k]]++;
249 player[pos[k]+die]--;
250 }
251 return(NIL);
252}
253nextmove(player,playee)
254int *player,*playee;
255{
256 int k;
257
258 imoves=0;
259 movegen(player,playee);
260 if(die1!=die2){
261 k=die1;
262 die1=die2;
263 die2=k;
264 movegen(player,playee);
265 }
266 if(imoves==0){
267 fprintf(stdout, "no move possible.\n");
268 return(NIL);
269 }
270 k=strategy(player,playee); /*select kth possible move*/
271 prtmov(k);
272 update(player,playee,k);
273 return(0);
274}
275prtmov(k)
276int k;
277{
278 int n;
279
280 if(k == NIL)
281 fprintf(stdout, "No move possible\n");
282 else for(n = 0; n < 4; n++){
283 if(moves[k].pos[n] == NIL)
284 break;
285 fprintf(stdout, " %d, %d",25-moves[k].pos[n],moves[k].mov[n]);
286 }
287 fprintf(stdout, "\n");
288}
289update(player,playee,k)
290int *player,*playee,k;
291{
292 int n,t;
293
294 for(n = 0; n < 4; n++){
295 if(moves[k].pos[n] == NIL)
296 break;
297 player[moves[k].pos[n]]--;
298 player[moves[k].pos[n]+moves[k].mov[n]]++;
299 t=25-moves[k].pos[n]-moves[k].mov[n];
300 if(t>0 && playee[t]==1){
301 playee[0]++;
302 playee[t]--;
303 }
304 }
305}
306piececount(player,startrow,endrow)
307int *player,startrow,endrow;
308{
309 int sum;
310
311 sum=0;
312 while(startrow <= endrow)
313 sum += player[startrow++];
314 return(sum);
315}
316pmoves()
317{
318 int i1, i2;
319
320 fprintf(stdout, "Possible moves are:\n");
321 for(i1 = 0; i1 < imoves; i1++){
322 fprintf(stdout, "\n%d",i1);
323 for (i2 = 0; i2<4; i2++){
324 if(moves[i1].pos[i2] == NIL)
325 break;
326 fprintf(stdout, "%d, %d",moves[i1].pos[i2],moves[i1].mov[i2]);
327 }
328 }
329 fprintf(stdout, "\n");
330}
331
332roll(who)
333{
334 register n;
335 char s[10];
336
337 if(who == BROWN && nobroll) {
338 fprintf(stdout, "Roll? ");
339 gets(s);
340 n = sscanf(s, "%d%d", &die1, &die2);
341 if(n != 2 || die1 < 1 || die1 > 6 || die2 < 1 || die2 > 6)
342 fprintf(stdout, "Illegal - I'll do it!\n");
343 else
344 return;
345 }
346 die1 = ((rand()>>8) % 6) + 1;
347 die2 = ((rand()>>8) % 6) + 1;
348}
349
350movegen(mover,movee)
351int *mover,*movee;
352{
353 int k;
354
355 for(i = 0; i <= 24; i++){
356 count = 0;
357 if(mover[i] == 0)
358 continue;
359 if((k=25-i-die1) > 0 && movee[k] >= 2)
360 if(mover[0] > 0)
361 break;
362 else
363 continue;
364 if(k <= 0){
365 if(piececount(mover, 0, 18) != 0)
366 break;
367 if((i+die1) != 25 && piececount(mover,19,i-1) != 0)
368 break;
369 }
370 mover[i]--;
371 mover[i+die1]++;
372 count = 1;
373 for(j = 0; j <= 24; j++){
374 if(mover[j]==0)
375 continue;
376 if((k=25-j-die2) > 0 && movee[k] >= 2)
377 if(mover[0] > 0)
378 break;
379 else
380 continue;
381 if(k <= 0){
382 if(piececount(mover,0,18) != 0)
383 break;
384 if((j+die2) != 25 && piececount(mover,19,j-1) != 0)
385 break;
386 }
387 mover[j]--;
388 mover[j+die2]++;
389 count = 2;
390 if(die1 != die2){
391 moverecord(mover);
392 if(mover[0] > 0)
393 break;
394 else
395 continue;
396 }
397 for(l = 0; l <= 24; l++){
398 if(mover[l] == 0)
399 continue;
400 if((k=25-l-die1) > 0 && movee[k] >= 2)
401 if(mover[0] > 0)
402 break;
403 else
404 continue;
405 if(k <= 0){
406 if(piececount(mover, 0, 18) != 0)
407 break;
408 if((l+die2) != 25 && piececount(mover,19,l-1) != 0)
409 break;
410 }
411 mover[l]--;
412 mover[l+die1]++;
413 count=3;
414 for(m=0;m<=24;m++){
415 if(mover[m]==0)
416 continue;
417 if((k=25-m-die1) >= 0 && movee[k] >= 2)
418 if(mover[0] > 0)
419 break;
420 else
421 continue;
422 if(k <= 0){
423 if(piececount(mover,0,18) != 0)
424 break;
425 if((m+die2) != 25 && piececount(mover,19,m-1) != 0)
426 break;
427 }
428 count=4;
429 moverecord(mover);
430 if(mover[0] > 0)
431 break;
432 }
433 if(count == 3)
434 moverecord(mover);
435 else{
436 mover[l]++;
437 mover[l+die1]--;
438 }
439 if(mover[0] > 0)
440 break;
441 }
442 if(count == 2)
443 moverecord(mover);
444 else{
445 mover[j]++;
446 mover[j+die1]--;
447 }
448 if(mover[0] > 0)
449 break;
450 }
451 if(count == 1)
452 moverecord(mover);
453 else{
454 mover[i]++;
455 mover[i+die1]--;
456 }
457 if(mover[0] > 0)
458 break;
459 }
460}
461moverecord(mover)
462int *mover;
463{
464 int t;
465
466 if(imoves < MAXIMOVES) {
467 for(t = 0; t <= 3; t++)
468 moves[imoves].pos[t] = NIL;
469 switch(count) {
470 case 4:
471 moves[imoves].pos[3]=m;
472 moves[imoves].mov[3]=die1;
473
474 case 3:
475 moves[imoves].pos[2]=l;
476 moves[imoves].mov[2]=die1;
477
478 case 2:
479 moves[imoves].pos[1]=j;
480 moves[imoves].mov[1]=die2;
481
482 case 1:
483 moves[imoves].pos[0]=i;
484 moves[imoves].mov[0]=die1;
485 imoves++;
486 }
487 }
488 switch(count) {
489 case 4:
490 break;
491
492 case 3:
493 mover[l]++;
494 mover[l+die1]--;
495 break;
496
497 case 2:
498 mover[j]++;
499 mover[j+die2]--;
500 break;
501
502 case 1:
503 mover[i]++;
504 mover[i+die1]--;
505 }
506}
507
508strategy(player,playee)
509int *player,*playee;
510{
511 int k, n, nn, bestval, moveval, prob;
512
513 n = 0;
514 if(imoves == 0)
515 return(NIL);
516 goodmoves[0] = NIL;
517 bestval = -32000;
518 for(k = 0; k < imoves; k++){
519 if((moveval=eval(player,playee,k,&prob)) < bestval)
520 continue;
521 if(moveval > bestval){
522 bestval = moveval;
523 n = 0;
524 }
525 if(n<MAXGMOV){
526 goodmoves[n]=k;
527 probmoves[n++]=prob;
528 }
529 }
530 if(level=='e' && n>1){
531 nn=n;
532 n=0;
533 prob=32000;
534 for(k = 0; k < nn; k++){
535 if((moveval=probmoves[k]) > prob)
536 continue;
537 if(moveval<prob){
538 prob=moveval;
539 n=0;
540 }
541 goodmoves[n]=goodmoves[k];
542 probmoves[n++]=probmoves[k];
543 }
544 }
545 return(goodmoves[(rand()>>4)%n]);
546}
547
548eval(player,playee,k,prob)
549int *player,*playee,k,*prob;
550{
551 int newtry[31], newother[31], *r, *q, *p, n, sum, first;
552 int ii, lastwhite, lastbrown;
553
554 *prob = sum = 0;
555 r = player+25;
556 p = newtry;
557 q = newother;
558 while(player<r){
559 *p++= *player++;
560 *q++= *playee++;
561 }
562 q=newtry+31;
563 for(p = newtry+25; p < q; p++) /* zero out spaces for hit pieces */
564 *p = 0;
565 for(n = 0; n < 4; n++){
566 if(moves[k].pos[n] == NIL)
567 break;
568 newtry[moves[k].pos[n]]--;
569 newtry[ii=moves[k].pos[n]+moves[k].mov[n]]++;
570 if(ii<25 && newother[25-ii]==1){
571 newother[25-ii]=0;
572 newother[0]++;
573 if(ii<=15 && level=='e') /* hit if near other's home */
574 sum++;
575 }
576 }
577 for(lastbrown = 0; newother[lastbrown] == 0; lastbrown++);
578 ;
579 for(lastwhite = 0; newtry[lastwhite] == 0; lastwhite++)
580 ;
581 lastwhite = 25-lastwhite;
582 if(lastwhite<=6 && lastwhite<lastbrown)
583 sum=1000;
584 /* experts running game. */
585 /* first priority is to */
586 /* get all pieces into */
587 /* white's home */
588 if(lastwhite<lastbrown && level=='e' && lastwhite>6) {
589 for(sum = 1000; lastwhite > 6; lastwhite--)
590 sum = sum-lastwhite*newtry[25-lastwhite];
591 }
592 for(first = 0; first < 25; first++)
593 if(newother[first] != 0) /*find other's first piece*/
594 break;
595 q = newtry+25;
596 for(p = newtry+1; p < q;) /* blocked points are good */
597 if(*p++ > 1)
598 sum++;
599 if(first > 5) { /* only stress removing pieces if */
600 /* homeboard cannot be hit */
601 q = newtry+31;
602 p=newtry+25;
603 for(n = 6; p < q; n--)
604 sum += *p++ * n; /*remove pieces, but just barely*/
605 }
606 if(level != 'b'){
607 r = newtry+25-first; /*singles past this point can't be hit*/
608 for(p = newtry+7; p < r; )
609 if(*p++ == 1) /*singles are bad after 1st 6 points if they can be hit*/
610 sum--;
611 q = newtry+3;
612 for(p = newtry; p < q; ) /*bad to be on 1st three points*/
613 sum -= *p++;
614 }
615
616 for(n = 1; n <= 4; n++)
617 *prob += n*getprob(newtry,newother,6*n-5,6*n);
618 return(sum);
619}
620instructions()
621{
622 register fd, r;
623 char buf[BUFSIZ];
624
625 if((fd = open(RULES, 0)) < 0) {
626 fprintf(stderr, "back: cannot open %s\n", RULES);
627 return;
628 }
629 while(r = read(fd, buf, BUFSIZ))
630 write(1, buf, r);
631}
632
633getprob(player,playee,start,finish)
634int *player,*playee,start,finish;
635{ /*returns the probability (times 102) that any
636 pieces belonging to 'player' and lying between
637 his points 'start' and 'finish' will be hit
638 by a piece belonging to playee
639 */
640 int k, n, sum;
641
642 sum = 0;
643 for(; start <= finish; start++){
644 if(player[start] == 1){
645 for(k = 1; k <= 12; k++){
646 if((n=25-start-k) < 0)
647 break;
648 if(playee[n] != 0)
649 sum += probability[k];
650 }
651 }
652 }
653 return(sum);
654}
655prtbrd()
656{
657 int k;
658 static char undersc[]="______________________________________________________";
659
660 fprintf(stdout, "White's Home\n%s\r",undersc);
661 for(k = 1; k <= 6; k++)
662 fprintf(stdout, "%4d",k);
663 fprintf(stdout, " ");
664 for(k = 7; k <= 12; k++)
665 fprintf(stdout, "%4d",k);
666 putchar('\n');
667 numline(brown, white, 1, 6);
668 fprintf(stdout, " ");
669 numline(brown, white, 7, 12);
670 putchar('\n');
671 colorline(brown, 'B', white, 'W', 1, 6);
672 fprintf(stdout, " ");
673 colorline(brown, 'B', white, 'W', 7, 12);
674 putchar('\n');
675 if(white[0] != 0)
676 fprintf(stdout, "%28dW\n",white[0]);
677 else
678 putchar('\n');
679 if(brown[0] != 0)
680 fprintf(stdout, "%28dB\n", brown[0]);
681 else
682 putchar('\n');
683 colorline(white, 'W', brown, 'B', 1, 6);
684 fprintf(stdout, " ");
685 colorline(white, 'W', brown, 'B', 7, 12);
686 fprintf(stdout, "\n%s\r",undersc);
687 numline(white, brown, 1, 6);
688 fprintf(stdout, " ");
689 numline(white, brown, 7, 12);
690 putchar('\n');
691 for(k = 24; k >= 19; k--)
692 fprintf(stdout, "%4d",k);
693 fprintf(stdout, " ");
694 for(k = 18; k >= 13; k--)
695 fprintf(stdout, "%4d",k);
696 fprintf(stdout, "\nBrown's Home\n\n\n\n\n");
697}
698numline(upcol,downcol,start,fin)
699int *upcol,*downcol,start,fin;
700{
701 int k, n;
702
703 for(k = start; k <= fin; k++){
704 if((n = upcol[k]) != 0 || (n = downcol[25-k]) != 0)
705 fprintf(stdout, "%4d", n);
706 else
707 fprintf(stdout, " ");
708 }
709}
710colorline(upcol,c1,downcol,c2,start,fin)
711int *upcol,*downcol,start,fin;
712char c1,c2;
713{
714 int k;
715 char c;
716
717 for(k = start; k <= fin; k++){
718 c = ' ';
719 if(upcol[k] != 0)
720 c = c1;
721 if(downcol[25-k] != 0)
722 c = c2;
723 fprintf(stdout, " %c",c);
724 }
725}