📄 talk.cpp
字号:
// ObjectWindows - (C) Copyright 1992 by Borland International
#include <windows.h>
#include <fstream.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <dos.h>
#include <time.h>
#include <ctype.h>
#include "wchess.h"
#include "wcdefs.h"
#include "externs.h"
/*
* Global declarations
*/
char *INIFile = "wchess.ini";
BOOL InLibrary; // True if program is in the opening library
BOOL MultiMove, // True if multimove mode
AutoPlay, // True if AutoPlay mode
SingleStep; // Single Step mode, used for debugging purposes
LEVELTYPE Level;
double AverageTime = 5.0;
PIECETYPE Pieces[8] = { rook, knight, bishop, queen,
king, bishop, knight, rook};
BYTE MaxLevel;
BOOL Turned;
BOOL UseLib;
LIBTYPE Openings;
COLORTYPE ProgramColor;
int MoveNo;
int PVTable[2][7][0x78];
MOVETYPE PlayerMove;
BOOL Logging;
NODEVAL Nodes; // Number of analysed nodes
CLOCKTYPE ChessClock;
extern int LegalMoves;
LINETYPE HintLine; /* suggested hint line */
MAXTYPE HintEvalu; /* Evaluation for hintline */
enum ANALYSISCONTROL {Start, Return, Continue};
int OpCount, LibNo;
static DEPTHTYPE LibDepth;
static BOOL Found;
static DEPTHTYPE dep;
ofstream *OutputFile;
typedef enum {readmove, checkmove, gamemove} CONTROLVAR;
static CONTROLVAR Control;
void InsertPiece(PIECETYPE p, COLORTYPE c, SQUARETYPE sq)
{
Board[sq].piece = p;
Board[sq].color = c;
}
void ClearPVTable()
{
COLORTYPE color;
PIECETYPE piece;
SQUARETYPE square;
for (color = white; color <= black; ((int)color)++)
for (piece = king; piece <= pawn; ((int)piece)++)
for (square = 0; square <= 0x77; square++)
PVTable[color][piece][square] = 0;
}
void ResetGame()
{
ClearBoard();
Running = FALSE;
for (int i = 0; i < 8; i++)
{
InsertPiece(Pieces[i], white, i);
InsertPiece(pawn, white, i + 0x10);
InsertPiece(pawn, black, i + 0x60);
InsertPiece(Pieces[i], black, i + 0x70);
}
CalcPieceTab();
Player = white;
ClearDisplay();
InitDisplay();
ColorToPlay(Player);
Opponent = black;
}
void NewGame()
{
SingleStep = InLibrary = FALSE;
GameOver = FALSE;
ResetGame();
PrintCurLevel();
ResetMoves();
if (!*Openings)
UseLib = 0;
else
UseLib = 200;
MovTab[-1].content = king;
InitChessTime();
ProgramColor = white;
MoveNo = 0;
ClearHint();
ClearPVTable();
PlayerMove = ZeroMove;
if (Logging && !AutoPlay)
*OutputFile << "\n No Player Program Hint Value Level Nodes Time\n";
InitNode(&Nodes);
ChessClock.totaltime = 0.0;
Control = (AutoPlay) ? gamemove : readmove;
}
void ResetNewPos(void)
{
ResetMoves();
CalcPieceTab();
UseLib = FALSE;
Running = FALSE;
ClearHint();
}
void ResetOpening()
{
const char *libfilename = "opening.lib";
ifstream fin(libfilename, ios::in | ios::binary);
if (!fin)
{
MessageBox(NULL,"Cannot find Openings Library", "Error",
MB_ICONHAND | MB_OK);
Openings = new unsigned char;
*Openings = 0;
return;
}
Openings = new unsigned char[32000];
fin.read(Openings, 32000);
fin.close();
*Openings = 0xFF;
}
static void StartUp()
{
long color;
randomize();
Level = (LEVELTYPE)GetPrivateProfileInt("WCHESS", "Level",
(int)easygame, INIFile);
if (GetPrivateProfileString("WCHESS", "AverageTime", "5.0", buf,
80, INIFile))
sscanf(buf, "%lf", &AverageTime);
if (GetPrivateProfileString("WCHESS", "WhiteSquare", "", buf, 80, INIFile))
{
sscanf(buf, "%ld", &color);
WhiteSquareColors[0] = color & 0xffL;
WhiteSquareColors[1] = (BYTE)((color & 0xff00L) >> 8);
WhiteSquareColors[2] = (BYTE)((color & 0xff0000L) >> 16);
}
if (GetPrivateProfileString("WCHESS", "BlackSquare", "", buf, 80, INIFile))
{
sscanf(buf, "%ld", &color);
BlackSquareColors[0] = color & 0xff;
BlackSquareColors[1] = ((color & 0xff00L) >> 8);
BlackSquareColors[2] = ((color & 0xff0000L) >> 16);
}
MaxLevel = GetPrivateProfileInt("WCHESS", "MaxLevel", MAXPLY, INIFile);
SoundOn = (BOOL)GetPrivateProfileInt("WCHESS", "SoundOn", 1, INIFile);
if (!SoundOn) // defaults to checked at startup
CheckMenuItem(MainMenu, IDM_SOUND, MF_UNCHECKED);
CalcAttackTab();
MultiMove = FALSE;
AutoPlay = FALSE;
Turned = FALSE;
ResetOpening();
OutputFile = new ofstream("Chess.log");
if (!OutputFile)
{
MessageBox(NULL, "Unable to open log file.\nLogging disabled", "OWL Chess", MB_OK | MB_ICONEXCLAMATION);
Logging = FALSE;
}
else
{
*OutputFile << endl;
*OutputFile << " OWL CHESS by Borland International\n";
*OutputFile << " ==================================\n" << endl;
}
}
const UNPLAYMARK = 0x3f;
/*
* Sets libno to the previous move in the block
*/
void PreviousLibNo(void)
{
int n;
n = 0;
do
{
LibNo--;
if (Openings[LibNo] >= 128) n++;
if (Openings[LibNo] & 64) n--;
} while (n);
}
/*
* Set libno to the first move in the block
*/
void FirstLibNo()
{
while (!(Openings[LibNo - 1] & 64))
PreviousLibNo();
}
/*
* set libno to the next move in the block. Unplayable
* moves are skipped if skip is set
*/
void NextLibNo(short skip)
{
int n;
if (Openings[LibNo] >= 128) FirstLibNo();
else
{
n = 0;
do
{
if (Openings[LibNo] & 64) n++;
if (Openings[LibNo] >= 128) n--;
LibNo++;
} while (n);
if (skip && (Openings[LibNo] == UNPLAYMARK))
FirstLibNo();
}
}
/*
* find the node corresponding to the correct block
*/
static void FindNode(void)
{
LibNo++;
if (Depth > LibDepth)
{
Found = TRUE;
return;
}
OpCount = -1;
InitMovGen();
do
{
OpCount++;
MovGen();
} while (Next.movpiece != empty && !EqMove(&Next, &MovTab[Depth]));
if (Next.movpiece != empty)
{
while (((Openings[LibNo] & 63) != OpCount) &&
(Openings[LibNo] < 128))
NextLibNo(0);
if ((Openings[LibNo] & 127) == 64 + OpCount)
{
MakeMove(&MovTab[Depth]);
FindNode();
TakeBackMove(&MovTab[Depth-1]);
}
}
}
/*
* Set LibNo to the block corresponding to the position
*/
void CalcLibNo(void)
{
LibNo = 0;
if (MoveNo < UseLib)
{
LibDepth = Depth;
while (MovTab[Depth].movpiece != empty)
TakeBackMove(&MovTab[Depth]);
Found = FALSE;
if (MovTab[Depth].content == king)
{
Depth++;
FindNode();
Depth--;
}
while(Depth < LibDepth)
MakeMove(&MovTab[Depth + 1]);
if (Found)
UseLib = 200;
else
{
UseLib = MoveNo;
LibNo = 0;
}
}
}
/*
* find an opening move from the library
*/
static void FindOpeningMove(void)
{
const unsigned char weight[7] = {7, 10, 12, 13, 14, 15, 16};
unsigned char cnt, r, p, countp;
r = random(16); /* calculate weighted random number in 0..16 */
p = 0;
while (r >= weight[p]) p++;
for (countp = 1; countp <= p; countp++) /* find corresponding node */
NextLibNo(1);
OpCount = Openings[LibNo] & 63; /* generate the move */
InitMovGen();
for (cnt = 0; cnt <= OpCount; cnt++)
MovGen();
/* store the move in mainline */
MainLine[0] = Next;
MainLine[1] = ZeroMove;
MainEvalu = 0;
MaxDepth = 0;
LegalMoves = 0;
InitNode(&Nodes);
}
void OutputNode(NODEVAL *nodes)
{
double nodereal;
if (!Logging)
return;
char buf[20];
nodereal = (nodes->nodebase * MAXINT) + nodes->nodeoffset;
sprintf(buf, "%12.1f", nodereal);
*OutputFile << buf;
}
static void ThinkAwhile();
void StartMove();
void ReturnAnalysis()
{
int myx;
char str[8];
char buf[40];
MovTab[0] = MainLine[0]; /* copy the MainLine to HintLine */
for (myx = 1; myx <= MAXPLY; myx++)
HintLine[myx - 1] = MainLine[myx];
dep = MAXPLY;
HintEvalu = MainEvalu;
if (MovTab[0].movpiece == empty)
{
HintLine[0] = ZeroMove; /* No possible move */
if (AutoPlay)
{
NewGame();
PrintBoard();
StartMove();
}
return;
}
// FlashMove(&MovTab[Depth+1]); /* flash and perform the move */
DoSlideMove(MovTab[Depth+1]);
EnterMove(&MovTab[Depth+1]);
if (SoundOn)
MessageBeep(0);
StoreMoves();
if (Logging && !AutoPlay)
{
sprintf(buf, "%3d. ",(MoveNo+1) / 2);
*OutputFile << buf;
strcpy(str, MoveStr(&MovTab[0]));
if ((PlayerMove.movpiece == empty) && (Opponent == white))
sprintf(buf, "%8.8s ", str);
else
sprintf(buf, "%s%8.8s",MoveStr(&PlayerMove), str);
*OutputFile << buf;
sprintf(buf, " (%s)%9.2f%3d:%2d", MoveStr(&MainLine[1]),
MainEvalu / 256.0, MaxDepth, LegalMoves);
*OutputFile << buf;
OutputNode(&Nodes);
sprintf(buf, "%8.1lf\n", ChessClock.totaltime);
*OutputFile << buf;
}
PlayerMove = ZeroMove;
ColorToPlay(Player);
if (AutoPlay)
{
if ((MoveNo >= 120) || (FiftyMoveCnt() >= 100) ||
(Repetition(0) >= 3) || (MainEvalu <= -0x880))
{
NewGame();
PrintBoard();
}
StartMove();
return;
}
if (Level != easygame && !GameOver)
ThinkAwhile();
}
/*
* Perform analysis in the opponents time of reflection.
* The program assumes that the opponent will perform the
* Hint move, and starts analysing on it for a counter move
*/
static void ThinkAwhile()
{
extern HCURSOR hArrowCursor;
SetClassWord(hWndMain, GCW_HCURSOR, WORD( hArrowCursor ));
SetCursor(hArrowCursor);
SetMenu(hWndMain, MainMenu);
if ((HintLine[0].movpiece == empty) || MultiMove)
return;
Analysis = FALSE;
Opan = TRUE;
AdjustMoves(); /* Setup surroundings as if the */
MovTab[Depth+1] = HintLine[0]; /* Opponent had performed */
MakeMove(&MovTab[Depth+1]); /* The hint move */
StoreMoves();
AdjustMoves();
Depth = 0; /* analyse until something is entered from by */
FindMove(MaxLevel); /* the user */
Depth = -1;
Opan = FALSE;
if (Analysis) /* If the Opponent did make the */
{ /* Hint move then go and */
ReturnAnalysis(); /* perform the counter move */
return;
}
TakeBackMove(&MovTab[Depth]); /* restore the surroundings */
if (GotValidMove)
{
AdjustMoves();
EnterKeyMove();
StoreMoves();
SetMenu(hWndMain, ThinkMenu);
SetClassWord(hWndMain, GCW_HCURSOR, WORD( hWaitCursor ));
SetCursor(hWaitCursor);
}
return;
}
void StartMove()
{
MSG msg;
StartAnalysis();
AdjustMoves();
CalcLibNo(); /* Try to find a move in the opening library */
Depth = 0;
if (LibNo > 0)
{
OpeningLibMsg();
InLibrary = TRUE;
FindOpeningMove();
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
if (msg.message == WM_COMMAND && msg.wParam == CM_STOP)
return;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
else
{
if (InLibrary)
{
InLibrary = FALSE;
ClearMessage();
}
FindMove(MaxLevel);
}
Depth = -1;
ReturnAnalysis();
}
void ProgramMove()
{
do
{
GotValidMove = FALSE;
ColorToPlay(Player);
StartMove();
}
while (GotValidMove);
}
void Talk()
{
StartUp();
NewGame();
}
BOOL Redo()
{
// MakeMove(&MovTab[Depth+1]);
EnterMove(&MovTab[Depth+1]);
ClearHint();
// UpdateBoard();
ClearBestLine();
ColorToPlay(Player);
if (Depth >= -1)
return FALSE; // cannot redo again
return TRUE; // can redo again
}
BOOL Undo()
{
// TakeBackMove(&MovTab[Depth]);
extern void RemoveMove(MOVETYPE *);
RemoveMove(&MovTab[Depth]);
ClearHint();
// UpdateBoard();
ClearBestLine();
ColorToPlay(Player);
if (MovTab[Depth].movpiece == empty)
return FALSE; // Can't undo anymore
return TRUE; // Can still undo
}
void QuitProgram()
{
long color;
if (Logging)
OutputFile->close();
color = RGB(WhiteSquareColors[0], WhiteSquareColors[1],
WhiteSquareColors[2]);
sprintf(buf, "%ld", color);
WritePrivateProfileString("WCHESS", "WhiteSquare", buf, INIFile);
color = RGB(BlackSquareColors[0], BlackSquareColors[1],
BlackSquareColors[2]);
sprintf(buf, "%ld", color);
WritePrivateProfileString("WCHESS", "BlackSquare", buf, INIFile);
sprintf(buf, "%d", Level);
WritePrivateProfileString("WCHESS", "Level", buf, INIFile);
sprintf(buf, "%lf", AverageTime);
WritePrivateProfileString("WCHESS", "AverageTime", buf, INIFile);
sprintf(buf, "%d", (int)MaxLevel);
WritePrivateProfileString("WCHESS", "MaxLevel", buf, INIFile);
sprintf(buf, "%d", (int)SoundOn);
WritePrivateProfileString("WCHESS", "SoundOn", buf, INIFile);
}
void FindHintMove()
{
/* If hintline is empty the get the move from the
opening library or perform a 1 - ply search */
if (HintLine[0].movpiece == empty)
{
AdjustMoves();
CalcLibNo();
Depth = 0;
if (LibNo > 0)
FindOpeningMove();
else
{
Analysis = 1;
Opan = 0;
FindMove(1);
}
Depth = -1;
HintLine[0] = MainLine[0];
HintLine[1] = ZeroMove;
HintEvalu = -MainEvalu;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -