/********************************************************************/ /* */ /* Hoser BackGammon version 1.0 */ /* */ /* Robert Pfister */ /* Copyright June,1987 all rights reserved. */ /********************************************************************/ /****************************************************************/ /* These routines do all the thinking for the computer side */ /* (read: the magic lives here) */ /****************************************************************/ /* This file contains: Eval vulnerable doom [CopyBoard] DoMove FindMove GenerateMoves Find4 Find3 Find2 Find1 */ #include "back.h" #include #define Running 1 #define Blocking 2 #define Pegging 3 #define BackGame 4 extern you_me_rec me; int Moves = 0, AvgPos = 0, LastVun = 0, list[4][2], count = 0, max = 0, GameStat = 0, MaxStat = 0; const BYTE block[26] = {-1,1,2,3,4,5,6, 8,9,10,11,12,13 ,14,15,17,21,25,27, 25,21,19,8,3,1,0}, run[26] = {-1,1,2,3,4,5,6, 15,16,17,18,19,20, 30,31,32,33,34,35, 50,51,52,53,54,55}, peg[26] = {-20,0,0,0,0,0,0 ,1,2,3,4,5,6, 30,31,32,33,34,35, 50,49,48,47,46,45,0}, back[26] = {20,40,30,20,10,5,0 ,1,2,3,4,5,6, 30,31,32,30,40,50, 50,49,48,30,20,10,0}; int doom(BYTE Board[26]) { int i, value = 0; if (LastVun == 0) return(0); /* find the "doom" factor..the possibility of getting outa being captured */ for(i = 1;i <= 10; i++) if (Board[i] < -1) value += 5; return(value); } int vulnerable(BYTE Board[26], int pos) { int i,j,k; int value = 0; int HitTable[7][7]; if ( (Board[pos]<0) || (pos == 0) || (Board[pos] >= 2) ) return 0; memset(&HitTable,0,sizeof HitTable); /* intitialize table */ for(i = 1; i <= 12; i++) /* look at all dice within 12 places */ if (pos-i >= 0) /* within the board */ if (Board[pos-i] < 0) /* there exists a piece at that place */ if (valid(Board,pos,pos-i,i)) { /* can capture legally */ if (i <= 6) /* find hits for one die */ for(j = 1; j <= 6; j++) { HitTable[i][j] = 1; HitTable[j][i] = 1; } for (j = 1;j < i; j++) { /* figure out combinations */ k = i-j; /* first die is j, second is k */ /* check legality of the intermediate place*/ if (valid (Board,pos,pos-j,j)) { HitTable[k][j] = 1; HitTable[j][k] = 1; } if (valid (Board,pos,pos-k,k)) { HitTable[k][j] = 1; HitTable[j][k] = 1; } } } /* end if valid (board,position) */ for(i = 1;i <= 6; i++) /* find how many hits in that table */ for(j = 1;j <= 6; j++) if (HitTable[i][j] == 1) value++; LastVun = value; return(value); } /* end of vulnerable */ int Eval(BYTE Board[26]) { int i; int num = 0, value = 0, me,you; int Msum = 0, Ysum = 0; /* see who is ahead */ for(i = 0; i <=24; i++) if (Board[i] > 0) Msum += (25 - i) * Board[i]; for(i = 1; i <= 25; i++) if (Board[i] < 0) Ysum -= i * Board[i]; for (i = 0; (i <= 24) && (Board[i] <= 0); i++); /* first occurence of me */ me = i; for (i = 25; (i >= 1) && (Board[i] >= 0); i--); /* first occurence of you */ you = i; GameStat = BackGame;/* default case */ if (Ysum > Msum+10) GameStat = Running;/* if closer to winning than them */ if (you > 18) GameStat = Blocking;/* if an opponent is within the bounds */ if (me > you) GameStat = Pegging; /* if complete separation */ for(i = 0; i <= 24; i++) { if (Board[i] > 0) { num += Board[i]; switch(GameStat) { case BackGame: value += back[i] * Board[i]; if (i < 18) value += 3 * vulnerable(Board,i); break; case Pegging: value += peg[i] * Board[i]; break; case Blocking: value += block[i] * Board[i]; value -= 4 * vulnerable(Board,i); value -= 6 * doom(Board); break; case Running: value += run[i] * Board[i]; value -= 6 * vulnerable(Board,i); value -= 6 * doom(Board); break; } /* end cases */ } /* end if */ } /* end for */ /* add points for taking men off...more if no chance of being taken */ if (GameStat == Pegging) value += (15-num) * 300; else value += (15-num) * 75; switch(GameStat) { case BackGame: num = 0; for(i = 0; i <= 6; i++) if ((Board[i] > 0) && (you > i)) num++; value += 100 * num; num = 0; for(i = 15; i <= 21; i++) if (Board[i] > 0) num += Board[i]; value += 30 * num; value -= 100 * Board[25]; num = 0; for(i = 17; i <= 23; i++) if (Board[i] >= 2) num++; value += (num * 300); break; /* if blocking game, check the block length...add points for more */ case Blocking: num = 0; for(i = 14; i <= 22; i++) { if (Board[i] >= 2) num++; if ((you > i) && (Board[i] >= 2)) num++; } value += (num * 400); num = 0; for(i = 0; i <= 17; i++) if (Board[i] > 0) num += (Board[i] * (18-i) * (18-i)); value -= num * 2/3; break; case Pegging: case Running: num = 0; for(i = 0; i <= 17; i++) if (Board[i] > 0) num++; value -= 10 * num; num = 0; for(i = 0; i <= 17; i++) if (Board[i] > 0) num += (Board[i] * (26-i) * (26-i)); value -= num; break; } return(value); } /* copy board 1 to board 2 */ #define CopyBoard(b1, b2) memcpy(b2,b1,sizeof_board) void DoMove(BYTE Board[26], BYTE Dice[4]) { int j; AvgPos += count; /* don't do anything if nothing to be done */ if (count == 0) { DoMenuStrip("Can't move from this position!!"); me.wasted += Dice[0] + Dice[1] + Dice[2] + Dice[3]; } else { PutMoveNumber(count); /* show move */ for(j = 0; j <= 3; j++) if (list[j][0] != -1) { BlinkPiece(Board,list[j][0]); update(Board,list[j][0], list[j][1] ,1); PutSpike( list[j][0],Board[list[j][0]] ); if ((list[j][1] > 0) && (list[j][1] < 25)) /******/ BlinkPiece(Board,list[j][1]); if (list[j][0] == 0) me.wasted += list[j][1]; } else me.wasted += Dice[j]; /* touch up the bars */ PutSpike(0 ,Board[ 0]); PutSpike(25,Board[25]); } } void FindMove(BYTE Board[26],BYTE Dice[4], int i1, int i2, int i3,int i4) { int j; if ((count<50)||(10 *(count/10) == count)) PutMoveNumber(count); j = Eval(Board); if ((count == 1) || (j > max)) { max = j; MaxStat = GameStat; list[0][0] = i1; list[0][1] = i1 + Dice[0]; list[1][0] = i2; list[1][1] = i2 + Dice[1]; list[2][0] = i3; list[2][1] = i3 + Dice[2]; list[3][0] = i4; list[3][1] = i4 + Dice[3]; } } void Find1(BYTE Board[26], BYTE Dice[4]) { int i1,i2; BYTE Board1[26], Dice2[4]; for (i2 = 0;i2 <= 1; i2++) { Dice2[0] = Dice[i2]; Dice2[1] = 0; Dice2[2] = 0; Dice2[3] = 0; for (i1 = 0;i1 <= 24; i1++) if (Board[i1] > 0) if (valid(Board, i1, i1 + Dice[i2], Dice[i2])) { count++; CopyBoard(Board,Board1); update(Board1,i1,i1+Dice[i2],1); FindMove(Board1,Dice2,i1,-1,-1,-1); } } } /* end of find1 */ void Find2(BYTE Board[26], BYTE Dice[4]) { int i1, i2; BYTE Board1[26], Board2[26]; for (i1 = 0;i1 <= 24; i1++) { if (Board[i1] > 0) if (valid(Board,i1,i1+Dice[0],Dice[0])) { CopyBoard(Board,Board1); update(Board1,i1,i1+Dice[0],1); for (i2 = 0;i2 <= 24; i2++) { if (Board1[i2] > 0) if (valid(Board1,i2,i2+Dice[1],Dice[1])) { count++; CopyBoard(Board1,Board2); update(Board2,i2,i2+Dice[1],1); FindMove(Board2,Dice,i1,i2,-1,-1); } /* end valid Dice[1] */ } /* end for i2 */ } /* end if Valid Dice[0] */ } /* end for i1 */ }/* end find2 */ void Find3(BYTE Board[26], BYTE Dice[4]) { int i1,i2,i3; BYTE Board1[26], Board2[26], Board3[26]; for (i1 = 0;i1 <= 24; i1++) { if (Board[i1] > 0) if (valid(Board,i1,i1+Dice[0],Dice[0])) { CopyBoard(Board,Board1); update(Board1,i1,i1+Dice[0],1); for (i2 = 0;i2 <= 24; i2++) { if (Board1[i2] > 0) if (valid(Board1,i2,i2+Dice[1],Dice[1])) { CopyBoard(Board1,Board2); update(Board2,i2,i2+Dice[1],1); for (i3 = 0;i3 <= 24; i3++) { if (Board2[i3] > 0) if (valid(Board2,i3,i3+Dice[2],Dice[2])) { count++; CopyBoard(Board2,Board3); update(Board3,i3,i3+Dice[2],1); FindMove(Board3,Dice,i1,i2,i3,-1); } /* end valid Dice[2] */ } /* end for i3 */ } /* end valid Dice[1] */ } /* end for i2 */ } /* end if Valid Dice[0] */ } /* end for i1 */ } /* end of Find3 */ void Find4(BYTE Board[26], BYTE Dice[4]) { int i1, i2, i3, i4; BYTE Board1[26], Board2[26], Board3[26], Board4[26]; for (i1 = 0;i1 <= 24; i1++) { if (Board[i1] > 0) if (valid(Board,i1,i1+Dice[0],Dice[0])) { CopyBoard(Board,Board1); update(Board1,i1,i1+Dice[0],1); for (i2 = 0;i2 <= 24; i2++) { if (Board1[i2] > 0) if (valid(Board1,i2,i2+Dice[1],Dice[1])) { CopyBoard(Board1,Board2); update(Board2,i2,i2+Dice[1],1); for (i3 = 0;i3 <= 24; i3++) { if (Board2[i3] > 0) if (valid(Board2,i3,i3+Dice[2],Dice[2])) { CopyBoard(Board2,Board3); update(Board3,i3,i3+Dice[2],1); for (i4 = 0;i4 <= 24; i4++) { if (Board3[i4] > 0) if (valid(Board3,i4,i4+Dice[3],Dice[3])) { count++; CopyBoard(Board3,Board4); update(Board4,i4,i4+Dice[3],1); FindMove(Board4,Dice,i1,i2,i3,i4); } } /* end for i4 */ } /* end valid Dice[2] */ } /* end for i3 */ } /* end valid Dice[1] */ } /* end for i2 */ } /* end if Valid Dice[0] */ } /* end for i1 */ } /* end of Find4 */ void GenerateMoves(BYTE Board[26], BYTE Dice[4]) { BYTE Dice2[4]; count = 0; PutMoveNumber(count); /* check for doubles rolled */ if (Dice[2] != 0) { Find4(Board,Dice); if (count != 0) return; me.incomplete++; Find3(Board,Dice); if (count != 0) return; Find2(Board,Dice); if (count != 0) return; } else { Find2(Board,Dice); Dice2[0] = Dice[1]; Dice2[1] = Dice[0]; Dice2[2] = Dice[2]; Dice2[3] = Dice[3]; Find2(Board,Dice2); if (count != 0) return; me.incomplete++; } Find1(Board,Dice); } /* end of generate */