// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright 1993 - 1998 Microsoft Corporation. All Rights Reserved.
//
// PROGRAM: Rev.c
//
// PURPOSE: Helper functions for Reversi Sample Game
//
// FUNCTIONS:
// finalscore() - Calculate final score
// legalcheck() - Return 1 if move legal, else return 0
// makemove() - Capture enemy pieces
// score() - Calculate the value of board
// minmax() - Play human move then recursively play computer move
//
// SPECIAL INSTRUCTIONS: N/A
//
#include <windows.h>
#include <windowsx.h>
#include <process.h>
#include <stdlib.h>
#include "reversi.h"
// declarations of function in reversi.c
VOID NEAR PASCAL paintmove(BYTE b[BoardSize], INT move, INT friendly,
INT enemy);
// variable declarations
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
};
//
// 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
//
// FUNCTION: finalscore()
//
// PURPOSE: Calculate final score
//
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);
}
//
// FUNCTION: legalcheck()
//
// PURPOSE: Return 1 if move legal, 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);
}
//
// FUNCTION: makemove()
//
// PURPOSE: Capture enemy pieces
//
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;
}
}
//
// FUNCTION: score()
//
// PURPOSE: 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);
}
//
// FUNCTION: minmax()
//
// PURPOSE: Play human move then recursively play computer move
//
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;
INT count=0; // not used !
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);
}