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