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