290 lines
7.4 KiB
C
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);
|
|
}
|