summaryrefslogtreecommitdiffstats
path: root/backgammon/common_source/backgammon.c
diff options
context:
space:
mode:
Diffstat (limited to 'backgammon/common_source/backgammon.c')
-rw-r--r--backgammon/common_source/backgammon.c751
1 files changed, 751 insertions, 0 deletions
diff --git a/backgammon/common_source/backgammon.c b/backgammon/common_source/backgammon.c
new file mode 100644
index 00000000..036301f4
--- /dev/null
+++ b/backgammon/common_source/backgammon.c
@@ -0,0 +1,751 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)backgammon.c 5.1 (Berkeley) 4/8/91";
+#endif /* not lint */
+
+/*
+** The game of Backgammon
+*/
+
+#include <stdio.h>
+
+#define WHITE 0
+#define BROWN 1
+#define NIL (-1)
+#define MAXGMOV 10
+#define MAXIMOVES 1000
+#define RULES "/usr/games/lib/backrules"
+
+char level; /*'b'=beginner, 'i'=intermediate, 'e'=expert*/
+
+int die1;
+int die2;
+int i;
+int j;
+int l;
+int m;
+int pflg = 1;
+int nobroll = 0;
+int count;
+int imoves;
+int goodmoves[MAXGMOV];
+int probmoves[MAXGMOV];
+
+int brown[] = { /* brown position table */
+ 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5,
+ 0, 0, 0, 0, 3, 0, 5, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0
+};
+
+int white[] = { /* white position table */
+ 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5,
+ 0, 0, 0, 0, 3, 0, 5, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0
+};
+
+int probability[] = {
+ 0, 11, 12, 13, 14, 15, 16,
+ 06, 05, 04, 03, 02, 01
+};
+
+struct {
+ int pos[4];
+ int mov[4];
+} moves[MAXIMOVES];
+
+main()
+{
+ int go[5], tvec[2];
+ int k, n, pid, ret, rpid, t;
+ char s[100];
+
+ srand(time(0));
+ go[5] = NIL;
+ fprintf(stdout, "Instructions? ");
+ gets(s);
+ if(*s == 'y')
+ instructions();
+ putchar('\n');
+ fprintf(stdout, "Opponent's level: b - beginner,\n");
+ fprintf(stdout, "i - intermediate, e - expert? ");
+ level='e';
+ gets(s);
+ if(*s == 'b')
+ level = 'b';
+ else if(*s == 'i')
+ level = 'i';
+ putchar('\n');
+ fprintf(stdout, "You will play brown.\n\n");
+ fprintf(stdout, "Would you like to roll your own dice? ");
+ gets(s);
+ putchar('\n');
+ if(*s == 'y')
+ nobroll = 1;
+ fprintf(stdout, "Would you like to go first? ");
+ gets(s);
+ putchar('\n');
+ if(*s == 'y')
+ goto nowhmove;
+whitesmv:
+ roll(WHITE);
+ fprintf(stdout, "white rolls %d, %d\n", die1, die2);
+ fprintf(stdout, "white's move is:");
+ if(nextmove(white, brown) == NIL)
+ goto nowhmove;
+ if(piececount(white, 0, 24) == 0){
+ fprintf(stdout, "White wins");
+ if(piececount(brown, 0, 6) != 0)
+ fprintf(stdout, " with a Backgammon!\n");
+ else if (piececount(brown, 0, 24) == 24)
+ fprintf(stdout, " with a Gammon.\n");
+ else
+ fprintf(stdout, ".\n");
+ exit(0);
+ }
+nowhmove:
+ if(pflg)
+ prtbrd();
+ roll(BROWN);
+retry:
+ fprintf(stdout, "\nYour roll is %d %d\n", die1, die2);
+ fprintf(stdout, "Move? ");
+ gets(s);
+ switch(*s) {
+ case '\0': /* empty line */
+ fprintf(stdout, "Brown's move skipped.\n");
+ goto whitesmv;
+
+ case 'b': /* how many beared off? */
+ fprintf(stdout, "Brown: %d\n", piececount(brown, 0, 24) - 15);
+ fprintf(stdout, "White: %d\n", piececount(white, 0, 24) - 15);
+ goto retry;
+
+ case 'p': /* print board */
+ prtbrd();
+ goto retry;
+
+ case 's': /* stop auto printing of board */
+ pflg = 0;
+ goto retry;
+
+ case 'r': /* resume auto printing */
+ pflg = 1;
+ goto retry;
+
+ case 'm': /* print possible moves */
+ pmoves();
+ goto retry;
+
+ case 'q': /* i give up */
+ exit(0);
+
+ case '!': /* escape to Shell */
+ if(s[1] != '\0')
+ system(s+1);
+ else if((pid = fork()) == 0) {
+ execl("/bin/sh", "sh", "-", 0);
+ fprintf(stderr, "back: cannot exec /bin/sh!\n");
+ exit(2);
+ }
+ while((rpid = wait(&ret)) != pid && rpid != -1)
+ ;
+ goto retry;
+
+ case '?': /* well, what can i do? */
+ fprintf(stdout, "<newline> skip this move\n");
+ fprintf(stdout, "b number beared off\n");
+ fprintf(stdout, "p print board\n");
+ fprintf(stdout, "q quit\n");
+ fprintf(stdout, "r resume auto print of board\n");
+ fprintf(stdout, "s stop auto print of board\n");
+ fprintf(stdout, "! escape to Shell\n");
+ goto retry;
+ }
+ n = sscanf(s,"%d%d%d%d%d",&go[0],&go[1],&go[2],&go[3],&go[4]);
+ if((die1 != die2 && n > 2) || n > 4){
+ fprintf(stdout, "Too many moves.\n");
+ goto retry;
+ }
+ go[n] = NIL;
+ if(*s=='-'){
+ go[0]= -go[0];
+ t=die1;
+ die1=die2;
+ die2=t;
+ }
+ for(k = 0; k < n; k++){
+ if(0 <= go[k] && go[k] <= 24)
+ continue;
+ else{
+ fprintf(stdout, "Move %d illegal.\n", go[k]);
+ goto retry;
+ }
+ }
+ if(play(brown, white, go))
+ goto retry;
+ if(piececount(brown, 0, 24) == 0){
+ fprintf(stdout, "Brown wins");
+ if(piececount(white, 0, 6) != 0)
+ fprintf(stdout, " with a Backgammon.\n");
+ else if(piececount(white, 0, 24) == 24)
+ fprintf(stdout, " with a gammon.\n");
+ else
+ fprintf(stdout, ".\n");
+ exit(0);
+ }
+ goto whitesmv;
+}
+
+play(player,playee,pos)
+int *player,*playee,pos[];
+{
+ int k, n, die, ipos;
+
+ for(k=0; k < player[0]; k++){ /*blots on player[0] must be moved first*/
+ if(pos[k] == NIL)
+ break;
+ if(pos[k] != 0){
+ fprintf(stdout, "Stone on bar must be moved first.\n");
+ return(NIL);
+ }
+ }
+ for(k = 0; (ipos=pos[k]) != NIL; k++){
+ die = k?die2:die1;
+ n = 25-ipos-die;
+ if(player[ipos] == 0)
+ goto badmove;
+ if(n > 0 && playee[n] >= 2)
+ goto badmove;
+ if(n <= 0){
+ if(piececount(player,0,18) != 0)
+ goto badmove;
+ if((ipos+die) != 25 && piececount(player,19,24-die)!=0)
+ goto badmove;
+ }
+ player[ipos]--;
+ player[ipos+die]++;
+ }
+ for(k = 0; pos[k] != NIL; k++){
+ die = k?die2:die1;
+ n = 25-pos[k]-die;
+ if(n>0 && playee[n]==1){
+ playee[n]=0;
+ playee[0]++;
+ }
+ }
+ return(0);
+
+badmove:
+ fprintf(stdout, "Move %d illegal.\n", ipos);
+ while(k--){
+ die=k?die2:die1;
+ player[pos[k]]++;
+ player[pos[k]+die]--;
+ }
+ return(NIL);
+}
+nextmove(player,playee)
+int *player,*playee;
+{
+ int k;
+
+ imoves=0;
+ movegen(player,playee);
+ if(die1!=die2){
+ k=die1;
+ die1=die2;
+ die2=k;
+ movegen(player,playee);
+ }
+ if(imoves==0){
+ fprintf(stdout, "no move possible.\n");
+ return(NIL);
+ }
+ k=strategy(player,playee); /*select kth possible move*/
+ prtmov(k);
+ update(player,playee,k);
+ return(0);
+}
+prtmov(k)
+int k;
+{
+ int n;
+
+ if(k == NIL)
+ fprintf(stdout, "No move possible\n");
+ else for(n = 0; n < 4; n++){
+ if(moves[k].pos[n] == NIL)
+ break;
+ fprintf(stdout, " %d, %d",25-moves[k].pos[n],moves[k].mov[n]);
+ }
+ fprintf(stdout, "\n");
+}
+update(player,playee,k)
+int *player,*playee,k;
+{
+ int n,t;
+
+ for(n = 0; n < 4; n++){
+ if(moves[k].pos[n] == NIL)
+ break;
+ player[moves[k].pos[n]]--;
+ player[moves[k].pos[n]+moves[k].mov[n]]++;
+ t=25-moves[k].pos[n]-moves[k].mov[n];
+ if(t>0 && playee[t]==1){
+ playee[0]++;
+ playee[t]--;
+ }
+ }
+}
+piececount(player,startrow,endrow)
+int *player,startrow,endrow;
+{
+ int sum;
+
+ sum=0;
+ while(startrow <= endrow)
+ sum += player[startrow++];
+ return(sum);
+}
+pmoves()
+{
+ int i1, i2;
+
+ fprintf(stdout, "Possible moves are:\n");
+ for(i1 = 0; i1 < imoves; i1++){
+ fprintf(stdout, "\n%d",i1);
+ for (i2 = 0; i2<4; i2++){
+ if(moves[i1].pos[i2] == NIL)
+ break;
+ fprintf(stdout, "%d, %d",moves[i1].pos[i2],moves[i1].mov[i2]);
+ }
+ }
+ fprintf(stdout, "\n");
+}
+
+roll(who)
+{
+ register n;
+ char s[10];
+
+ if(who == BROWN && nobroll) {
+ fprintf(stdout, "Roll? ");
+ gets(s);
+ n = sscanf(s, "%d%d", &die1, &die2);
+ if(n != 2 || die1 < 1 || die1 > 6 || die2 < 1 || die2 > 6)
+ fprintf(stdout, "Illegal - I'll do it!\n");
+ else
+ return;
+ }
+ die1 = ((rand()>>8) % 6) + 1;
+ die2 = ((rand()>>8) % 6) + 1;
+}
+
+movegen(mover,movee)
+int *mover,*movee;
+{
+ int k;
+
+ for(i = 0; i <= 24; i++){
+ count = 0;
+ if(mover[i] == 0)
+ continue;
+ if((k=25-i-die1) > 0 && movee[k] >= 2)
+ if(mover[0] > 0)
+ break;
+ else
+ continue;
+ if(k <= 0){
+ if(piececount(mover, 0, 18) != 0)
+ break;
+ if((i+die1) != 25 && piececount(mover,19,i-1) != 0)
+ break;
+ }
+ mover[i]--;
+ mover[i+die1]++;
+ count = 1;
+ for(j = 0; j <= 24; j++){
+ if(mover[j]==0)
+ continue;
+ if((k=25-j-die2) > 0 && movee[k] >= 2)
+ if(mover[0] > 0)
+ break;
+ else
+ continue;
+ if(k <= 0){
+ if(piececount(mover,0,18) != 0)
+ break;
+ if((j+die2) != 25 && piececount(mover,19,j-1) != 0)
+ break;
+ }
+ mover[j]--;
+ mover[j+die2]++;
+ count = 2;
+ if(die1 != die2){
+ moverecord(mover);
+ if(mover[0] > 0)
+ break;
+ else
+ continue;
+ }
+ for(l = 0; l <= 24; l++){
+ if(mover[l] == 0)
+ continue;
+ if((k=25-l-die1) > 0 && movee[k] >= 2)
+ if(mover[0] > 0)
+ break;
+ else
+ continue;
+ if(k <= 0){
+ if(piececount(mover, 0, 18) != 0)
+ break;
+ if((l+die2) != 25 && piececount(mover,19,l-1) != 0)
+ break;
+ }
+ mover[l]--;
+ mover[l+die1]++;
+ count=3;
+ for(m=0;m<=24;m++){
+ if(mover[m]==0)
+ continue;
+ if((k=25-m-die1) >= 0 && movee[k] >= 2)
+ if(mover[0] > 0)
+ break;
+ else
+ continue;
+ if(k <= 0){
+ if(piececount(mover,0,18) != 0)
+ break;
+ if((m+die2) != 25 && piececount(mover,19,m-1) != 0)
+ break;
+ }
+ count=4;
+ moverecord(mover);
+ if(mover[0] > 0)
+ break;
+ }
+ if(count == 3)
+ moverecord(mover);
+ else{
+ mover[l]++;
+ mover[l+die1]--;
+ }
+ if(mover[0] > 0)
+ break;
+ }
+ if(count == 2)
+ moverecord(mover);
+ else{
+ mover[j]++;
+ mover[j+die1]--;
+ }
+ if(mover[0] > 0)
+ break;
+ }
+ if(count == 1)
+ moverecord(mover);
+ else{
+ mover[i]++;
+ mover[i+die1]--;
+ }
+ if(mover[0] > 0)
+ break;
+ }
+}
+moverecord(mover)
+int *mover;
+{
+ int t;
+
+ if(imoves < MAXIMOVES) {
+ for(t = 0; t <= 3; t++)
+ moves[imoves].pos[t] = NIL;
+ switch(count) {
+ case 4:
+ moves[imoves].pos[3]=m;
+ moves[imoves].mov[3]=die1;
+
+ case 3:
+ moves[imoves].pos[2]=l;
+ moves[imoves].mov[2]=die1;
+
+ case 2:
+ moves[imoves].pos[1]=j;
+ moves[imoves].mov[1]=die2;
+
+ case 1:
+ moves[imoves].pos[0]=i;
+ moves[imoves].mov[0]=die1;
+ imoves++;
+ }
+ }
+ switch(count) {
+ case 4:
+ break;
+
+ case 3:
+ mover[l]++;
+ mover[l+die1]--;
+ break;
+
+ case 2:
+ mover[j]++;
+ mover[j+die2]--;
+ break;
+
+ case 1:
+ mover[i]++;
+ mover[i+die1]--;
+ }
+}
+
+strategy(player,playee)
+int *player,*playee;
+{
+ int k, n, nn, bestval, moveval, prob;
+
+ n = 0;
+ if(imoves == 0)
+ return(NIL);
+ goodmoves[0] = NIL;
+ bestval = -32000;
+ for(k = 0; k < imoves; k++){
+ if((moveval=eval(player,playee,k,&prob)) < bestval)
+ continue;
+ if(moveval > bestval){
+ bestval = moveval;
+ n = 0;
+ }
+ if(n<MAXGMOV){
+ goodmoves[n]=k;
+ probmoves[n++]=prob;
+ }
+ }
+ if(level=='e' && n>1){
+ nn=n;
+ n=0;
+ prob=32000;
+ for(k = 0; k < nn; k++){
+ if((moveval=probmoves[k]) > prob)
+ continue;
+ if(moveval<prob){
+ prob=moveval;
+ n=0;
+ }
+ goodmoves[n]=goodmoves[k];
+ probmoves[n++]=probmoves[k];
+ }
+ }
+ return(goodmoves[(rand()>>4)%n]);
+}
+
+eval(player,playee,k,prob)
+int *player,*playee,k,*prob;
+{
+ int newtry[31], newother[31], *r, *q, *p, n, sum, first;
+ int ii, lastwhite, lastbrown;
+
+ *prob = sum = 0;
+ r = player+25;
+ p = newtry;
+ q = newother;
+ while(player<r){
+ *p++= *player++;
+ *q++= *playee++;
+ }
+ q=newtry+31;
+ for(p = newtry+25; p < q; p++) /* zero out spaces for hit pieces */
+ *p = 0;
+ for(n = 0; n < 4; n++){
+ if(moves[k].pos[n] == NIL)
+ break;
+ newtry[moves[k].pos[n]]--;
+ newtry[ii=moves[k].pos[n]+moves[k].mov[n]]++;
+ if(ii<25 && newother[25-ii]==1){
+ newother[25-ii]=0;
+ newother[0]++;
+ if(ii<=15 && level=='e') /* hit if near other's home */
+ sum++;
+ }
+ }
+ for(lastbrown = 0; newother[lastbrown] == 0; lastbrown++);
+ ;
+ for(lastwhite = 0; newtry[lastwhite] == 0; lastwhite++)
+ ;
+ lastwhite = 25-lastwhite;
+ if(lastwhite<=6 && lastwhite<lastbrown)
+ sum=1000;
+ /* experts running game. */
+ /* first priority is to */
+ /* get all pieces into */
+ /* white's home */
+ if(lastwhite<lastbrown && level=='e' && lastwhite>6) {
+ for(sum = 1000; lastwhite > 6; lastwhite--)
+ sum = sum-lastwhite*newtry[25-lastwhite];
+ }
+ for(first = 0; first < 25; first++)
+ if(newother[first] != 0) /*find other's first piece*/
+ break;
+ q = newtry+25;
+ for(p = newtry+1; p < q;) /* blocked points are good */
+ if(*p++ > 1)
+ sum++;
+ if(first > 5) { /* only stress removing pieces if */
+ /* homeboard cannot be hit */
+ q = newtry+31;
+ p=newtry+25;
+ for(n = 6; p < q; n--)
+ sum += *p++ * n; /*remove pieces, but just barely*/
+ }
+ if(level != 'b'){
+ r = newtry+25-first; /*singles past this point can't be hit*/
+ for(p = newtry+7; p < r; )
+ if(*p++ == 1) /*singles are bad after 1st 6 points if they can be hit*/
+ sum--;
+ q = newtry+3;
+ for(p = newtry; p < q; ) /*bad to be on 1st three points*/
+ sum -= *p++;
+ }
+
+ for(n = 1; n <= 4; n++)
+ *prob += n*getprob(newtry,newother,6*n-5,6*n);
+ return(sum);
+}
+instructions()
+{
+ register fd, r;
+ char buf[BUFSIZ];
+
+ if((fd = open(RULES, 0)) < 0) {
+ fprintf(stderr, "back: cannot open %s\n", RULES);
+ return;
+ }
+ while(r = read(fd, buf, BUFSIZ))
+ write(1, buf, r);
+}
+
+getprob(player,playee,start,finish)
+int *player,*playee,start,finish;
+{ /*returns the probability (times 102) that any
+ pieces belonging to 'player' and lying between
+ his points 'start' and 'finish' will be hit
+ by a piece belonging to playee
+ */
+ int k, n, sum;
+
+ sum = 0;
+ for(; start <= finish; start++){
+ if(player[start] == 1){
+ for(k = 1; k <= 12; k++){
+ if((n=25-start-k) < 0)
+ break;
+ if(playee[n] != 0)
+ sum += probability[k];
+ }
+ }
+ }
+ return(sum);
+}
+prtbrd()
+{
+ int k;
+ static char undersc[]="______________________________________________________";
+
+ fprintf(stdout, "White's Home\n%s\r",undersc);
+ for(k = 1; k <= 6; k++)
+ fprintf(stdout, "%4d",k);
+ fprintf(stdout, " ");
+ for(k = 7; k <= 12; k++)
+ fprintf(stdout, "%4d",k);
+ putchar('\n');
+ numline(brown, white, 1, 6);
+ fprintf(stdout, " ");
+ numline(brown, white, 7, 12);
+ putchar('\n');
+ colorline(brown, 'B', white, 'W', 1, 6);
+ fprintf(stdout, " ");
+ colorline(brown, 'B', white, 'W', 7, 12);
+ putchar('\n');
+ if(white[0] != 0)
+ fprintf(stdout, "%28dW\n",white[0]);
+ else
+ putchar('\n');
+ if(brown[0] != 0)
+ fprintf(stdout, "%28dB\n", brown[0]);
+ else
+ putchar('\n');
+ colorline(white, 'W', brown, 'B', 1, 6);
+ fprintf(stdout, " ");
+ colorline(white, 'W', brown, 'B', 7, 12);
+ fprintf(stdout, "\n%s\r",undersc);
+ numline(white, brown, 1, 6);
+ fprintf(stdout, " ");
+ numline(white, brown, 7, 12);
+ putchar('\n');
+ for(k = 24; k >= 19; k--)
+ fprintf(stdout, "%4d",k);
+ fprintf(stdout, " ");
+ for(k = 18; k >= 13; k--)
+ fprintf(stdout, "%4d",k);
+ fprintf(stdout, "\nBrown's Home\n\n\n\n\n");
+}
+numline(upcol,downcol,start,fin)
+int *upcol,*downcol,start,fin;
+{
+ int k, n;
+
+ for(k = start; k <= fin; k++){
+ if((n = upcol[k]) != 0 || (n = downcol[25-k]) != 0)
+ fprintf(stdout, "%4d", n);
+ else
+ fprintf(stdout, " ");
+ }
+}
+colorline(upcol,c1,downcol,c2,start,fin)
+int *upcol,*downcol,start,fin;
+char c1,c2;
+{
+ int k;
+ char c;
+
+ for(k = start; k <= fin; k++){
+ c = ' ';
+ if(upcol[k] != 0)
+ c = c1;
+ if(downcol[25-k] != 0)
+ c = c2;
+ fprintf(stdout, " %c",c);
+ }
+}