#include #include #include #include #include "reversi.h" VOID NEAR PASCAL paintmove(BYTE b[BoardSize], INT move, INT friendly, INT enemy); BOOL NEAR PASCAL msgcheck(VOID); extern INT moves[61]; extern INT BestMove[max_depth+2]; extern HWND hWin; extern HDC hDisp; extern INT depth; extern INT direc[]; /* Indexes for computing scores and whether or not a player has */ /* any pieces on the board. Very order dependant. */ BYTE PieceFlags[] = { 0x00 , /* Ignore sides */ 0x00 , /* Ignore blanks */ 0x01 , /* Human has a piece */ 0x02 , /* Computer has a piece */ }; INT Scores[] = { 0, 0 }; INT humanScore = 0; INT compScroe = 0; BYTE FinalComp[] = {0, 0, -1, 1 }; /* Table for compute # computer pieces */ BYTE FinalHuman[] = {0, 0, 1, -1}; /* Table for compute # human pieces */ /* * The scoring tables are used to evaluate the board * position. The corners of the board change value * according to whether a given square is occupied or * not. This can be done dynamically, saving ~ 1K * worth of data space but costing an as of yet * undetermined performance hit. */ #define B11 11 /* Offsets to particular squares */ #define B18 18 #define B81 81 #define B88 88 #define maskb11 0x08 /* Masks used for indexing into Scoring tables. */ #define maskb18 0x04 #define maskb81 0x02 #define maskb88 0x01 INT NEAR PASCAL finalscore( BYTE b[], BYTE friendly, BYTE enemy) { INT i; INT count=0; for (i=11 ; i<=88 ; i++) { if (b[i] == friendly) count++; else if (b[i] == enemy) count--; } if (count > 0) return(win + count); else if (count < 0) return(loss + count); else return(0); } INT NEAR PASCAL legalcheck( BYTE b[], INT move, BYTE friendly, BYTE enemy) { INT sq,d; INT *p; if (b[move] == empty) { p=direc; while ((d = *p++) != 0) { sq=move; if (b[sq += d] == enemy) { while(b[sq += d] == enemy) ; if (b[sq] == friendly) return(1); } } } return(0); } VOID NEAR PASCAL makemove( BYTE b[], INT move, BYTE friendly, BYTE enemy) { INT sq,d; INT *p; if (move != PASS) { p=direc; while ((d = *p++) != 0) { sq=move; if (b[sq += d] == enemy) { while(b[sq += d] == enemy) ; if (b[sq] == friendly) while(b[sq -= d] == enemy) b[sq]=friendly; } } b[move]=friendly; } } /* calculate the value of board */ INT NEAR PASCAL score( BYTE b[], BYTE friendly, BYTE enemy) { INT *pvalue; BYTE *pb; INT fpoints=0; INT epoints=0; INT ecount=0; BYTE bv; INT v,b11,b18,b81,b88; static INT value[79] = { 99, -8, 8, 6, 6, 8, -8, 99,000, 000, -8,-24, -4, -3, -3, -4,-24, -8,000, 000, 8, -4, 7, 4, 4, 7, -4, 8,000, 000, 6, -3, 4, 0, 0, 4, -3, 6,000, 000, 6, -3, 4, 0, 0, 4, -3, 6,000, 000, 8, -4, 7, 4, 4, 7, -4, 8,000, 000, -8,-24, -4, -3, -3, -4,-24, -8,000, 000, 99, -8, 8, 6, 6, 8, -8, 99,infin}; static INT value2[79]= { 99, -8, 8, 6, 6, 8, -8, 99,000, 000, -8,-24, 0, 1, 1, 0,-24, -8,000, 000, 8, 0, 7, 4, 4, 7, 0, 8,000, 000, 6, 1, 4, 1, 1, 4, 1, 6,000, 000, 6, 1, 4, 1, 1, 4, 1, 6,000, 000, 8, 0, 7, 4, 4, 7, 0, 8,000, 000, -8,-24, 0, 1, 1, 1,-24, -8,000, 000, 99, -8, 8, 6, 6, 8, -8, 99,infin}; pb = &b[11]; b11 = *pb; b18 = b[18]; b81 = b[81]; b88 = b[88]; if ((b11 != empty) || (b18 != empty) || (b81 != empty) || (b88 != empty)) { pvalue = value2; if (b11 == empty) { value2[12-11] = -8; value2[21-11] = -8; value2[22-11] = -24; } else { value2[12-11] = 12; value2[21-11] = 12; value2[22-11] = 8; } if (b18 == empty) { value2[17-11] = -8; value2[28-11] = -8; value2[27-11] = -24; } else { value2[17-11] = 12; value2[28-11] = 12; value2[27-11] = 8; } if (b81 == empty) { value2[82-11] = -8; value2[71-11] = -8; value2[72-11] = -24; } else { value2[82-11] = 12; value2[71-11] = 12; value2[72-11] = 8; } if (b88 == empty) { value2[87-11] = -8; value2[78-11] = -8; value2[77-11] = -24; } else { value2[87-11] = 12; value2[78-11] = 12; value2[77-11] = 8; } } else { pvalue = value; } while((v=*pvalue++) != infin) { bv = *pb++; if (bv == friendly) fpoints += v; else if (bv == enemy) { epoints += v; ecount++; } } if (!ecount) /* any enemy pieces on the board? */ return(win); /* if not, we just won! */ else return(fpoints-epoints); } INT NEAR PASCAL minmax( BYTE b[max_depth + 2][100], INT move, BYTE friendly, BYTE enemy, INT ply, INT vmin, INT vmax) { BYTE *pCurrent, *pPrevious, *pSource, *pDest; INT *pMoves; INT *pBestMove; INT i; INT sq, value, cur_move; pPrevious = &b[ply][0]; pCurrent = &b[ply+1][0]; pSource = &b[ply][11]; pDest = &b[ply+1][11]; for (i=11 ; i<=88 ; i++) *pDest++=*pSource++; pBestMove = &BestMove[ply]; if (move == PASS) { if (ply == depth) { pMoves = moves; while((sq = *pMoves++) != 0) { if (legalcheck(pCurrent,sq,enemy,friendly)) return(score(pCurrent,friendly,enemy)); } return(finalscore(pCurrent,friendly,enemy)); } } else { if (ply == 0) { hDisp = GetDC(hWin); paintmove(pCurrent,move,friendly,enemy); ReleaseDC(hWin, hDisp); } else { makemove(pCurrent,move,friendly,enemy); if (ply == depth) return(score(pCurrent,friendly,enemy)); } } pMoves = moves; cur_move = PASS; *pBestMove = PASS; while((sq = *pMoves++) != 0) { if (legalcheck(pCurrent,sq,enemy,friendly)) { cur_move = sq; value = minmax(b,cur_move,enemy,friendly,ply+1,-vmax,-vmin); if (value > vmin) { vmin = value; *pBestMove = cur_move; if (value >= vmax) goto cutoff; /* alpha-beta cutoff */ } } } if (cur_move == PASS) { if (move == PASS) /* two passes in a row mean game is over */ return(finalscore(pCurrent,friendly,enemy)); else { value = minmax(b,PASS,enemy,friendly,ply+1,-vmax,-vmin); if (value > vmin) vmin = value; } } cutoff: return(-vmin); }