windows-nt/Source/XPSP1/NT/shell/osshell/games/reversi/rev.c
2020-09-26 16:20:57 +08:00

290 lines
7.4 KiB
C

#include <windows.h>
#include <port1632.h>
#include <process.h>
#include <stdlib.h>
#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);
}