///////////////////////////////////////////////////////////////////////////// // // EpdProcessor.cpp : implementation for EPD Processing classes // // Written by Thomas F. Mooney, III (tfm3@teleproc.com) // Copyright © 1999. // // This code may be used in compiled form in any way you desire. This // file may be redistributed unmodified by any means PROVIDING it is // not sold for profit without the authors written consent, and // providing that this notice and the authors name is included. If // the source code in this file is used in any commercial application // then acknowledgement must be made to the author of this file // (in whatever form you wish). // // This file is provided "as is" with no expressed or implied warranty. // The author accepts no liability if it causes any damage to your // computer, data, etc. // // Please report any bugs/anomalies/suggestions to the author via the // e-mail address listed above. // ///////////////////////////////////////////////////////////////////////////// static char Copyright[] = "Copyright © 1999 - TeleProcess Management, Inc."; #include "EpdProcessor.h" #include // The EpdProcessor constructor sets all member variables // to their correct initial state. EpdProcessor::EpdProcessor() : m_Board(), m_bGenerateOpcodes(false), m_bOpcode_hm(true), m_bOpcode_hmvc(true), m_bOpcode_fmvn(true), m_bEpdValid(false), m_nPvValid(EPD_STATUS_FAILURE), m_nSanValid(EPD_STATUS_FAILURE), m_EpdErrorMsg("No Epd Provided"), m_PvErrorMsg("No PV Provided"), m_SanErrorMsg("No SAN Move Provided"), m_bEpCapturePossible(false), m_PV(""), m_bCheckmate(false), m_bStalemate(false) { m_EpdVector.clear(); m_EpdBinaryVector.clear(); m_EpdList.clear(); m_EpdBinaryList.clear(); m_SanList.clear(); } // The ~EpdProcessor destructor is a stub function that does // nothing. EpdProcessor::~EpdProcessor() { } // SetEpd takes a user supplied position, parses it into its // constituent parts and does extensive error checking to // assure that the supplied position is valid. bool EpdProcessor::SetEpd(EPD EpdPosition) { m_bEpdValid = true; // assume valid m_EpdErrorMsg = ""; // Reset everything dependent on a new EPD m_nPvValid = EPD_STATUS_FAILURE; m_nSanValid = EPD_STATUS_FAILURE; m_PvErrorMsg = "No PV Provided"; m_PV = ""; m_bEpCapturePossible = false; m_SanErrorMsg = "No SAN Move Provided"; m_EpdVector.clear(); m_EpdBinaryVector.clear(); m_EpdList.clear(); m_EpdBinaryList.clear(); m_SanList.clear(); m_bCheckmate = false; m_bStalemate = false; // Get ready to parse supplied EPD EPD EpdData; char format[32]; std::string CastleAvailability; std::string EnPassantTarget; EpdBinary EpdBinaryData; char* pPiecePlacement = NULL; char* pActiveColor = NULL; char* pCastleAvailability = NULL; char* pEnPassantTarget = NULL; char* pOperator = NULL; char* pHalfMoveClock = NULL; char* pFullMoveNumber = NULL; char pszWhiteSpace[] = " \t\v\r\n"; char pszSemiColon[] = " ;"; char HalfMoveClockLiteral[] = "hmvc"; char FullMoveNumberLiteral[] = "fmvn"; // Parse supplied EPD, check for missing pieces as we go pPiecePlacement = strtok(EpdPosition.begin(), pszWhiteSpace); if (pPiecePlacement != NULL) { m_PiecePlacement = pPiecePlacement; pActiveColor = strtok(NULL, pszWhiteSpace); if (pActiveColor != NULL) { pCastleAvailability = strtok(NULL, pszWhiteSpace); if (pCastleAvailability != NULL) { m_CastleAvailability = pCastleAvailability; pEnPassantTarget = strtok(NULL, pszWhiteSpace); if (pEnPassantTarget != NULL) { m_EnPassantTarget = pEnPassantTarget; pOperator = strtok(NULL, pszSemiColon); while (pOperator != NULL) { if (strncmp(pOperator, HalfMoveClockLiteral, sizeof(HalfMoveClockLiteral) - 1) == 0) { pHalfMoveClock = strtok(NULL, pszSemiColon); } else if (strncmp(pOperator, FullMoveNumberLiteral, sizeof(FullMoveNumberLiteral) - 1) == 0) { pFullMoveNumber = strtok(NULL, pszSemiColon); } pOperator = strtok(NULL, pszSemiColon); } } else { m_bEpdValid = false; m_EpdErrorMsg = "Missing EPD en passant target square"; } } else { m_bEpdValid = false; m_EpdErrorMsg = "Missing EPD castle availability"; } } else { m_bEpdValid = false; m_EpdErrorMsg = "Missing EPD active color"; } } else { m_bEpdValid = false; m_EpdErrorMsg = "Missing EPD piece placement data"; } // Change empty fields to null strings if (m_CastleAvailability == "-") { m_CastleAvailability = ""; } if (m_EnPassantTarget == "-") { m_EnPassantTarget = ""; } // Supply defaults where needed if (pHalfMoveClock != NULL) { m_nHalfMoveClock = atoi(pHalfMoveClock); } else { m_nHalfMoveClock = 0; } if (pFullMoveNumber != NULL) { m_nFullMoveNumber = atoi(pFullMoveNumber); } else { m_nFullMoveNumber = 1; } // Perform additional validation of position if (m_bEpdValid) { ValidatePiecePlacement(); } if (m_bEpdValid) { ValidateActiveColor(pActiveColor); } if (m_bEpdValid) { ValidateCastleAvailability(); } if (m_bEpdValid) { ValidateEnPassantTarget(); } if (m_bEpdValid) { m_Board.SetPiecePlacement(m_PiecePlacement); m_Board.SetWhiteToMove(m_bWhiteToMove); m_Board.SetCastleAvailability(m_CastleAvailability); m_Board.SetEnPassantTarget(m_EnPassantTarget); m_bEpdValid = m_Board.ValidateCheckStatus(); if (m_bEpdValid) { m_bEpdValid = m_Board.ValidateEnPassantStatus(); if (m_bEpdValid) { m_bEpdValid = m_Board.ValidatePawnPlacement(); if (m_bEpdValid) { m_bEpdValid = m_Board.ValidateCastleAvailability(); if (!m_bEpdValid) { m_EpdErrorMsg = "Invalid EPD castle availability"; } } else { m_EpdErrorMsg = "Invalid pawn placement"; } } else { m_EpdErrorMsg = "Invalid en passant target square"; } } else { m_EpdErrorMsg = "Invalid check status, player has moved into check"; } } if (m_bEpdValid) { // Build EPD from the original supplied EPD EpdData = ""; EpdData += m_Board.GetPiecePlacement(); if (m_Board.IsWhiteToMove()) { EpdData += " w "; } else { EpdData += " b "; } CastleAvailability = m_Board.GetCastleAvailability(); if (CastleAvailability == "") { CastleAvailability = "-"; } EpdData += CastleAvailability; EpdData += " "; EnPassantTarget = m_Board.GetEnPassantTarget(); if (EnPassantTarget == "") { EnPassantTarget = "-"; } EpdData += EnPassantTarget; if (m_bGenerateOpcodes) { if (m_bOpcode_fmvn) { sprintf(format, " fmvn %d;", m_Board.GetFullMoveNumber()); EpdData += format; } if (m_bOpcode_hmvc) { sprintf(format, " hmvc %d;", m_Board.GetHalfMoveClock()); EpdData += format; } } m_EpdVector.push_back(EpdData); m_bEpCapturePossible = m_Board.IsEnPassantCapturePossible(); EpdBinaryData = m_Board.GetBinaryPosition(); m_EpdBinaryVector.push_back(EpdBinaryData); } // indicate to user whether the supplied EPD was valid return m_bEpdValid; } // SetEpd takes a user supplied compressed EPD, and does // extensive error checking to assure that the supplied // position is valid. bool EpdProcessor::SetEpdBinary(EpdBinary EpdPosition) { return SetEpd(EpdPosition.GetEpd()); } // GetEpdError indicates to user the nature of the error // in the EPD they supplied std::string EpdProcessor::GetEpdError() { return m_EpdErrorMsg; } // SetPv takes a PV (Predicted Variation), parses it into // its constituent moves and process the moves against the // previously supplied position int EpdProcessor::SetPv(PV SanMoves) { m_nPvValid = EPD_STATUS_SUCCESS; // assume valid m_PvErrorMsg = ""; // Reset everything dependent upon a new PV m_SanList.clear(); m_PV = ""; // Get ready to parse into individual moves char* pMove; char pszWhiteSpace[] = " \t\v\r\n"; if (m_bEpdValid) // only process if we already have a // valid EPD { if (SanMoves.size() > 0) { pMove = strtok(SanMoves.begin(), pszWhiteSpace); while (pMove != NULL) { m_SanList.push_back(pMove); pMove = strtok(NULL, pszWhiteSpace); } } GenerateEpdVector(); // Generate EPDs from PV } else { m_nPvValid = EPD_STATUS_FAILURE; m_PvErrorMsg = "No valid EPD available"; } // indicate to user the outcome of their PV return m_nPvValid; } // GetPvError indicates to user the nature of the error // in the PV they supplied std::string EpdProcessor::GetPvError() { return m_PvErrorMsg; } // GetPv returns the PV to the user after it has been processed. // Minor changes may have been made PV EpdProcessor::GetPv() { return m_PV; } // GetEpd returns a single EPD that has been generated via // calls to SetEpd() and SetPv. The desired EPD is indicated // by supplying the number of half-moves to apply to the // original EPD. EPD EpdProcessor::GetEpd(int HalfMoveCount) { if ((HalfMoveCount < m_EpdVector.size()) && // check for proper (HalfMoveCount >= 0)) // range { return m_EpdVector[HalfMoveCount]; } else { return ""; } } // GetEpdBinary returns a single compressed EPD that has been // generated via calls to SetEpd() and SetPv(). The desired // compressed EPD is indicated by supplying the number of // half-moves to apply to the original EPD. EpdBinary EpdProcessor::GetEpdBinary(int HalfMoveCount) { if ((HalfMoveCount < m_EpdBinaryVector.size()) && // check for proper (HalfMoveCount >= 0)) // range { return m_EpdBinaryVector[HalfMoveCount]; } else { return EpdBinary(); } } // GetEpdVector returns the entire collection of EPDs generated // via calls to SetEpd() and SetPv(). The first EPD is the // supplied EPD, the next has the first move of the PV applied.... EPD_VECTOR EpdProcessor::GetEpdVector() { return m_EpdVector; } // GetEpdVector returns the entire collection of compressed // EPDs generated via calls to SetEpd() and SetPv(). The first // compressed EPD is the supplied EPD, the next has the first // move of the PV applied.... EPD_BINARY_VECTOR EpdProcessor::GetEpdBinaryVector() { return m_EpdBinaryVector; } // GetLegalEpdList() returns a collection of all of the EPDs // that may be reached by making one move from the position // supplied in SetEpd(). EPD_LIST EpdProcessor::GetLegalEpdList() { GenerateLegalEpds(); // Generate list, standard and binary // Return the collection to the user. return m_EpdList; } // GetLegalEpdList() returns a collection of all of the EPDs // that may be reached by making one move from the position // supplied in SetEpd(). The EPDs are in compressed format. EPD_BINARY_LIST EpdProcessor::GetLegalEpdBinaryList() { GenerateLegalEpds(); // Generate list, standard and binary // Return the collection to the user. return m_EpdBinaryList; } // GetLegalSanList() returns a collection of all of the moved // that may be played from the position supplied in SetEpd(). // Each of the moves are in SAN notation. SAN_LIST EpdProcessor::GetLegalSanList() { MOVE_LIST LegalMoveList; MOVE_LIST::iterator pMove; ChessMove Move; SAN SanMove; int nColor; bool bKingChecked; // Reset everything related to the new collection m_bStalemate = false; m_bCheckmate = false; m_SanList.clear(); if (m_bEpdValid) // only if the user supplied a valid EPD { // Set up the board as the user specified m_Board.SetPiecePlacement(m_PiecePlacement); m_Board.SetWhiteToMove(m_bWhiteToMove); m_Board.SetCastleAvailability(m_CastleAvailability); m_Board.SetEnPassantTarget(m_EnPassantTarget); m_Board.SetHalfMoveClock(m_nHalfMoveClock); m_Board.SetFullMoveNumber(m_nFullMoveNumber); if (m_bWhiteToMove) { nColor = WHITE; } else { nColor = BLACK; } // Is player to move in check? bKingChecked = m_Board.IsKingChecked(nColor); // Get all the moves (include EPD data) that may be played LegalMoveList = m_Board.GetLegalMoveList(true); if (LegalMoveList.size() == 0) // if there are no moves { if (bKingChecked) // determine if we were already in check { m_bCheckmate = true; // Yes - it's checkmate } else { m_bStalemate = true; // No - it's stalemate } } // Sort the moves LegalMoveList.sort(); // Build a list of moves in SAN notation pMove = LegalMoveList.begin(); while (pMove != LegalMoveList.end()) { Move = *pMove; SanMove = Move.CreateSAN(); m_SanList.push_back(SanMove); pMove++; } } // Return the collection to the user. return m_SanList; } // IsCheckmate() indicates to the user if the position they've // supplied is checkmate. bool EpdProcessor::IsCheckmate() { return m_bCheckmate; } // IsStalemate() indicates to the user if the position they've // supplied is stalemate. bool EpdProcessor::IsStalemate() { return m_bStalemate; } // IsMoveLegal() determines whether a single move supplied by // the user is legal to play from the position previously // supplied by the user with SetEpd(). int EpdProcessor::IsMoveLegal(SAN& San) { ChessMove Move; // Reset everything related to validating the move. m_nSanValid = EPD_STATUS_SUCCESS; // assume valid m_SanErrorMsg = ""; if (m_bEpdValid) // only if the user supplied a valid EPD { // Set up the board as the user specified m_Board.SetPiecePlacement(m_PiecePlacement); m_Board.SetWhiteToMove(m_bWhiteToMove); m_Board.SetCastleAvailability(m_CastleAvailability); m_Board.SetEnPassantTarget(m_EnPassantTarget); m_Board.SetHalfMoveClock(m_nHalfMoveClock); m_Board.SetFullMoveNumber(m_nFullMoveNumber); // Parse the supplied move Move.ParseSAN(San); Move.SetLastInPv(true); // Only move, analyze checkmate if (Move.IsLegalMove()) // Did it parse okay? { m_Board.Move(Move); // Yes, make the move } else { m_nSanValid = EPD_STATUS_FAILURE; // No, inidicate error m_SanErrorMsg = Move.GetErrorMsg(); } if (Move.IsLegalMove()) // Did it play okay? { // Yes, carry on if (Move.IsMoveAltered()) // Did we alter it? { m_nSanValid = EPD_STATUS_WARNING; // Indicate change San = Move.CreateSAN(); // and return new move } } else { m_nSanValid = EPD_STATUS_FAILURE; // No, indicate error m_SanErrorMsg = Move.GetErrorMsg(); } } else { m_nSanValid = EPD_STATUS_FAILURE; m_SanErrorMsg = "No valid EPD available"; } // Indicate whether move was legal return m_nSanValid; } // GetSanError indicates to user the nature of the error // in the move they supplied std::string EpdProcessor::GetSanError() { return m_SanErrorMsg; } bool EpdProcessor::IsEnPassantCapturePossible() { return m_bEpCapturePossible; } // GenerateOutputOpcodes controls whether opcodes are supplied in // the EPDs we generate void EpdProcessor::GenerateOutputOpcodes(bool Generate) { m_bGenerateOpcodes = Generate; } // SetOutputOpcodeTypes controls the types of opcode we supply in // the EPDs we generate void EpdProcessor::SetOutputOpcodeTypes(bool hm, bool hmvc, bool fmvn) { m_bOpcode_hm = hm; m_bOpcode_hmvc = hmvc; m_bOpcode_fmvn = fmvn; } // ValidatePiecePlacement does extensive error checking on the piece // placement data in the EPD the user has supplied. We validate that // there are eight ranks, each rank eight files wide, valid codes of // the chess men, no more than eight pawns per side, no more than // sixteen pawns and pieces per side, one and only one king per side. void EpdProcessor::ValidatePiecePlacement() { std::string PiecePlacement = m_PiecePlacement; std::list RankList; std::list::iterator pRank; std::string Rank; char pszSlash[] = "/"; char* pParseRank = NULL; int nIndex; int nSize; char cRankItem; int nRankWidth; int nEmptySquares; int nBlackPawns = 0; int nBlackPieces = 0; int nBlackKings = 0; int nWhitePawns = 0; int nWhitePieces = 0; int nWhiteKings = 0; pParseRank = strtok(PiecePlacement.begin(), pszSlash); while (pParseRank != NULL) { RankList.push_back(pParseRank); pParseRank = strtok(NULL, pszSlash); } if (RankList.size() == 8) { pRank = RankList.begin(); while (pRank != RankList.end()) { Rank = *pRank; nSize = Rank.size(); nIndex = 0; nRankWidth = 0; while (nIndex < nSize) { cRankItem = Rank[nIndex]; if ((cRankItem >= '1') && (cRankItem <= '8')) { nEmptySquares = cRankItem - '0'; nRankWidth += nEmptySquares; } else if (cRankItem == 'p') { nBlackPawns++; nRankWidth++; } else if (cRankItem == 'P') { nWhitePawns++; nRankWidth++; } else if ((cRankItem == 'r') || (cRankItem == 'n') || (cRankItem == 'b') || (cRankItem == 'q')) { nBlackPieces++; nRankWidth++; } else if ((cRankItem == 'R') || (cRankItem == 'N') || (cRankItem == 'B') || (cRankItem == 'Q')) { nWhitePieces++; nRankWidth++; } else if (cRankItem == 'k') { nBlackPieces++; nBlackKings++; nRankWidth++; } else if (cRankItem == 'K') { nWhitePieces++; nWhiteKings++; nRankWidth++; } else { m_bEpdValid = false; m_EpdErrorMsg = "Invalid EPD piece placement data, invalid character"; break; } nIndex++; } if (m_bEpdValid) { if (nRankWidth != 8) { m_bEpdValid = false; m_EpdErrorMsg = "Invalid EPD piece placement data, rank width != 8"; break; } } else { break; } pRank++; } if (m_bEpdValid) { if ((nBlackPawns > 8) || (nWhitePawns > 8) || ((nBlackPawns + nBlackPieces) > 16) || ((nWhitePawns + nWhitePieces) > 16) || (nBlackKings != 1) || (nWhiteKings != 1)) { m_bEpdValid = false; m_EpdErrorMsg = "Invalid EPD piece placement data, invalid pawn/piece/king configuration"; } } } else { m_bEpdValid = false; m_EpdErrorMsg = "Invalid EPD piece placement data, rank count != 8"; } } // ValidateActiveColor ensures that the color to move in the supplied // EPD is either white (w) or black(b). void EpdProcessor::ValidateActiveColor(char* pActiveColor) { if (*pActiveColor == 'w') { m_bWhiteToMove = true; } else if (*pActiveColor == 'b') { m_bWhiteToMove = false; } else { m_bEpdValid = false; m_EpdErrorMsg = "Invalid EPD active color"; } } // ValidateCastleAvailability ensure that the castle availability // string supplied in the EPD contains valid characters and that // the characters are in the correct sequence. void EpdProcessor::ValidateCastleAvailability() { int nSize; int nIndex; char cAvailable; bool bWhiteKingside = false; bool bWhiteQueenside = false; bool bBlackKingside = false; bool bBlackQueenside = false; if (m_CastleAvailability != "") { nSize = m_CastleAvailability.size(); if ((nSize >= 1) && (nSize <= 4)) { nIndex = 0; while (nIndex < nSize) { cAvailable = m_CastleAvailability[nIndex]; if (cAvailable == 'K') { if ((!bWhiteKingside) && (!bWhiteQueenside) && (!bBlackKingside) && (!bBlackQueenside)) { bWhiteKingside = true; } else { m_bEpdValid = false; m_EpdErrorMsg = "Invalid EPD castle availability"; break; } } else if (cAvailable == 'Q') { if ((!bWhiteQueenside) && (!bBlackKingside) && (!bBlackQueenside)) { bWhiteQueenside = true; } else { m_bEpdValid = false; m_EpdErrorMsg = "Invalid EPD castle availability"; break; } } else if (cAvailable == 'k') { if ((!bBlackKingside) && (!bBlackQueenside)) { bBlackKingside = true; } else { m_bEpdValid = false; m_EpdErrorMsg = "Invalid EPD castle availability"; break; } } else if (cAvailable == 'q') { if (!bBlackQueenside) { bBlackQueenside = true; } else { m_bEpdValid = false; m_EpdErrorMsg = "Invalid EPD castle availability"; break; } } else { m_bEpdValid = false; m_EpdErrorMsg = "Invalid EPD castle availability"; break; } nIndex++; } } else { m_bEpdValid = false; m_EpdErrorMsg = "Invalid EPD castle availability"; } } } // ValidateEnPassantTarget ensures that the en passant target string // supplied it the EPD is empty or contains a valid rank and file. void EpdProcessor::ValidateEnPassantTarget() { char cFile; char cRank; if (m_EnPassantTarget != "") { if (m_EnPassantTarget.size() == 2) { cFile = m_EnPassantTarget[0]; cRank = m_EnPassantTarget[1]; if ((cFile < 'a') || (cFile > 'h') || ((m_bWhiteToMove) && (cRank != '6')) || ((!m_bWhiteToMove) && (cRank != '3'))) { m_bEpdValid = false; m_EpdErrorMsg = "Invalid EPD en passant target square"; } } else { m_bEpdValid = false; m_EpdErrorMsg = "Invalid EPD en passant target square"; } } } // GenerateEpdVector takes the EPD supplied in SetEpd() and the PV // supplied in SetPv() and generates the resultant EPDs. void EpdProcessor::GenerateEpdVector() { EPD EpdData; char format[32]; std::string CastleAvailability; std::string EnPassantTarget; EpdBinary EpdBinaryData; std::list::iterator pSan; std::list::iterator pSanLast; SAN San; ChessMove Move; int nMoveNumber = 0; m_EpdVector.clear(); m_EpdBinaryVector.clear(); // Set up the board as the user specified m_Board.SetPiecePlacement(m_PiecePlacement); m_Board.SetWhiteToMove(m_bWhiteToMove); m_Board.SetCastleAvailability(m_CastleAvailability); m_Board.SetEnPassantTarget(m_EnPassantTarget); m_Board.SetHalfMoveClock(m_nHalfMoveClock); m_Board.SetFullMoveNumber(m_nFullMoveNumber); // Build EPD from the original supplied EPD EpdData = ""; EpdData += m_Board.GetPiecePlacement(); if (m_Board.IsWhiteToMove()) { EpdData += " w "; } else { EpdData += " b "; } CastleAvailability = m_Board.GetCastleAvailability(); if (CastleAvailability == "") { CastleAvailability = "-"; } EpdData += CastleAvailability; EpdData += " "; EnPassantTarget = m_Board.GetEnPassantTarget(); if (EnPassantTarget == "") { EnPassantTarget = "-"; } EpdData += EnPassantTarget; if (m_bGenerateOpcodes) { if (m_bOpcode_fmvn) { sprintf(format, " fmvn %d;", m_Board.GetFullMoveNumber()); EpdData += format; } if (m_bOpcode_hmvc) { sprintf(format, " hmvc %d;", m_Board.GetHalfMoveClock()); EpdData += format; } } m_EpdVector.push_back(EpdData); EpdBinaryData = m_Board.GetBinaryPosition(); m_EpdBinaryVector.push_back(EpdBinaryData); // Process collection of supplied moves pSan = m_SanList.begin(); pSanLast = m_SanList.end(); pSanLast--; while (pSan != m_SanList.end()) { nMoveNumber++; San = *pSan; // Make parse move to see if it's valid SAN Move.ParseSAN(San); if (Move.IsLegalMove()) // only if it's valid { // Flag only last move in PV, controls checkmate analysis if (pSan == pSanLast) { Move.SetLastInPv(true); } // Make move on chess board m_Board.Move(Move); } if (Move.IsLegalMove()) // only if move was legal { if (Move.IsMoveAltered()) // Was move altered? { m_nPvValid = EPD_STATUS_WARNING; // Yes, indicate to user San = Move.CreateSAN(); // and get altered move } // Build EPD after move has been processed EpdData = ""; EpdData += m_Board.GetPiecePlacement(); if (m_Board.IsWhiteToMove()) { EpdData += " w "; } else { EpdData += " b "; } CastleAvailability = m_Board.GetCastleAvailability(); if (CastleAvailability == "") { CastleAvailability = "-"; } EpdData += CastleAvailability; EpdData += " "; EnPassantTarget = m_Board.GetEnPassantTarget(); if (EnPassantTarget == "") { EnPassantTarget = "-"; } EpdData += EnPassantTarget; if (m_bGenerateOpcodes) { if (m_bOpcode_fmvn) { sprintf(format, " fmvn %d;", m_Board.GetFullMoveNumber()); EpdData += format; } if (m_bOpcode_hm) { sprintf(format, " hm %s;", San.c_str()); EpdData += format; } if (m_bOpcode_hmvc) { sprintf(format, " hmvc %d;", m_Board.GetHalfMoveClock()); EpdData += format; } } m_EpdVector.push_back(EpdData); EpdBinaryData = m_Board.GetBinaryPosition(); m_EpdBinaryVector.push_back(EpdBinaryData); if (m_PV != "") { m_PV += " "; } m_PV += San; } else { // Indicate nature of error // prepend move number and move to aid user m_nPvValid = EPD_STATUS_FAILURE; sprintf(format, "Move %d, %s: ", nMoveNumber, San.c_str()); m_PvErrorMsg = format; m_PvErrorMsg += Move.GetErrorMsg(); break; } pSan++; } } // GenerateLegalEpds() generates a collection of all of the // EPDs that may be reached by making one move from the // position supplied in SetEpd(). EPDs are generated in both // standard and compressed formats; void EpdProcessor::GenerateLegalEpds() { MOVE_LIST LegalMoveList; MOVE_LIST::iterator pMove; ChessMove Move; SAN San; EPD EpdData; EpdBinary EpdBinaryData; char format[32]; std::string CastleAvailability; std::string EnPassantTarget; int nFullMoveNumber; int nHalfMoveClock; int nColor; bool bKingChecked; // Reset everything related to the new collection m_bStalemate = false; m_bCheckmate = false; m_EpdList.clear(); m_EpdBinaryList.clear(); if (m_bEpdValid) // only if the user supplied a valid EPD { // Set up the board as the user specified m_Board.SetPiecePlacement(m_PiecePlacement); m_Board.SetWhiteToMove(m_bWhiteToMove); m_Board.SetCastleAvailability(m_CastleAvailability); m_Board.SetEnPassantTarget(m_EnPassantTarget); m_Board.SetHalfMoveClock(m_nHalfMoveClock); m_Board.SetFullMoveNumber(m_nFullMoveNumber); if (m_bWhiteToMove) { nColor = WHITE; } else { nColor = BLACK; } // Is player to move in check? bKingChecked = m_Board.IsKingChecked(nColor); // Get all the moves (include EPD data) that may be played LegalMoveList = m_Board.GetLegalMoveList(true); if (LegalMoveList.size() == 0) // if there are no moves { if (bKingChecked) // determine if we were already in check { m_bCheckmate = true; // Yes - it's checkmate } else { m_bStalemate = true; // No - it's stalemate } } // Sort the moves LegalMoveList.sort(); // Build a list of resultant EPDs pMove = LegalMoveList.begin(); while (pMove != LegalMoveList.end()) { Move = *pMove; // We've save some of the EPD data with the move for efficiency // sake so we don't need to "replay" the move. Some of the EPD // data we derive from the information the user supplied in their // EPD. EpdData = Move.GetPiecePlacementAfter(); if (m_bWhiteToMove) { EpdData += " b "; } else { EpdData += " w "; } CastleAvailability = Move.GetCastleAvailabilityAfter();; if (CastleAvailability == "") { CastleAvailability = "-"; } EpdData += CastleAvailability; EpdData += " "; EnPassantTarget = Move.GetEnPassantTarget(); if (EnPassantTarget == "") { EnPassantTarget = "-"; } EpdData += EnPassantTarget; // Generate compressed EPD from basic EPD EpdBinaryData = EpdData; m_EpdBinaryList.push_back(EpdBinaryData); if (m_bGenerateOpcodes) { if (m_bOpcode_fmvn) { nFullMoveNumber = m_nFullMoveNumber; if (!m_bWhiteToMove) { nFullMoveNumber++; } sprintf(format, " fmvn %d;", nFullMoveNumber); EpdData += format; } if (m_bOpcode_hm) { San = Move.CreateSAN(); sprintf(format, " hm %s;", San.c_str()); EpdData += format; } if (m_bOpcode_hmvc) { if ((Move.GetManToMove() == Pawn) || (Move.IsCapture())) { nHalfMoveClock = 0; } else { nHalfMoveClock = m_nHalfMoveClock + 1; } sprintf(format, " hmvc %d;", nHalfMoveClock); EpdData += format; } } m_EpdList.push_back(EpdData); pMove++; } } }