diff --git a/src/perfect/bufferedFile.cpp b/src/perfect/bufferedFile.cpp index bb897a44..9eca3887 100644 --- a/src/perfect/bufferedFile.cpp +++ b/src/perfect/bufferedFile.cpp @@ -15,7 +15,7 @@ BufferedFile::BufferedFile(unsigned int numberOfThreads, unsigned int bufferSizeInBytes, const char *fileName) { // locals - unsigned int curThread; + unsigned int curThread; // Init blocks bufferSize = bufferSizeInBytes; @@ -27,7 +27,8 @@ BufferedFile::BufferedFile(unsigned int numberOfThreads, unsigned int bufferSize bytesInReadBuffer = new unsigned int[numThreads]; bytesInWriteBuffer = new unsigned int[numThreads]; - for (curThread = 0; curThread < numThreads; curThread++) { + for (curThread = 0; curThread < numThreads; curThread++) + { curReadingPointer[curThread] = 0; curWritingPointer[curThread] = 0; bytesInReadBuffer[curThread] = 0; @@ -39,7 +40,8 @@ BufferedFile::BufferedFile(unsigned int numberOfThreads, unsigned int bufferSize hFile = CreateFileA(fileName, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); // opened file succesfully - if (hFile == INVALID_HANDLE_VALUE) { + if (hFile == INVALID_HANDLE_VALUE) + { hFile = nullptr; return; } @@ -67,12 +69,13 @@ BufferedFile::~BufferedFile() delete[] bytesInWriteBuffer; // close file - if (hFile != nullptr) CloseHandle(hFile); + if (hFile != nullptr) + CloseHandle(hFile); } //----------------------------------------------------------------------------- // Name: getFileSize() -// Desc: +// Desc: //----------------------------------------------------------------------------- long long BufferedFile::getFileSize() { @@ -84,11 +87,12 @@ long long BufferedFile::getFileSize() //----------------------------------------------------------------------------- // Name: flushBuffers() -// Desc: +// Desc: //----------------------------------------------------------------------------- bool BufferedFile::flushBuffers() { - for (unsigned int threadNo = 0; threadNo < numThreads; threadNo++) { + for (unsigned int threadNo = 0; threadNo < numThreads; threadNo++) + { writeDataToFile(hFile, curWritingPointer[threadNo] - bytesInWriteBuffer[threadNo], bytesInWriteBuffer[threadNo], &writeBuffer[threadNo * bufferSize + 0]); bytesInWriteBuffer[threadNo] = 0; } @@ -101,21 +105,30 @@ bool BufferedFile::flushBuffers() //----------------------------------------------------------------------------- void BufferedFile::writeDataToFile(HANDLE hFile, long long offset, unsigned int sizeInBytes, void *pData) { - DWORD dwBytesWritten; - LARGE_INTEGER liDistanceToMove; - unsigned int restingBytes = sizeInBytes; + DWORD dwBytesWritten; + LARGE_INTEGER liDistanceToMove; + unsigned int restingBytes = sizeInBytes; liDistanceToMove.QuadPart = offset; EnterCriticalSection(&csIO); - while (!SetFilePointerEx(hFile, liDistanceToMove, nullptr, FILE_BEGIN)) cout << endl << "SetFilePointerEx failed!"; - while (restingBytes > 0) { - if (WriteFile(hFile, pData, sizeInBytes, &dwBytesWritten, nullptr) == TRUE) { + while (!SetFilePointerEx(hFile, liDistanceToMove, nullptr, FILE_BEGIN)) + cout << endl + << "SetFilePointerEx failed!"; + while (restingBytes > 0) + { + if (WriteFile(hFile, pData, sizeInBytes, &dwBytesWritten, nullptr) == TRUE) + { restingBytes -= dwBytesWritten; pData = (void *)(((unsigned char *)pData) + dwBytesWritten); - if (restingBytes > 0) cout << endl << "Still " << restingBytes << " to write!"; - } else { - cout << endl << "WriteFile Failed!"; + if (restingBytes > 0) + cout << endl + << "Still " << restingBytes << " to write!"; + } + else + { + cout << endl + << "WriteFile Failed!"; } } LeaveCriticalSection(&csIO); @@ -127,21 +140,30 @@ void BufferedFile::writeDataToFile(HANDLE hFile, long long offset, unsigned int //----------------------------------------------------------------------------- void BufferedFile::readDataFromFile(HANDLE hFile, long long offset, unsigned int sizeInBytes, void *pData) { - DWORD dwBytesRead; - LARGE_INTEGER liDistanceToMove; - unsigned int restingBytes = sizeInBytes; + DWORD dwBytesRead; + LARGE_INTEGER liDistanceToMove; + unsigned int restingBytes = sizeInBytes; liDistanceToMove.QuadPart = offset; EnterCriticalSection(&csIO); - while (!SetFilePointerEx(hFile, liDistanceToMove, nullptr, FILE_BEGIN)) cout << endl << "SetFilePointerEx failed!"; - while (restingBytes > 0) { - if (ReadFile(hFile, pData, sizeInBytes, &dwBytesRead, nullptr) == TRUE) { + while (!SetFilePointerEx(hFile, liDistanceToMove, nullptr, FILE_BEGIN)) + cout << endl + << "SetFilePointerEx failed!"; + while (restingBytes > 0) + { + if (ReadFile(hFile, pData, sizeInBytes, &dwBytesRead, nullptr) == TRUE) + { restingBytes -= dwBytesRead; pData = (void *)(((unsigned char *)pData) + dwBytesRead); - if (restingBytes > 0) cout << endl << "Still " << restingBytes << " to read!"; - } else { - cout << endl << "ReadFile Failed!"; + if (restingBytes > 0) + cout << endl + << "Still " << restingBytes << " to read!"; + } + else + { + cout << endl + << "ReadFile Failed!"; } } LeaveCriticalSection(&csIO); @@ -149,7 +171,7 @@ void BufferedFile::readDataFromFile(HANDLE hFile, long long offset, unsigned int //----------------------------------------------------------------------------- // Name: writeBytes() -// Desc: +// Desc: //----------------------------------------------------------------------------- bool BufferedFile::writeBytes(unsigned int numBytes, unsigned char *pData) { @@ -158,18 +180,21 @@ bool BufferedFile::writeBytes(unsigned int numBytes, unsigned char *pData) //----------------------------------------------------------------------------- // Name: writeBytes() -// Desc: +// Desc: //----------------------------------------------------------------------------- bool BufferedFile::writeBytes(unsigned int threadNo, long long positionInFile, unsigned int numBytes, unsigned char *pData) { // parameters ok? - if (threadNo >= numThreads) return false; - if (pData == nullptr) return false; + if (threadNo >= numThreads) + return false; + if (pData == nullptr) + return false; // locals // if buffer full or not sequential write operation write buffer to file - if (bytesInWriteBuffer[threadNo] && (positionInFile != curWritingPointer[threadNo] || bytesInWriteBuffer[threadNo] + numBytes >= bufferSize)) { + if (bytesInWriteBuffer[threadNo] && (positionInFile != curWritingPointer[threadNo] || bytesInWriteBuffer[threadNo] + numBytes >= bufferSize)) + { writeDataToFile(hFile, curWritingPointer[threadNo] - bytesInWriteBuffer[threadNo], bytesInWriteBuffer[threadNo], &writeBuffer[threadNo * bufferSize + 0]); bytesInWriteBuffer[threadNo] = 0; @@ -186,7 +211,7 @@ bool BufferedFile::writeBytes(unsigned int threadNo, long long positionInFile, u //----------------------------------------------------------------------------- // Name: takeBytes() -// Desc: +// Desc: //----------------------------------------------------------------------------- bool BufferedFile::readBytes(unsigned int numBytes, unsigned char *pData) { @@ -195,18 +220,22 @@ bool BufferedFile::readBytes(unsigned int numBytes, unsigned char *pData) //----------------------------------------------------------------------------- // Name: takeBytes() -// Desc: +// Desc: //----------------------------------------------------------------------------- bool BufferedFile::readBytes(unsigned int threadNo, long long positionInFile, unsigned int numBytes, unsigned char *pData) { // parameters ok? - if (threadNo >= numThreads) return false; - if (pData == nullptr) return false; + if (threadNo >= numThreads) + return false; + if (pData == nullptr) + return false; // read from file into buffer if not enough data in buffer or if it is not an sequential reading operation? - if (positionInFile != curReadingPointer[threadNo] || bytesInReadBuffer[threadNo] < numBytes) { + if (positionInFile != curReadingPointer[threadNo] || bytesInReadBuffer[threadNo] < numBytes) + { bytesInReadBuffer[threadNo] = ((positionInFile + bufferSize <= fileSize) ? bufferSize : (unsigned int)(fileSize - positionInFile)); - if (bytesInReadBuffer[threadNo] < numBytes) return false; + if (bytesInReadBuffer[threadNo] < numBytes) + return false; readDataFromFile(hFile, positionInFile, bytesInReadBuffer[threadNo], &readBuffer[threadNo * bufferSize + bufferSize - bytesInReadBuffer[threadNo]]); } memcpy(pData, &readBuffer[threadNo * bufferSize + bufferSize - bytesInReadBuffer[threadNo]], numBytes); diff --git a/src/perfect/bufferedFile.h b/src/perfect/bufferedFile.h index abe76d20..5cad8182 100644 --- a/src/perfect/bufferedFile.h +++ b/src/perfect/bufferedFile.h @@ -21,21 +21,21 @@ class BufferedFile { private: // Variables - HANDLE hFile; // Handle of the file - unsigned int numThreads; // number of threads - unsigned char *readBuffer; // Array of size [numThreads*blockSize] containing the data of the block, where reading is taking place - unsigned char *writeBuffer; // '' - access by [threadNo*bufferSize+position] - long long *curReadingPointer; // array of size [numThreads] with pointers to the byte which is currently read - long long *curWritingPointer; // '' - unsigned int *bytesInReadBuffer; // - unsigned int *bytesInWriteBuffer; // - unsigned int bufferSize; // size in bytes of a buffer - long long fileSize; // size in bytes - CRITICAL_SECTION csIO; + HANDLE hFile; // Handle of the file + unsigned int numThreads; // number of threads + unsigned char *readBuffer; // Array of size [numThreads*blockSize] containing the data of the block, where reading is taking place + unsigned char *writeBuffer; // '' - access by [threadNo*bufferSize+position] + long long *curReadingPointer; // array of size [numThreads] with pointers to the byte which is currently read + long long *curWritingPointer; // '' + unsigned int *bytesInReadBuffer; // + unsigned int *bytesInWriteBuffer; // + unsigned int bufferSize; // size in bytes of a buffer + long long fileSize; // size in bytes + CRITICAL_SECTION csIO; // Functions - void writeDataToFile(HANDLE hFile, long long offset, unsigned int sizeInBytes, void *pData); - void readDataFromFile(HANDLE hFile, long long offset, unsigned int sizeInBytes, void *pData); + void writeDataToFile(HANDLE hFile, long long offset, unsigned int sizeInBytes, void *pData); + void readDataFromFile(HANDLE hFile, long long offset, unsigned int sizeInBytes, void *pData); public: // Constructor / destructor @@ -43,12 +43,12 @@ public: ~BufferedFile(); // Functions - bool flushBuffers(); - bool writeBytes(unsigned int numBytes, unsigned char *pData); - bool readBytes(unsigned int numBytes, unsigned char *pData); - bool writeBytes(unsigned int threadNo, long long positionInFile, unsigned int numBytes, unsigned char *pData); - bool readBytes(unsigned int threadNo, long long positionInFile, unsigned int numBytes, unsigned char *pData); - long long getFileSize(); + bool flushBuffers(); + bool writeBytes(unsigned int numBytes, unsigned char *pData); + bool readBytes(unsigned int numBytes, unsigned char *pData); + bool writeBytes(unsigned int threadNo, long long positionInFile, unsigned int numBytes, unsigned char *pData); + bool readBytes(unsigned int threadNo, long long positionInFile, unsigned int numBytes, unsigned char *pData); + long long getFileSize(); }; #endif diff --git a/src/perfect/config.h b/src/perfect/config.h index 4e57d001..8559a866 100644 --- a/src/perfect/config.h +++ b/src/perfect/config.h @@ -6,7 +6,6 @@ https://github.com/madweasel/madweasels-cpp \*********************************************************************/ - #ifndef CONFIG_H #define CONFIG_H diff --git a/src/perfect/cyclicArray.cpp b/src/perfect/cyclicArray.cpp index beec76fb..eade6bb5 100644 --- a/src/perfect/cyclicArray.cpp +++ b/src/perfect/cyclicArray.cpp @@ -11,7 +11,7 @@ //----------------------------------------------------------------------------- // Name: CyclicArray() // Desc: Creates a cyclic array. The passed file is used as temporary data buffer for the cyclic array. -//----------------------------------------------------------------------------- +//-----------------------------F------------------------------------------------ CyclicArray::CyclicArray(unsigned int blockSizeInBytes, unsigned int numberOfBlocks, const char *fileName) { // Init blocks @@ -29,7 +29,8 @@ CyclicArray::CyclicArray(unsigned int blockSizeInBytes, unsigned int numberOfBlo hFile = CreateFileA(fileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); // opened file succesfully - if (hFile == INVALID_HANDLE_VALUE) { + if (hFile == INVALID_HANDLE_VALUE) + { hFile = nullptr; return; } @@ -46,7 +47,8 @@ CyclicArray::~CyclicArray() delete[] writingBlock; // close file - if (hFile != nullptr) CloseHandle(hFile); + if (hFile != nullptr) + CloseHandle(hFile); } //----------------------------------------------------------------------------- @@ -55,21 +57,30 @@ CyclicArray::~CyclicArray() //----------------------------------------------------------------------------- void CyclicArray::writeDataToFile(HANDLE hFile, long long offset, unsigned int sizeInBytes, void *pData) { - DWORD dwBytesWritten; - LARGE_INTEGER liDistanceToMove; - unsigned int restingBytes = sizeInBytes; + DWORD dwBytesWritten; + LARGE_INTEGER liDistanceToMove; + unsigned int restingBytes = sizeInBytes; liDistanceToMove.QuadPart = offset; - while (!SetFilePointerEx(hFile, liDistanceToMove, nullptr, FILE_BEGIN)) cout << endl << "SetFilePointerEx failed!"; + while (!SetFilePointerEx(hFile, liDistanceToMove, nullptr, FILE_BEGIN)) + cout << endl + << "SetFilePointerEx failed!"; - while (restingBytes > 0) { - if (WriteFile(hFile, pData, sizeInBytes, &dwBytesWritten, nullptr) == TRUE) { + while (restingBytes > 0) + { + if (WriteFile(hFile, pData, sizeInBytes, &dwBytesWritten, nullptr) == TRUE) + { restingBytes -= dwBytesWritten; pData = (void *)(((unsigned char *)pData) + dwBytesWritten); - if (restingBytes > 0) cout << endl << "Still " << restingBytes << " to write!"; - } else { - cout << endl << "WriteFile Failed!"; + if (restingBytes > 0) + cout << endl + << "Still " << restingBytes << " to write!"; + } + else + { + cout << endl + << "WriteFile Failed!"; } } } @@ -80,37 +91,47 @@ void CyclicArray::writeDataToFile(HANDLE hFile, long long offset, unsigned int s //----------------------------------------------------------------------------- void CyclicArray::readDataFromFile(HANDLE hFile, long long offset, unsigned int sizeInBytes, void *pData) { - DWORD dwBytesRead; - LARGE_INTEGER liDistanceToMove; - unsigned int restingBytes = sizeInBytes; + DWORD dwBytesRead; + LARGE_INTEGER liDistanceToMove; + unsigned int restingBytes = sizeInBytes; liDistanceToMove.QuadPart = offset; - while (!SetFilePointerEx(hFile, liDistanceToMove, nullptr, FILE_BEGIN)) cout << endl << "SetFilePointerEx failed!"; + while (!SetFilePointerEx(hFile, liDistanceToMove, nullptr, FILE_BEGIN)) + cout << endl + << "SetFilePointerEx failed!"; - while (restingBytes > 0) { - if (ReadFile(hFile, pData, sizeInBytes, &dwBytesRead, nullptr) == TRUE) { + while (restingBytes > 0) + { + if (ReadFile(hFile, pData, sizeInBytes, &dwBytesRead, nullptr) == TRUE) + { restingBytes -= dwBytesRead; pData = (void *)(((unsigned char *)pData) + dwBytesRead); - if (restingBytes > 0) cout << endl << "Still " << restingBytes << " to read!"; - } else { - cout << endl << "ReadFile Failed!"; + if (restingBytes > 0) + cout << endl + << "Still " << restingBytes << " to read!"; + } + else + { + cout << endl + << "ReadFile Failed!"; } } } //----------------------------------------------------------------------------- // Name: addBytes() -// Desc: Add the passed data to the cyclic array. If the writing pointer reaches the end of a block, +// Desc: Add the passed data to the cyclic array. If the writing pointer reaches the end of a block, // the data of the whole block is written to the file and the next block is considered for writing. //----------------------------------------------------------------------------- bool CyclicArray::addBytes(unsigned int numBytes, unsigned char *pData) { // locals - unsigned int bytesWritten = 0; + unsigned int bytesWritten = 0; // write each byte - while (bytesWritten < numBytes) { + while (bytesWritten < numBytes) + { // store byte in current reading block *curWritingPointer = *pData; @@ -119,16 +140,19 @@ bool CyclicArray::addBytes(unsigned int numBytes, unsigned char *pData) pData++; // when block is full then save current one to file and begin new one - if (curWritingPointer == writingBlock + blockSize) { + if (curWritingPointer == writingBlock + blockSize) + { // copy data into reading block? - if (curReadingBlock == curWritingBlock) { + if (curReadingBlock == curWritingBlock) + { memcpy(readingBlock, writingBlock, blockSize); curReadingPointer = readingBlock + (curReadingPointer - writingBlock); } // will reading block be overwritten? - if (curReadingBlock == curWritingBlock && !readWriteInSameRound) return false; + if (curReadingBlock == curWritingBlock && !readWriteInSameRound) + return false; // store bock in file writeDataToFile(hFile, ((long long)blockSize) * ((long long)curWritingBlock), blockSize, writingBlock); @@ -136,7 +160,8 @@ bool CyclicArray::addBytes(unsigned int numBytes, unsigned char *pData) // set pointer to beginnig of writing block curWritingPointer = writingBlock; curWritingBlock = (curWritingBlock + 1) % numBlocks; - if (curWritingBlock == 0) readWriteInSameRound = false; + if (curWritingBlock == 0) + readWriteInSameRound = false; } } @@ -146,17 +171,19 @@ bool CyclicArray::addBytes(unsigned int numBytes, unsigned char *pData) //----------------------------------------------------------------------------- // Name: bytesAvailable() -// Desc: +// Desc: //----------------------------------------------------------------------------- bool CyclicArray::bytesAvailable() { - if (curReadingBlock == curWritingBlock && curReadingPointer == curWritingPointer && readWriteInSameRound) return false; - else return true; + if (curReadingBlock == curWritingBlock && curReadingPointer == curWritingPointer && readWriteInSameRound) + return false; + else + return true; } //----------------------------------------------------------------------------- // Name: takeBytes() -// Desc: Load data from the cyclic array. If the reading pointer reaches the end of a block, +// Desc: Load data from the cyclic array. If the reading pointer reaches the end of a block, // the data of the next whole block is read from the file. //----------------------------------------------------------------------------- bool CyclicArray::takeBytes(unsigned int numBytes, unsigned char *pData) @@ -164,11 +191,13 @@ bool CyclicArray::takeBytes(unsigned int numBytes, unsigned char *pData) // locals unsigned int bytesRead = 0; - // read each byte - while (bytesRead < numBytes) { + // read each byte + while (bytesRead < numBytes) + { // was current reading byte already written ? - if (curReadingBlock == curWritingBlock && curReadingPointer == curWritingPointer && readWriteInSameRound) return false; + if (curReadingBlock == curWritingBlock && curReadingPointer == curWritingPointer && readWriteInSameRound) + return false; // read current byte *pData = *curReadingPointer; @@ -177,17 +206,21 @@ bool CyclicArray::takeBytes(unsigned int numBytes, unsigned char *pData) pData++; // load next block? - if (curReadingPointer == readingBlock + blockSize) { + if (curReadingPointer == readingBlock + blockSize) + { // go to next block curReadingBlock = (curReadingBlock + 1) % numBlocks; - if (curReadingBlock == 0) readWriteInSameRound = true; + if (curReadingBlock == 0) + readWriteInSameRound = true; // writing block reached ? - if (curReadingBlock == curWritingBlock) { + if (curReadingBlock == curWritingBlock) + { curReadingPointer = writingBlock; - - } else { + } + else + { // set pointer to beginnig of reading block curReadingPointer = readingBlock; @@ -210,31 +243,34 @@ bool CyclicArray::takeBytes(unsigned int numBytes, unsigned char *pData) bool CyclicArray::loadFile(const char *fileName, LONGLONG &numBytesLoaded) { // locals - HANDLE hLoadFile; + HANDLE hLoadFile; unsigned char *dataInFile; - LARGE_INTEGER largeInt; - LONGLONG maxFileSize = ((LONGLONG)blockSize) * ((LONGLONG)numBlocks); - LONGLONG curOffset = 0; - unsigned int numBlocksInFile; - unsigned int curBlock; - unsigned int numBytesInLastBlock; + LARGE_INTEGER largeInt; + LONGLONG maxFileSize = ((LONGLONG)blockSize) * ((LONGLONG)numBlocks); + LONGLONG curOffset = 0; + unsigned int numBlocksInFile; + unsigned int curBlock; + unsigned int numBytesInLastBlock; numBytesLoaded = 0; // cyclic array file must be open - if (hFile == nullptr) return false; + if (hFile == nullptr) + return false; // Open Database-File (FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_RANDOM_ACCESS) hLoadFile = CreateFileA(fileName, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); // opened file succesfully - if (hLoadFile == INVALID_HANDLE_VALUE) { + if (hLoadFile == INVALID_HANDLE_VALUE) + { return false; } // does data of file fit into cyclic array ? GetFileSizeEx(hLoadFile, &largeInt); - if (maxFileSize < largeInt.QuadPart) { + if (maxFileSize < largeInt.QuadPart) + { CloseHandle(hLoadFile); return false; } @@ -250,8 +286,9 @@ bool CyclicArray::loadFile(const char *fileName, LONGLONG &numBytesLoaded) numBytesInLastBlock = (unsigned int)(largeInt.QuadPart % ((LONGLONG)blockSize)); dataInFile = new unsigned char[blockSize]; - // - for (curBlock = 0; curBlock < numBlocksInFile - 1; curBlock++, curOffset += blockSize) { + // + for (curBlock = 0; curBlock < numBlocksInFile - 1; curBlock++, curOffset += blockSize) + { // load data from file readDataFromFile(hLoadFile, curOffset, blockSize, dataInFile); @@ -281,14 +318,15 @@ bool CyclicArray::saveFile(const char *fileName) { // locals unsigned char *dataInFile; - HANDLE hSaveFile; - LONGLONG curOffset; - unsigned int curBlock; - unsigned int bytesToWrite; + HANDLE hSaveFile; + LONGLONG curOffset; + unsigned int curBlock; + unsigned int bytesToWrite; void *pointer; // cyclic array file must be open - if (hFile == nullptr) { + if (hFile == nullptr) + { return false; } @@ -296,7 +334,8 @@ bool CyclicArray::saveFile(const char *fileName) hSaveFile = CreateFileA(fileName, GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); // opened file succesfully - if (hSaveFile == INVALID_HANDLE_VALUE) { + if (hSaveFile == INVALID_HANDLE_VALUE) + { return false; } @@ -305,22 +344,27 @@ bool CyclicArray::saveFile(const char *fileName) curBlock = curReadingBlock; dataInFile = new unsigned char[blockSize]; - do { + do + { // copy current block - if (curBlock == curWritingBlock && curBlock == curReadingBlock) { + if (curBlock == curWritingBlock && curBlock == curReadingBlock) + { pointer = curReadingPointer; bytesToWrite = (unsigned int)(curWritingPointer - curReadingPointer); - - } else if (curBlock == curWritingBlock) { + } + else if (curBlock == curWritingBlock) + { pointer = writingBlock; bytesToWrite = (unsigned int)(curWritingPointer - writingBlock); - - } else if (curBlock == curReadingBlock) { + } + else if (curBlock == curReadingBlock) + { pointer = curReadingPointer; bytesToWrite = blockSize - (unsigned int)(curReadingPointer - readingBlock); - - } else { + } + else + { readDataFromFile(hFile, ((long long)curBlock) * ((long long)blockSize), blockSize, dataInFile); pointer = dataInFile; bytesToWrite = blockSize; @@ -331,8 +375,10 @@ bool CyclicArray::saveFile(const char *fileName) curOffset += bytesToWrite; // exit? - if (curBlock == curWritingBlock) break; - else curBlock = (curBlock + 1) % numBlocks; + if (curBlock == curWritingBlock) + break; + else + curBlock = (curBlock + 1) % numBlocks; } while (true); diff --git a/src/perfect/cyclicArray.h b/src/perfect/cyclicArray.h index a4fa9426..55fa1cfc 100644 --- a/src/perfect/cyclicArray.h +++ b/src/perfect/cyclicArray.h @@ -21,16 +21,16 @@ class CyclicArray { private: // Variables - HANDLE hFile; // Handle of the file - unsigned char *readingBlock; // Array of size [blockSize] containing the data of the block, where reading is taking place - unsigned char *writingBlock; // '' - unsigned char *curReadingPointer; // pointer to the byte which is currently read - unsigned char *curWritingPointer; // '' - unsigned int blockSize; // size in bytes of a block - unsigned int curReadingBlock; // index of the block, where reading is taking place - unsigned int curWritingBlock; // index of the block, where writing is taking place - unsigned int numBlocks; // amount of blocks - bool readWriteInSameRound; // true if curReadingBlock > curWritingBlock, false otherwise + HANDLE hFile; // Handle of the file + unsigned char *readingBlock; // Array of size [blockSize] containing the data of the block, where reading is taking place + unsigned char *writingBlock; // '' + unsigned char *curReadingPointer; // pointer to the byte which is currently read + unsigned char *curWritingPointer; // '' + unsigned int blockSize; // size in bytes of a block + unsigned int curReadingBlock; // index of the block, where reading is taking place + unsigned int curWritingBlock; // index of the block, where writing is taking place + unsigned int numBlocks; // amount of blocks + bool readWriteInSameRound; // true if curReadingBlock > curWritingBlock, false otherwise // Functions void writeDataToFile(HANDLE hFile, long long offset, unsigned int sizeInBytes, void *pData); @@ -42,11 +42,11 @@ public: ~CyclicArray(); // Functions - bool addBytes(unsigned int numBytes, unsigned char *pData); - bool takeBytes(unsigned int numBytes, unsigned char *pData); - bool loadFile(const char *fileName, LONGLONG &numBytesLoaded); - bool saveFile(const char *fileName); - bool bytesAvailable(); + bool addBytes(unsigned int numBytes, unsigned char *pData); + bool takeBytes(unsigned int numBytes, unsigned char *pData); + bool loadFile(const char *fileName, LONGLONG &numBytesLoaded); + bool saveFile(const char *fileName); + bool bytesAvailable(); }; #endif diff --git a/src/perfect/main.cpp b/src/perfect/main.cpp index 56519e28..117a2600 100644 --- a/src/perfect/main.cpp +++ b/src/perfect/main.cpp @@ -10,22 +10,22 @@ using namespace std; -unsigned int startTestFromLayer = 0; -unsigned int endTestAtLayer = NUM_LAYERS - 1; +unsigned int startTestFromLayer = 0; +unsigned int endTestAtLayer = NUM_LAYERS - 1; #ifdef _DEBUG -char databaseDirectory[] = "D:\\database"; +char databaseDirectory[] = "D:\\database"; #elif _RELEASE_X64 -char databaseDirectory[] = ""; +char databaseDirectory[] = ""; #endif -bool calculateDatabase = false; +bool calculateDatabase = false; int main(void) { // locals - bool playerOneHuman = false; - bool playerTwoHuman = false; - char ch[100]; - unsigned int pushFrom, pushTo; + bool playerOneHuman = false; + bool playerTwoHuman = false; + char ch[100]; + unsigned int pushFrom, pushTo; Position *pos = new Position(); PerfectAI *ai = new PerfectAI(databaseDirectory); @@ -35,7 +35,8 @@ int main(void) // intro cout << "*************************" << endl; cout << "* Muehle *" << endl; - cout << "*************************" << endl << endl; + cout << "*************************" << endl + << endl; ai->setDatabasePath(databaseDirectory); @@ -46,28 +47,40 @@ int main(void) pos->beginNewGame(ai, ai, (rand() % 2) ? fieldStruct::playerOne : fieldStruct::playerTwo); #endif // SELF_PLAY - if (calculateDatabase) { + if (calculateDatabase) + { // calculate ai->calculateDatabase(MAX_DEPTH_OF_TREE, false); // test database - cout << endl << "Begin test starting from layer: "; startTestFromLayer; - cout << endl << "End test at layer: "; endTestAtLayer; + cout << endl + << "Begin test starting from layer: "; + startTestFromLayer; + cout << endl + << "End test at layer: "; + endTestAtLayer; ai->testLayers(startTestFromLayer, endTestAtLayer); - - } else { - + } + else + { #ifdef SELF_PLAY int moveCount = 0; #else - cout << "Is Player 1 human? (y/n):"; cin >> ch; if (ch[0] == 'y') playerOneHuman = true; - cout << "Is Player 2 human? (y/n):"; cin >> ch; if (ch[0] == 'y') playerTwoHuman = true; + cout << "Is Player 1 human? (y/n):"; + cin >> ch; + if (ch[0] == 'y') + playerOneHuman = true; + cout << "Is Player 2 human? (y/n):"; + cin >> ch; + if (ch[0] == 'y') + playerTwoHuman = true; #endif // SELF_PLAY // play - do { + do + { // print board cout << "\n\n\n\n\n\n\n\n\n\n\n"; pos->getComputersChoice(&pushFrom, &pushTo); @@ -76,7 +89,8 @@ int main(void) #ifdef SELF_PLAY moveCount++; - if (moveCount > 99) { + if (moveCount > 99) + { goto out; } #endif // SELF_PLAY @@ -84,32 +98,49 @@ int main(void) pos->printBoard(); // Human - if ((pos->getCurrentPlayer() == fieldStruct::playerOne && playerOneHuman) - || (pos->getCurrentPlayer() == fieldStruct::playerTwo && playerTwoHuman)) { - do { + if ((pos->getCurrentPlayer() == fieldStruct::playerOne && playerOneHuman) || (pos->getCurrentPlayer() == fieldStruct::playerTwo && playerTwoHuman)) + { + do + { // Show text - if (pos->mustStoneBeRemoved()) cout << "\n Which stone do you want to remove? [a-x]: \n\n\n"; - else if (pos->inSettingPhase()) cout << "\n Where are you going? [a-x]: \n\n\n"; - else cout << "\n Your train? [a-x][a-x]: \n\n\n"; + if (pos->mustStoneBeRemoved()) + cout << "\n Which stone do you want to remove? [a-x]: \n\n\n"; + else if (pos->inSettingPhase()) + cout << "\n Where are you going? [a-x]: \n\n\n"; + else + cout << "\n Your train? [a-x][a-x]: \n\n\n"; // get input cin >> ch; - if ((ch[0] >= 'a') && (ch[0] <= 'x')) pushFrom = ch[0] - 'a'; else pushFrom = fieldStruct::size; + if ((ch[0] >= 'a') && (ch[0] <= 'x')) + pushFrom = ch[0] - 'a'; + else + pushFrom = fieldStruct::size; - if (pos->inSettingPhase()) { - if ((ch[0] >= 'a') && (ch[0] <= 'x')) pushTo = ch[0] - 'a'; else pushTo = fieldStruct::size; - } else { - if ((ch[1] >= 'a') && (ch[1] <= 'x')) pushTo = ch[1] - 'a'; else pushTo = fieldStruct::size; + if (pos->inSettingPhase()) + { + if ((ch[0] >= 'a') && (ch[0] <= 'x')) + pushTo = ch[0] - 'a'; + else + pushTo = fieldStruct::size; + } + else + { + if ((ch[1] >= 'a') && (ch[1] <= 'x')) + pushTo = ch[1] - 'a'; + else + pushTo = fieldStruct::size; } // undo - if (ch[0] == 'u' && ch[1] == 'n' && ch[2] == 'd' && ch[3] == 'o') { + if (ch[0] == 'u' && ch[1] == 'n' && ch[2] == 'd' && ch[3] == 'o') + { // undo moves until a human player shall move - do { + do + { pos->undo_move(); - } while (!((pos->getCurrentPlayer() == fieldStruct::playerOne && playerOneHuman) - || (pos->getCurrentPlayer() == fieldStruct::playerTwo && playerTwoHuman))); + } while (!((pos->getCurrentPlayer() == fieldStruct::playerOne && playerOneHuman) || (pos->getCurrentPlayer() == fieldStruct::playerTwo && playerTwoHuman))); // reprint board break; @@ -118,7 +149,9 @@ int main(void) } while (pos->do_move(pushFrom, pushTo) == false); // Computer - } else { + } + else + { cout << "\n"; pos->do_move(pushFrom, pushTo); } @@ -130,13 +163,17 @@ int main(void) pos->printBoard(); - if (pos->getWinner() == fieldStruct::playerOne) cout << "\n Player 1 (o) won after " << pos->getMovesDone() << " move.\n\n"; - else if (pos->getWinner() == fieldStruct::playerTwo) cout << "\n Player 2 (x) won after " << pos->getMovesDone() << " move.\n\n"; - else if (pos->getWinner() == fieldStruct::gameDrawn) cout << "\n Draw!\n\n"; - else cout << "\n A program error has occurred!\n\n"; + if (pos->getWinner() == fieldStruct::playerOne) + cout << "\n Player 1 (o) won after " << pos->getMovesDone() << " move.\n\n"; + else if (pos->getWinner() == fieldStruct::playerTwo) + cout << "\n Player 2 (x) won after " << pos->getMovesDone() << " move.\n\n"; + else if (pos->getWinner() == fieldStruct::gameDrawn) + cout << "\n Draw!\n\n"; + else + cout << "\n A program error has occurred!\n\n"; } - out: +out: char end; cin >> end; diff --git a/src/perfect/millAI.cpp b/src/perfect/millAI.cpp index db1b3717..31932dba 100644 --- a/src/perfect/millAI.cpp +++ b/src/perfect/millAI.cpp @@ -12,15 +12,16 @@ using namespace std; //----------------------------------------------------------------------------- // Name: printBoard() -// Desc: +// Desc: //----------------------------------------------------------------------------- void fieldStruct::printBoard() { // locals unsigned int index; - char c[fieldStruct::size]; + char c[fieldStruct::size]; - for (index = 0; index < fieldStruct::size; index++) c[index] = GetCharFromStone(this->board[index]); + for (index = 0; index < fieldStruct::size; index++) + c[index] = GetCharFromStone(this->board[index]); cout << "current player : " << GetCharFromStone(this->curPlayer->id) << " has " << this->curPlayer->numStones << " stones\n"; cout << "opponent player : " << GetCharFromStone(this->oppPlayer->id) << " has " << this->oppPlayer->numStones << " stones\n"; @@ -28,34 +29,51 @@ void fieldStruct::printBoard() cout << "setting phase : " << (this->settingPhase ? "true" : "false"); cout << "\n"; cout << "\n a-----b-----c " << c[0] << "-----" << c[1] << "-----" << c[2]; - cout << "\n | | | " << "| | |"; - cout << "\n | d---e---f | " << "| " << c[3] << "---" << c[4] << "---" << c[5] << " |"; - cout << "\n | | | | | " << "| | | | |"; - cout << "\n | | g-h-i | | " << "| | " << c[6] << "-" << c[7] << "-" << c[8] << " | |"; - cout << "\n | | | | | | | " << "| | | | | |"; + cout << "\n | | | " + << "| | |"; + cout << "\n | d---e---f | " + << "| " << c[3] << "---" << c[4] << "---" << c[5] << " |"; + cout << "\n | | | | | " + << "| | | | |"; + cout << "\n | | g-h-i | | " + << "| | " << c[6] << "-" << c[7] << "-" << c[8] << " | |"; + cout << "\n | | | | | | | " + << "| | | | | |"; cout << "\n j-k-l m-n-o " << c[9] << "-" << c[10] << "-" << c[11] << " " << c[12] << "-" << c[13] << "-" << c[14]; - cout << "\n | | | | | | | " << "| | | | | |"; - cout << "\n | | p-q-r | | " << "| | " << c[15] << "-" << c[16] << "-" << c[17] << " | |"; - cout << "\n | | | | | " << "| | | | |"; - cout << "\n | s---t---u | " << "| " << c[18] << "---" << c[19] << "---" << c[20] << " |"; - cout << "\n | | | " << "| | |"; + cout << "\n | | | | | | | " + << "| | | | | |"; + cout << "\n | | p-q-r | | " + << "| | " << c[15] << "-" << c[16] << "-" << c[17] << " | |"; + cout << "\n | | | | | " + << "| | | | |"; + cout << "\n | s---t---u | " + << "| " << c[18] << "---" << c[19] << "---" << c[20] << " |"; + cout << "\n | | | " + << "| | |"; cout << "\n v-----w-----x " << c[21] << "-----" << c[22] << "-----" << c[23]; cout << "\n"; } //----------------------------------------------------------------------------- // Name: GetCharFromStone() -// Desc: +// Desc: //----------------------------------------------------------------------------- char fieldStruct::GetCharFromStone(int stone) { - switch (stone) { - case fieldStruct::playerOne: return 'o'; - case fieldStruct::playerTwo: return 'x'; - case fieldStruct::playerOneWarning: return '1'; - case fieldStruct::playerTwoWarning: return '2'; - case fieldStruct::playerBothWarning: return '3'; - case fieldStruct::squareIsFree: return ' '; + switch (stone) + { + case fieldStruct::playerOne: + return 'o'; + case fieldStruct::playerTwo: + return 'x'; + case fieldStruct::playerOneWarning: + return '1'; + case fieldStruct::playerTwoWarning: + return '2'; + case fieldStruct::playerBothWarning: + return '3'; + case fieldStruct::squareIsFree: + return ' '; } return 'f'; } @@ -75,13 +93,15 @@ void fieldStruct::copyBoard(fieldStruct *destination) destination->settingPhase = this->settingPhase; destination->stoneMustBeRemoved = this->stoneMustBeRemoved; - for (i = 0; i < this->size; i++) { + for (i = 0; i < this->size; i++) + { destination->board[i] = this->board[i]; destination->warnings[i] = this->warnings[i]; destination->stonePartOfMill[i] = this->stonePartOfMill[i]; - for (j = 0; j < 4; j++) { + for (j = 0; j < 4; j++) + { destination->connectedSquare[i][j] = this->connectedSquare[i][j]; destination->stoneMoveAble[i][j] = this->stoneMoveAble[i][j]; @@ -104,11 +124,12 @@ void Player::copyPlayer(Player *destination) destination->warning = this->warning; destination->numPossibleMoves = this->numPossibleMoves; - for (i = 0; i < MAX_NUM_POS_MOVES; i++) destination->posFrom[i] = this->posFrom[i]; - for (i = 0; i < MAX_NUM_POS_MOVES; i++) destination->posTo[i] = this->posTo[i]; + for (i = 0; i < MAX_NUM_POS_MOVES; i++) + destination->posFrom[i] = this->posFrom[i]; + for (i = 0; i < MAX_NUM_POS_MOVES; i++) + destination->posTo[i] = this->posTo[i]; } - //----------------------------------------------------------------------------- // Name: createBoard() // Desc: Creates, but doesn't initialize, the arrays of the of the passed board structure. @@ -136,7 +157,8 @@ void fieldStruct::createBoard() oppPlayer->numStonesMissing = 0; // zero - for (i = 0; i < size; i++) { + for (i = 0; i < size; i++) + { board[i] = squareIsFree; warnings[i] = noWarning; stonePartOfMill[i] = 0; @@ -203,7 +225,7 @@ void fieldStruct::createBoard() //----------------------------------------------------------------------------- // Name: deleteBoard() -// Desc: ... +// Desc: ... //----------------------------------------------------------------------------- void fieldStruct::deleteBoard() { @@ -213,7 +235,7 @@ void fieldStruct::deleteBoard() //----------------------------------------------------------------------------- // Name: setConnection() -// Desc: +// Desc: //----------------------------------------------------------------------------- inline void fieldStruct::setConnection(unsigned int index, int firstDirection, int secondDirection, int thirdDirection, int fourthDirection) { @@ -225,7 +247,7 @@ inline void fieldStruct::setConnection(unsigned int index, int firstDirection, i //----------------------------------------------------------------------------- // Name: setNeighbour() -// Desc: +// Desc: //----------------------------------------------------------------------------- inline void fieldStruct::setNeighbour(unsigned int index, unsigned int firstNeighbour0, unsigned int secondNeighbour0, unsigned int firstNeighbour1, unsigned int secondNeighbour1) { diff --git a/src/perfect/millAI.h b/src/perfect/millAI.h index 4edfdf47..c6d57256 100644 --- a/src/perfect/millAI.h +++ b/src/perfect/millAI.h @@ -15,72 +15,78 @@ //using namespace std; /*** Konstanten ******************************************************/ -#define MAX_NUM_POS_MOVES (3 * 18) // not (9 * 4) = 36 since the possibilities with 3 stones are more -#define SAFE_DELETE(p) { if(p) { delete (p); (p)=nullptr; } } +#define MAX_NUM_POS_MOVES (3 * 18) // not (9 * 4) = 36 since the possibilities with 3 stones are more +#define SAFE_DELETE(p) \ + { \ + if (p) \ + { \ + delete (p); \ + (p) = nullptr; \ + } \ + } /*** Klassen *********************************************************/ class Player { public: - int id; // static - unsigned int warning; // static - unsigned int numStones; // number of stones of this player on the board - unsigned int numStonesMissing; // number of stones, which where stolen by the opponent - unsigned int numPossibleMoves; // amount of possible moves - unsigned int posTo[MAX_NUM_POS_MOVES]; // target board position of a possible move - unsigned int posFrom[MAX_NUM_POS_MOVES]; // source board position of a possible move + int id; // static + unsigned int warning; // static + unsigned int numStones; // number of stones of this player on the board + unsigned int numStonesMissing; // number of stones, which where stolen by the opponent + unsigned int numPossibleMoves; // amount of possible moves + unsigned int posTo[MAX_NUM_POS_MOVES]; // target board position of a possible move + unsigned int posFrom[MAX_NUM_POS_MOVES]; // source board position of a possible move - void copyPlayer(Player *destination); + void copyPlayer(Player *destination); }; class fieldStruct { public: // constants - static const int squareIsFree = 0; // trivial - static const int playerOne = -1; // so rowOwner can be calculated easy - static const int playerTwo = 1; - static const int playerBlack = -1; // so rowOwner can be calculated easy - static const int playerWhite = 1; - static const unsigned int noWarning = 0; // so the bitwise or-operation can be applied, without interacting with playerOne & Two - static const unsigned int playerOneWarning = 2; - static const unsigned int playerTwoWarning = 4; - static const unsigned int playerBothWarning = 6; - static const unsigned int numStonesPerPlayer = 9; - static const unsigned int size = 24; // number of squares - static const int gameDrawn = 3; // only a nonzero value + static const int squareIsFree = 0; // trivial + static const int playerOne = -1; // so rowOwner can be calculated easy + static const int playerTwo = 1; + static const int playerBlack = -1; // so rowOwner can be calculated easy + static const int playerWhite = 1; + static const unsigned int noWarning = 0; // so the bitwise or-operation can be applied, without interacting with playerOne & Two + static const unsigned int playerOneWarning = 2; + static const unsigned int playerTwoWarning = 4; + static const unsigned int playerBothWarning = 6; + static const unsigned int numStonesPerPlayer = 9; + static const unsigned int size = 24; // number of squares + static const int gameDrawn = 3; // only a nonzero value // variables - int board[size]; // one of the values above for each board position - unsigned int warnings[size]; // array containing the warnings for each board position - bool stoneMoveAble[size][4]; // true if stone can be moved in this direction - unsigned int stonePartOfMill[size]; // the number of mills, of which this stone is part of - unsigned int connectedSquare[size][4]; // static array containg the index of the neighbour or "size" - unsigned int neighbour[size][2][2]; // static array containing the two neighbours of each squares - unsigned int stonesSet; // number of stones set in the setting phase - bool settingPhase; // true if stonesSet < 18 - unsigned int stoneMustBeRemoved; // number of stones which must be removed by the current player - Player *curPlayer, *oppPlayer; // pointers to the current and opponent player + int board[size]; // one of the values above for each board position + unsigned int warnings[size]; // array containing the warnings for each board position + bool stoneMoveAble[size][4]; // true if stone can be moved in this direction + unsigned int stonePartOfMill[size]; // the number of mills, of which this stone is part of + unsigned int connectedSquare[size][4]; // static array containg the index of the neighbour or "size" + unsigned int neighbour[size][2][2]; // static array containing the two neighbours of each squares + unsigned int stonesSet; // number of stones set in the setting phase + bool settingPhase; // true if stonesSet < 18 + unsigned int stoneMustBeRemoved; // number of stones which must be removed by the current player + Player *curPlayer, *oppPlayer; // pointers to the current and opponent player // useful functions - void printBoard(); - void copyBoard(fieldStruct *destination); - void createBoard(); - void deleteBoard(); + void printBoard(); + void copyBoard(fieldStruct *destination); + void createBoard(); + void deleteBoard(); private: - // helper functions - char GetCharFromStone(int stone); - void setConnection(unsigned int index, int firstDirection, int secondDirection, int thirdDirection, int fourthDirection); - void setNeighbour(unsigned int index, unsigned int firstNeighbour0, unsigned int secondNeighbour0, unsigned int firstNeighbour1, unsigned int secondNeighbour1); + char GetCharFromStone(int stone); + void setConnection(unsigned int index, int firstDirection, int secondDirection, int thirdDirection, int fourthDirection); + void setNeighbour(unsigned int index, unsigned int firstNeighbour0, unsigned int secondNeighbour0, unsigned int firstNeighbour1, unsigned int secondNeighbour1); }; class MillAI abstract { protected: - fieldStruct dummyField; + fieldStruct dummyField; public: // Constructor / destructor @@ -94,7 +100,7 @@ public: }; // Functions - virtual void play(fieldStruct *theField, unsigned int *pushFrom, unsigned int *pushTo) = 0; + virtual void play(fieldStruct *theField, unsigned int *pushFrom, unsigned int *pushTo) = 0; }; #endif diff --git a/src/perfect/minMaxKI.cpp b/src/perfect/minMaxKI.cpp index c728ce7d..9daa1536 100644 --- a/src/perfect/minMaxKI.cpp +++ b/src/perfect/minMaxKI.cpp @@ -27,7 +27,7 @@ MiniMaxAI::~MiniMaxAI() //----------------------------------------------------------------------------- // Name: play() -// Desc: +// Desc: //----------------------------------------------------------------------------- void MiniMaxAI::play(fieldStruct *theField, unsigned int *pushFrom, unsigned int *pushTo) { @@ -35,16 +35,23 @@ void MiniMaxAI::play(fieldStruct *theField, unsigned int *pushFrom, unsigned int field = theField; ownId = field->curPlayer->id; curSearchDepth = 0; - unsigned int bestChoice; - unsigned int searchDepth; + unsigned int bestChoice; + unsigned int searchDepth; // automatic depth - if (depthOfFullTree == 0) { - if (theField->settingPhase) searchDepth = 5; - else if (theField->curPlayer->numStones <= 4) searchDepth = 7; - else if (theField->oppPlayer->numStones <= 4) searchDepth = 7; - else searchDepth = 7; - } else { + if (depthOfFullTree == 0) + { + if (theField->settingPhase) + searchDepth = 5; + else if (theField->curPlayer->numStones <= 4) + searchDepth = 7; + else if (theField->oppPlayer->numStones <= 4) + searchDepth = 7; + else + searchDepth = 7; + } + else + { searchDepth = depthOfFullTree; } @@ -60,11 +67,18 @@ void MiniMaxAI::play(fieldStruct *theField, unsigned int *pushFrom, unsigned int Possibility *rootPossibilities = (Possibility *)getBestChoice(searchDepth, &bestChoice, MAX_NUM_POS_MOVES); // decode the best choice - if (field->stoneMustBeRemoved) { - *pushFrom = bestChoice; *pushTo = 0; - } else if (field->settingPhase) { - *pushFrom = 0; *pushTo = bestChoice; - } else { + if (field->stoneMustBeRemoved) + { + *pushFrom = bestChoice; + *pushTo = 0; + } + else if (field->settingPhase) + { + *pushFrom = 0; + *pushTo = bestChoice; + } + else + { *pushFrom = rootPossibilities->from[bestChoice]; *pushTo = rootPossibilities->to[bestChoice]; } @@ -80,7 +94,7 @@ void MiniMaxAI::play(fieldStruct *theField, unsigned int *pushFrom, unsigned int //----------------------------------------------------------------------------- // Name: setSearchDepth() -// Desc: +// Desc: //----------------------------------------------------------------------------- void MiniMaxAI::setSearchDepth(unsigned int depth) { @@ -89,7 +103,7 @@ void MiniMaxAI::setSearchDepth(unsigned int depth) //----------------------------------------------------------------------------- // Name: prepareBestChoiceCalculation() -// Desc: +// Desc: //----------------------------------------------------------------------------- void MiniMaxAI::prepareBestChoiceCalculation() { @@ -100,7 +114,7 @@ void MiniMaxAI::prepareBestChoiceCalculation() //----------------------------------------------------------------------------- // Name: getPossSettingPhase() -// Desc: +// Desc: //----------------------------------------------------------------------------- unsigned int *MiniMaxAI::getPossSettingPhase(unsigned int *numPossibilities, void **pPossibilities) { @@ -109,10 +123,12 @@ unsigned int *MiniMaxAI::getPossSettingPhase(unsigned int *numPossibilities, voi unsigned int *idPossibility = &idPossibilities[curSearchDepth * MAX_NUM_POS_MOVES]; // possibilities with cut off - for ((*numPossibilities) = 0, i = 0; i < field->size; i++) { + for ((*numPossibilities) = 0, i = 0; i < field->size; i++) + { // move possible ? - if (field->board[i] == field->squareIsFree) { + if (field->board[i] == field->squareIsFree) + { idPossibility[*numPossibilities] = i; (*numPossibilities)++; @@ -127,26 +143,30 @@ unsigned int *MiniMaxAI::getPossSettingPhase(unsigned int *numPossibilities, voi //----------------------------------------------------------------------------- // Name: getPossNormalMove() -// Desc: +// Desc: //----------------------------------------------------------------------------- unsigned int *MiniMaxAI::getPossNormalMove(unsigned int *numPossibilities, void **pPossibilities) { // locals - unsigned int from, to, dir; + unsigned int from, to, dir; unsigned int *idPossibility = &idPossibilities[curSearchDepth * MAX_NUM_POS_MOVES]; Possibility *possibility = &possibilities[curSearchDepth]; // if he is not allowed to spring - if (field->curPlayer->numStones > 3) { + if (field->curPlayer->numStones > 3) + { - for ((*numPossibilities) = 0, from = 0; from < field->size; from++) { - for (dir = 0; dir < 4; dir++) { + for ((*numPossibilities) = 0, from = 0; from < field->size; from++) + { + for (dir = 0; dir < 4; dir++) + { - // destination + // destination to = field->connectedSquare[from][dir]; // move possible ? - if (to < field->size && field->board[from] == field->curPlayer->id && field->board[to] == field->squareIsFree) { + if (to < field->size && field->board[from] == field->curPlayer->id && field->board[to] == field->squareIsFree) + { // stone is moveable idPossibility[*numPossibilities] = *numPossibilities; @@ -158,13 +178,18 @@ unsigned int *MiniMaxAI::getPossNormalMove(unsigned int *numPossibilities, void } } } - } else { + } + else + { - for ((*numPossibilities) = 0, from = 0; from < field->size; from++) { - for (to = 0; to < field->size; to++) { + for ((*numPossibilities) = 0, from = 0; from < field->size; from++) + { + for (to = 0; to < field->size; to++) + { // move possible ? - if (field->board[from] == field->curPlayer->id && field->board[to] == field->squareIsFree && *numPossibilities < MAX_NUM_POS_MOVES) { + if (field->board[from] == field->curPlayer->id && field->board[to] == field->squareIsFree && *numPossibilities < MAX_NUM_POS_MOVES) + { // stone is moveable idPossibility[*numPossibilities] = *numPossibilities; @@ -184,7 +209,7 @@ unsigned int *MiniMaxAI::getPossNormalMove(unsigned int *numPossibilities, void //----------------------------------------------------------------------------- // Name: getPossStoneRemove() -// Desc: +// Desc: //----------------------------------------------------------------------------- unsigned int *MiniMaxAI::getPossStoneRemove(unsigned int *numPossibilities, void **pPossibilities) { @@ -193,10 +218,12 @@ unsigned int *MiniMaxAI::getPossStoneRemove(unsigned int *numPossibilities, void unsigned int *idPossibility = &idPossibilities[curSearchDepth * MAX_NUM_POS_MOVES]; // possibilities with cut off - for ((*numPossibilities) = 0, i = 0; i < field->size; i++) { + for ((*numPossibilities) = 0, i = 0; i < field->size; i++) + { // move possible ? - if (field->board[i] == field->oppPlayer->id && !field->stonePartOfMill[i]) { + if (field->board[i] == field->oppPlayer->id && !field->stonePartOfMill[i]) + { idPossibility[*numPossibilities] = i; (*numPossibilities)++; @@ -211,7 +238,7 @@ unsigned int *MiniMaxAI::getPossStoneRemove(unsigned int *numPossibilities, void //----------------------------------------------------------------------------- // Name: getPossibilities() -// Desc: +// Desc: //----------------------------------------------------------------------------- unsigned int *MiniMaxAI::getPossibilities(unsigned int threadNo, unsigned int *numPossibilities, bool *opponentsMove, void **pPossibilities) { @@ -219,20 +246,26 @@ unsigned int *MiniMaxAI::getPossibilities(unsigned int threadNo, unsigned int *n *opponentsMove = (field->curPlayer->id == ownId) ? false : true; // When game has ended of course nothing happens any more - if (gameHasFinished) { + if (gameHasFinished) + { *numPossibilities = 0; return 0; // look what is to do - } else { - if (field->stoneMustBeRemoved) return getPossStoneRemove(numPossibilities, pPossibilities); - else if (field->settingPhase) return getPossSettingPhase(numPossibilities, pPossibilities); - else return getPossNormalMove(numPossibilities, pPossibilities); + } + else + { + if (field->stoneMustBeRemoved) + return getPossStoneRemove(numPossibilities, pPossibilities); + else if (field->settingPhase) + return getPossSettingPhase(numPossibilities, pPossibilities); + else + return getPossNormalMove(numPossibilities, pPossibilities); } } //----------------------------------------------------------------------------- // Name: getValueOfSituation() -// Desc: +// Desc: //----------------------------------------------------------------------------- void MiniMaxAI::getValueOfSituation(unsigned int threadNo, float &floatValue, TwoBit &shortValue) { @@ -242,7 +275,7 @@ void MiniMaxAI::getValueOfSituation(unsigned int threadNo, float &floatValue, Tw //----------------------------------------------------------------------------- // Name: deletePossibilities() -// Desc: +// Desc: //----------------------------------------------------------------------------- void MiniMaxAI::deletePossibilities(unsigned int threadNo, void *pPossibilities) { @@ -250,7 +283,7 @@ void MiniMaxAI::deletePossibilities(unsigned int threadNo, void *pPossibilities) //----------------------------------------------------------------------------- // Name: undo() -// Desc: +// Desc: //----------------------------------------------------------------------------- void MiniMaxAI::undo(unsigned int threadNo, unsigned int idPossibility, bool opponentsMove, void *pBackup, void *pPossibilities) { @@ -277,7 +310,8 @@ void MiniMaxAI::undo(unsigned int threadNo, unsigned int idPossibility, bool opp field->board[oldState->to] = oldState->fieldTo; // very expensive - for (int i = 0; i < field->size; i++) { + for (int i = 0; i < field->size; i++) + { field->stonePartOfMill[i] = oldState->stonePartOfMill[i]; field->warnings[i] = oldState->warnings[i]; } @@ -285,12 +319,13 @@ void MiniMaxAI::undo(unsigned int threadNo, unsigned int idPossibility, bool opp //----------------------------------------------------------------------------- // Name: setWarning() -// Desc: +// Desc: //----------------------------------------------------------------------------- inline void MiniMaxAI::setWarning(unsigned int stoneOne, unsigned int stoneTwo, unsigned int stoneThree) { // if all 3 fields are occupied by current player than he closed a mill - if (field->board[stoneOne] == field->curPlayer->id && field->board[stoneTwo] == field->curPlayer->id && field->board[stoneThree] == field->curPlayer->id) { + if (field->board[stoneOne] == field->curPlayer->id && field->board[stoneTwo] == field->curPlayer->id && field->board[stoneThree] == field->curPlayer->id) + { field->stonePartOfMill[stoneOne]++; field->stonePartOfMill[stoneTwo]++; @@ -299,7 +334,8 @@ inline void MiniMaxAI::setWarning(unsigned int stoneOne, unsigned int stoneTwo, } // is a mill destroyed ? - if (field->board[stoneOne] == field->squareIsFree && field->stonePartOfMill[stoneOne] && field->stonePartOfMill[stoneTwo] && field->stonePartOfMill[stoneThree]) { + if (field->board[stoneOne] == field->squareIsFree && field->stonePartOfMill[stoneOne] && field->stonePartOfMill[stoneTwo] && field->stonePartOfMill[stoneThree]) + { field->stonePartOfMill[stoneOne]--; field->stonePartOfMill[stoneTwo]--; @@ -307,116 +343,159 @@ inline void MiniMaxAI::setWarning(unsigned int stoneOne, unsigned int stoneTwo, } // stone was set - if (field->board[stoneOne] == field->curPlayer->id) { + if (field->board[stoneOne] == field->curPlayer->id) + { // a warnig was destroyed field->warnings[stoneOne] = field->noWarning; // a warning is created - if (field->board[stoneTwo] == field->curPlayer->id && field->board[stoneThree] == field->squareIsFree) field->warnings[stoneThree] |= field->curPlayer->warning; - if (field->board[stoneThree] == field->curPlayer->id && field->board[stoneTwo] == field->squareIsFree) field->warnings[stoneTwo] |= field->curPlayer->warning; + if (field->board[stoneTwo] == field->curPlayer->id && field->board[stoneThree] == field->squareIsFree) + field->warnings[stoneThree] |= field->curPlayer->warning; + if (field->board[stoneThree] == field->curPlayer->id && field->board[stoneTwo] == field->squareIsFree) + field->warnings[stoneTwo] |= field->curPlayer->warning; // stone was removed - } else if (field->board[stoneOne] == field->squareIsFree) { + } + else if (field->board[stoneOne] == field->squareIsFree) + { // a warning is created - if (field->board[stoneTwo] == field->curPlayer->id && field->board[stoneThree] == field->curPlayer->id) field->warnings[stoneOne] |= field->curPlayer->warning; - if (field->board[stoneTwo] == field->oppPlayer->id && field->board[stoneThree] == field->oppPlayer->id) field->warnings[stoneOne] |= field->oppPlayer->warning; + if (field->board[stoneTwo] == field->curPlayer->id && field->board[stoneThree] == field->curPlayer->id) + field->warnings[stoneOne] |= field->curPlayer->warning; + if (field->board[stoneTwo] == field->oppPlayer->id && field->board[stoneThree] == field->oppPlayer->id) + field->warnings[stoneOne] |= field->oppPlayer->warning; // a warning is destroyed - if (field->warnings[stoneTwo] && field->board[stoneThree] != field->squareIsFree) { + if (field->warnings[stoneTwo] && field->board[stoneThree] != field->squareIsFree) + { // reset warning if necessary - if (field->board[field->neighbour[stoneTwo][0][0]] == field->curPlayer->id && field->board[field->neighbour[stoneTwo][0][1]] == field->curPlayer->id) field->warnings[stoneTwo] = field->curPlayer->warning; - else if (field->board[field->neighbour[stoneTwo][1][0]] == field->curPlayer->id && field->board[field->neighbour[stoneTwo][1][1]] == field->curPlayer->id) field->warnings[stoneTwo] = field->curPlayer->warning; - else if (field->board[field->neighbour[stoneTwo][0][0]] == field->oppPlayer->id && field->board[field->neighbour[stoneTwo][0][1]] == field->oppPlayer->id) field->warnings[stoneTwo] = field->oppPlayer->warning; - else if (field->board[field->neighbour[stoneTwo][1][0]] == field->oppPlayer->id && field->board[field->neighbour[stoneTwo][1][1]] == field->oppPlayer->id) field->warnings[stoneTwo] = field->oppPlayer->warning; - else field->warnings[stoneTwo] = field->noWarning; - - } else if (field->warnings[stoneThree] && field->board[stoneTwo] != field->squareIsFree) { + if (field->board[field->neighbour[stoneTwo][0][0]] == field->curPlayer->id && field->board[field->neighbour[stoneTwo][0][1]] == field->curPlayer->id) + field->warnings[stoneTwo] = field->curPlayer->warning; + else if (field->board[field->neighbour[stoneTwo][1][0]] == field->curPlayer->id && field->board[field->neighbour[stoneTwo][1][1]] == field->curPlayer->id) + field->warnings[stoneTwo] = field->curPlayer->warning; + else if (field->board[field->neighbour[stoneTwo][0][0]] == field->oppPlayer->id && field->board[field->neighbour[stoneTwo][0][1]] == field->oppPlayer->id) + field->warnings[stoneTwo] = field->oppPlayer->warning; + else if (field->board[field->neighbour[stoneTwo][1][0]] == field->oppPlayer->id && field->board[field->neighbour[stoneTwo][1][1]] == field->oppPlayer->id) + field->warnings[stoneTwo] = field->oppPlayer->warning; + else + field->warnings[stoneTwo] = field->noWarning; + } + else if (field->warnings[stoneThree] && field->board[stoneTwo] != field->squareIsFree) + { // reset warning if necessary - if (field->board[field->neighbour[stoneThree][0][0]] == field->curPlayer->id && field->board[field->neighbour[stoneThree][0][1]] == field->curPlayer->id) field->warnings[stoneThree] = field->curPlayer->warning; - else if (field->board[field->neighbour[stoneThree][1][0]] == field->curPlayer->id && field->board[field->neighbour[stoneThree][1][1]] == field->curPlayer->id) field->warnings[stoneThree] = field->curPlayer->warning; - else if (field->board[field->neighbour[stoneThree][0][0]] == field->oppPlayer->id && field->board[field->neighbour[stoneThree][0][1]] == field->oppPlayer->id) field->warnings[stoneThree] = field->oppPlayer->warning; - else if (field->board[field->neighbour[stoneThree][1][0]] == field->oppPlayer->id && field->board[field->neighbour[stoneThree][1][1]] == field->oppPlayer->id) field->warnings[stoneThree] = field->oppPlayer->warning; - else field->warnings[stoneThree] = field->noWarning; + if (field->board[field->neighbour[stoneThree][0][0]] == field->curPlayer->id && field->board[field->neighbour[stoneThree][0][1]] == field->curPlayer->id) + field->warnings[stoneThree] = field->curPlayer->warning; + else if (field->board[field->neighbour[stoneThree][1][0]] == field->curPlayer->id && field->board[field->neighbour[stoneThree][1][1]] == field->curPlayer->id) + field->warnings[stoneThree] = field->curPlayer->warning; + else if (field->board[field->neighbour[stoneThree][0][0]] == field->oppPlayer->id && field->board[field->neighbour[stoneThree][0][1]] == field->oppPlayer->id) + field->warnings[stoneThree] = field->oppPlayer->warning; + else if (field->board[field->neighbour[stoneThree][1][0]] == field->oppPlayer->id && field->board[field->neighbour[stoneThree][1][1]] == field->oppPlayer->id) + field->warnings[stoneThree] = field->oppPlayer->warning; + else + field->warnings[stoneThree] = field->noWarning; } } } //----------------------------------------------------------------------------- // Name: updateWarning() -// Desc: +// Desc: //----------------------------------------------------------------------------- inline void MiniMaxAI::updateWarning(unsigned int firstStone, unsigned int secondStone) { // set warnings - if (firstStone < field->size) setWarning(firstStone, field->neighbour[firstStone][0][0], field->neighbour[firstStone][0][1]); - if (firstStone < field->size) setWarning(firstStone, field->neighbour[firstStone][1][0], field->neighbour[firstStone][1][1]); + if (firstStone < field->size) + setWarning(firstStone, field->neighbour[firstStone][0][0], field->neighbour[firstStone][0][1]); + if (firstStone < field->size) + setWarning(firstStone, field->neighbour[firstStone][1][0], field->neighbour[firstStone][1][1]); - if (secondStone < field->size) setWarning(secondStone, field->neighbour[secondStone][0][0], field->neighbour[secondStone][0][1]); - if (secondStone < field->size) setWarning(secondStone, field->neighbour[secondStone][1][0], field->neighbour[secondStone][1][1]); + if (secondStone < field->size) + setWarning(secondStone, field->neighbour[secondStone][0][0], field->neighbour[secondStone][0][1]); + if (secondStone < field->size) + setWarning(secondStone, field->neighbour[secondStone][1][0], field->neighbour[secondStone][1][1]); // no stone must be removed if each belongs to a mill - unsigned int i; - bool atLeastOneStoneRemoveAble = false; - if (field->stoneMustBeRemoved) for (i = 0; i < field->size; i++) if (field->stonePartOfMill[i] == 0 && field->board[i] == field->oppPlayer->id) { - atLeastOneStoneRemoveAble = true; break; - } - if (!atLeastOneStoneRemoveAble) field->stoneMustBeRemoved = 0; + unsigned int i; + bool atLeastOneStoneRemoveAble = false; + if (field->stoneMustBeRemoved) + for (i = 0; i < field->size; i++) + if (field->stonePartOfMill[i] == 0 && field->board[i] == field->oppPlayer->id) + { + atLeastOneStoneRemoveAble = true; + break; + } + if (!atLeastOneStoneRemoveAble) + field->stoneMustBeRemoved = 0; } //----------------------------------------------------------------------------- // Name: updatePossibleMoves() -// Desc: +// Desc: //----------------------------------------------------------------------------- inline void MiniMaxAI::updatePossibleMoves(unsigned int stone, Player *stoneOwner, bool stoneRemoved, unsigned int ignoreStone) { // locals - unsigned int neighbor, direction; + unsigned int neighbor, direction; // look into every direction - for (direction = 0; direction < 4; direction++) { + for (direction = 0; direction < 4; direction++) + { neighbor = field->connectedSquare[stone][direction]; // neighbor must exist - if (neighbor < field->size) { + if (neighbor < field->size) + { // relevant when moving from one square to another connected square - if (ignoreStone == neighbor) continue; + if (ignoreStone == neighbor) + continue; // if there is no neighbour stone than it only affects the actual stone - if (field->board[neighbor] == field->squareIsFree) { + if (field->board[neighbor] == field->squareIsFree) + { - if (stoneRemoved) stoneOwner->numPossibleMoves--; - else stoneOwner->numPossibleMoves++; + if (stoneRemoved) + stoneOwner->numPossibleMoves--; + else + stoneOwner->numPossibleMoves++; // if there is a neighbour stone than it effects only this one - } else if (field->board[neighbor] == field->curPlayer->id) { + } + else if (field->board[neighbor] == field->curPlayer->id) + { - if (stoneRemoved) field->curPlayer->numPossibleMoves++; - else field->curPlayer->numPossibleMoves--; + if (stoneRemoved) + field->curPlayer->numPossibleMoves++; + else + field->curPlayer->numPossibleMoves--; + } + else + { - } else { - - if (stoneRemoved) field->oppPlayer->numPossibleMoves++; - else field->oppPlayer->numPossibleMoves--; + if (stoneRemoved) + field->oppPlayer->numPossibleMoves++; + else + field->oppPlayer->numPossibleMoves--; } } } // only 3 stones resting - if (field->curPlayer->numStones <= 3 && !field->settingPhase) field->curPlayer->numPossibleMoves = field->curPlayer->numStones * (field->size - field->curPlayer->numStones - field->oppPlayer->numStones); - if (field->oppPlayer->numStones <= 3 && !field->settingPhase) field->oppPlayer->numPossibleMoves = field->oppPlayer->numStones * (field->size - field->curPlayer->numStones - field->oppPlayer->numStones); + if (field->curPlayer->numStones <= 3 && !field->settingPhase) + field->curPlayer->numPossibleMoves = field->curPlayer->numStones * (field->size - field->curPlayer->numStones - field->oppPlayer->numStones); + if (field->oppPlayer->numStones <= 3 && !field->settingPhase) + field->oppPlayer->numPossibleMoves = field->oppPlayer->numStones * (field->size - field->curPlayer->numStones - field->oppPlayer->numStones); } //----------------------------------------------------------------------------- // Name: setStone() -// Desc: +// Desc: //----------------------------------------------------------------------------- -inline void MiniMaxAI::setStone(unsigned int to, Backup *backup) +inline void MiniMaxAI::setStone(unsigned int to, Backup *backup) { // backup backup->from = field->size; @@ -430,7 +509,8 @@ inline void MiniMaxAI::setStone(unsigned int to, Backup *backup) field->stonesSet++; // setting phase finished ? - if (field->stonesSet == 18) field->settingPhase = false; + if (field->stonesSet == 18) + field->settingPhase = false; // update possible moves updatePossibleMoves(to, field->curPlayer, false, field->size); @@ -441,9 +521,9 @@ inline void MiniMaxAI::setStone(unsigned int to, Backup *backup) //----------------------------------------------------------------------------- // Name: normalMove() -// Desc: +// Desc: //----------------------------------------------------------------------------- -inline void MiniMaxAI::normalMove(unsigned int from, unsigned int to, Backup *backup) +inline void MiniMaxAI::normalMove(unsigned int from, unsigned int to, Backup *backup) { // backup backup->from = from; @@ -465,7 +545,7 @@ inline void MiniMaxAI::normalMove(unsigned int from, unsigned int to, Backup *ba //----------------------------------------------------------------------------- // Name: removeStone() -// Desc: +// Desc: //----------------------------------------------------------------------------- inline void MiniMaxAI::removeStone(unsigned int from, Backup *backup) { @@ -488,12 +568,13 @@ inline void MiniMaxAI::removeStone(unsigned int from, Backup *backup) updateWarning(from, field->size); // end of game ? - if ((field->oppPlayer->numStones < 3) && (!field->settingPhase)) gameHasFinished = true; + if ((field->oppPlayer->numStones < 3) && (!field->settingPhase)) + gameHasFinished = true; } //----------------------------------------------------------------------------- // Name: move() -// Desc: +// Desc: //----------------------------------------------------------------------------- void MiniMaxAI::move(unsigned int threadNo, unsigned int idPossibility, bool opponentsMove, void **pBackup, void *pPossibilities) { @@ -501,7 +582,7 @@ void MiniMaxAI::move(unsigned int threadNo, unsigned int idPossibility, bool opp Backup *oldState = &oldStates[curSearchDepth]; Possibility *tmpPossibility = (Possibility *)pPossibilities; Player *tmpPlayer; - unsigned int i; + unsigned int i; // calculate place of stone *pBackup = (void *)oldState; @@ -521,33 +602,45 @@ void MiniMaxAI::move(unsigned int threadNo, unsigned int idPossibility, bool opp curSearchDepth++; // very expensive - for (i = 0; i < field->size; i++) { + for (i = 0; i < field->size; i++) + { oldState->stonePartOfMill[i] = field->stonePartOfMill[i]; oldState->warnings[i] = field->warnings[i]; } // move - if (field->stoneMustBeRemoved) { + if (field->stoneMustBeRemoved) + { removeStone(idPossibility, oldState); - } else if (field->settingPhase) { + } + else if (field->settingPhase) + { setStone(idPossibility, oldState); - } else { + } + else + { normalMove(tmpPossibility->from[idPossibility], tmpPossibility->to[idPossibility], oldState); } // when opponent is unable to move than current player has won - if ((!field->oppPlayer->numPossibleMoves) && (!field->settingPhase) && (!field->stoneMustBeRemoved) && (field->oppPlayer->numStones > 3)) gameHasFinished = true; + if ((!field->oppPlayer->numPossibleMoves) && (!field->settingPhase) && (!field->stoneMustBeRemoved) && (field->oppPlayer->numStones > 3)) + gameHasFinished = true; // calc value - if (!opponentsMove) currentValue = (float)field->oppPlayer->numStonesMissing - field->curPlayer->numStonesMissing + field->stoneMustBeRemoved + field->curPlayer->numPossibleMoves * 0.1f - field->oppPlayer->numPossibleMoves * 0.1f; - else currentValue = (float)field->curPlayer->numStonesMissing - field->oppPlayer->numStonesMissing - field->stoneMustBeRemoved + field->oppPlayer->numPossibleMoves * 0.1f - field->curPlayer->numPossibleMoves * 0.1f; + if (!opponentsMove) + currentValue = (float)field->oppPlayer->numStonesMissing - field->curPlayer->numStonesMissing + field->stoneMustBeRemoved + field->curPlayer->numPossibleMoves * 0.1f - field->oppPlayer->numPossibleMoves * 0.1f; + else + currentValue = (float)field->curPlayer->numStonesMissing - field->oppPlayer->numStonesMissing - field->stoneMustBeRemoved + field->oppPlayer->numPossibleMoves * 0.1f - field->curPlayer->numPossibleMoves * 0.1f; // when game has finished - perfect for the current player - if (gameHasFinished && !opponentsMove) currentValue = VALUE_GAME_WON - curSearchDepth; - if (gameHasFinished && opponentsMove) currentValue = VALUE_GAME_LOST + curSearchDepth; + if (gameHasFinished && !opponentsMove) + currentValue = VALUE_GAME_WON - curSearchDepth; + if (gameHasFinished && opponentsMove) + currentValue = VALUE_GAME_LOST + curSearchDepth; // set next player - if (!field->stoneMustBeRemoved) { + if (!field->stoneMustBeRemoved) + { tmpPlayer = field->curPlayer; field->curPlayer = field->oppPlayer; field->oppPlayer = tmpPlayer; @@ -556,7 +649,7 @@ void MiniMaxAI::move(unsigned int threadNo, unsigned int idPossibility, bool opp //----------------------------------------------------------------------------- // Name: printMoveInformation() -// Desc: +// Desc: //----------------------------------------------------------------------------- void MiniMaxAI::printMoveInformation(unsigned int threadNo, unsigned int idPossibility, void *pPossibilities) { @@ -564,7 +657,10 @@ void MiniMaxAI::printMoveInformation(unsigned int threadNo, unsigned int idPossi Possibility *tmpPossibility = (Possibility *)pPossibilities; // move - if (field->stoneMustBeRemoved) cout << "remove stone from " << (char)(idPossibility + 97); - else if (field->settingPhase) cout << "set stone to " << (char)(idPossibility + 97); - else cout << "move from " << (char)(tmpPossibility->from[idPossibility] + 97) << " to " << (char)(tmpPossibility->to[idPossibility] + 97); + if (field->stoneMustBeRemoved) + cout << "remove stone from " << (char)(idPossibility + 97); + else if (field->settingPhase) + cout << "set stone to " << (char)(idPossibility + 97); + else + cout << "move from " << (char)(tmpPossibility->from[idPossibility] + 97) << " to " << (char)(tmpPossibility->to[idPossibility] + 97); } diff --git a/src/perfect/miniMax.cpp b/src/perfect/miniMax.cpp index f60142f1..42398a40 100644 --- a/src/perfect/miniMax.cpp +++ b/src/perfect/miniMax.cpp @@ -44,12 +44,15 @@ MiniMax::MiniMax() numWriteSkvOperations = 0; numReadPlyOperations = 0; numWritePlyOperations = 0; - if (MEASURE_ONLY_IO) { + if (MEASURE_ONLY_IO) + { readSkvInterval.QuadPart = 0; writeSkvInterval.QuadPart = 0; readPlyInterval.QuadPart = 0; writePlyInterval.QuadPart = 0; - } else { + } + else + { QueryPerformanceCounter(&readSkvInterval); QueryPerformanceCounter(&writeSkvInterval); QueryPerformanceCounter(&readPlyInterval); @@ -61,11 +64,11 @@ MiniMax::MiniMax() // PL_TO_MOVE_CHANGED means that in the predecessor state the player to move has changed to the other player. // PL_TO_MOVE_UNCHANGED means that the player to move is still the one who shall move. unsigned char skvPerspectiveMatrixTmp[4][2] = { - // PL_TO_MOVE_UNCHANGED PL_TO_MOVE_CHANGED - SKV_VALUE_INVALID, SKV_VALUE_INVALID, // SKV_VALUE_INVALID - SKV_VALUE_GAME_WON, SKV_VALUE_GAME_LOST, // SKV_VALUE_GAME_LOST - SKV_VALUE_GAME_DRAWN, SKV_VALUE_GAME_DRAWN, // SKV_VALUE_GAME_DRAWN - SKV_VALUE_GAME_LOST, SKV_VALUE_GAME_WON // SKV_VALUE_GAME_WON + // PL_TO_MOVE_UNCHANGED PL_TO_MOVE_CHANGED + SKV_VALUE_INVALID, SKV_VALUE_INVALID, // SKV_VALUE_INVALID + SKV_VALUE_GAME_WON, SKV_VALUE_GAME_LOST, // SKV_VALUE_GAME_LOST + SKV_VALUE_GAME_DRAWN, SKV_VALUE_GAME_DRAWN, // SKV_VALUE_GAME_DRAWN + SKV_VALUE_GAME_LOST, SKV_VALUE_GAME_WON // SKV_VALUE_GAME_WON }; memcpy(skvPerspectiveMatrix, skvPerspectiveMatrixTmp, 4 * 2); @@ -84,11 +87,12 @@ MiniMax::~MiniMax() //----------------------------------------------------------------------------- // Name: falseOrStop() -// Desc: +// Desc: //----------------------------------------------------------------------------- bool MiniMax::falseOrStop() { - if (stopOnCriticalError) WaitForSingleObject(GetCurrentProcess(), INFINITE); + if (stopOnCriticalError) + WaitForSingleObject(GetCurrentProcess(), INFINITE); return false; } @@ -105,9 +109,9 @@ void *MiniMax::getBestChoice(unsigned int tilLevel, unsigned int *choice, unsign calcDatabase = false; // Locals - Node root; - AlphaBetaGlobalVars alphaBetaVars(this, getLayerNumber(0)); - RunAlphaBetaVars tva(this, &alphaBetaVars, alphaBetaVars.layerNumber); + Node root; + AlphaBetaGlobalVars alphaBetaVars(this, getLayerNumber(0)); + RunAlphaBetaVars tva(this, &alphaBetaVars, alphaBetaVars.layerNumber); srand((unsigned int)time(nullptr)); tva.curThreadNo = 0; @@ -131,7 +135,7 @@ void *MiniMax::getBestChoice(unsigned int tilLevel, unsigned int *choice, unsign void MiniMax::calculateDatabase(unsigned int maxDepthOfTree, bool onlyPrepareLayer) { // locals - bool abortCalculation = false; + bool abortCalculation = false; this->onlyPrepareLayer = onlyPrepareLayer; lastCalculatedLayer.clear(); @@ -143,7 +147,8 @@ void MiniMax::calculateDatabase(unsigned int maxDepthOfTree, bool onlyPrepareLay prepareDatabaseCalculation(); // when database not completed then do it - if (hFileShortKnotValues != nullptr && skvfHeader.completed == false) { + if (hFileShortKnotValues != nullptr && skvfHeader.completed == false) + { // reserve memory lastCalculatedLayer.clear(); @@ -154,13 +159,16 @@ void MiniMax::calculateDatabase(unsigned int maxDepthOfTree, bool onlyPrepareLay arrayInfos.vectorArrays.resize(ArrayInfo::numArrayTypes * skvfHeader.numLayers, arrayInfos.listArrays.end()); // calc layer after layer, beginning with the last one - for (curCalculatedLayer = 0; curCalculatedLayer < skvfHeader.numLayers; curCalculatedLayer++) { + for (curCalculatedLayer = 0; curCalculatedLayer < skvfHeader.numLayers; curCalculatedLayer++) + { // layer already calculated? - if (layerStats[curCalculatedLayer].layerIsCompletedAndInFile) continue; + if (layerStats[curCalculatedLayer].layerIsCompletedAndInFile) + continue; // don't calc if neither the layer nor the partner layer has any knots - if (layerStats[curCalculatedLayer].knotsInLayer == 0 && layerStats[layerStats[curCalculatedLayer].partnerLayer].knotsInLayer == 0) continue; + if (layerStats[curCalculatedLayer].knotsInLayer == 0 && layerStats[layerStats[curCalculatedLayer].partnerLayer].knotsInLayer == 0) + continue; // calc abortCalculation = (!calcLayer(curCalculatedLayer)); @@ -170,17 +178,21 @@ void MiniMax::calculateDatabase(unsigned int maxDepthOfTree, bool onlyPrepareLay unloadAllPlyInfos(); // don't save layer and header when only preparing layers - if (onlyPrepareLayer) return; - if (abortCalculation) break; + if (onlyPrepareLayer) + return; + if (abortCalculation) + break; // save header saveHeader(&skvfHeader, layerStats); saveHeader(&plyInfoHeader, plyInfos); } - // don't save layer and header when only preparing layers or when - if (onlyPrepareLayer) return; - if (!abortCalculation) { + // don't save layer and header when only preparing layers or when + if (onlyPrepareLayer) + return; + if (!abortCalculation) + { // calc layer statistics calcLayerStatistics("statistics.txt"); @@ -194,7 +206,9 @@ void MiniMax::calculateDatabase(unsigned int maxDepthOfTree, bool onlyPrepareLay // free mem curCalculationActionId = MM_ACTION_NONE; - } else { + } + else + { PRINT(1, this, "\nThe database is already fully calculated.\n"); } @@ -208,43 +222,53 @@ void MiniMax::calculateDatabase(unsigned int maxDepthOfTree, bool onlyPrepareLay //----------------------------------------------------------------------------- // Name: calcLayer() -// Desc: +// Desc: //----------------------------------------------------------------------------- bool MiniMax::calcLayer(unsigned int layerNumber) { // locals - vector layersToCalculate; + vector layersToCalculate; // moves can be done reverse, leading to too depth searching trees - if (shallRetroAnalysisBeUsed(layerNumber)) { + if (shallRetroAnalysisBeUsed(layerNumber)) + { // calc values for all states of layer layersToCalculate.push_back(layerNumber); - if (layerNumber != layerStats[layerNumber].partnerLayer) layersToCalculate.push_back(layerStats[layerNumber].partnerLayer); - if (!calcKnotValuesByRetroAnalysis(layersToCalculate)) return false; + if (layerNumber != layerStats[layerNumber].partnerLayer) + layersToCalculate.push_back(layerStats[layerNumber].partnerLayer); + if (!calcKnotValuesByRetroAnalysis(layersToCalculate)) + return false; // save partner layer - if (layerStats[layerNumber].partnerLayer != layerNumber) { + if (layerStats[layerNumber].partnerLayer != layerNumber) + { saveLayerToFile(layerStats[layerNumber].partnerLayer); } // use minimax-algorithm - } else { - if (!calcKnotValuesByAlphaBeta(layerNumber)) return false; + } + else + { + if (!calcKnotValuesByAlphaBeta(layerNumber)) + return false; } // save layer saveLayerToFile(layerNumber); // test layer - if (!testLayer(layerNumber)) { + if (!testLayer(layerNumber)) + { PRINT(0, this, "ERROR: Layer calculation cancelled or failed!" << endl); return false; } // test partner layer if retro-analysis has been used - if (shallRetroAnalysisBeUsed(layerNumber) && layerStats[layerNumber].partnerLayer != layerNumber) { - if (!testLayer(layerStats[layerNumber].partnerLayer)) { + if (shallRetroAnalysisBeUsed(layerNumber) && layerStats[layerNumber].partnerLayer != layerNumber) + { + if (!testLayer(layerStats[layerNumber].partnerLayer)) + { PRINT(0, this, "ERROR: Layer calculation cancelled or failed!" << endl); return false; } @@ -252,7 +276,8 @@ bool MiniMax::calcLayer(unsigned int layerNumber) // update output information EnterCriticalSection(&csOsPrint); - if (shallRetroAnalysisBeUsed(layerNumber) && layerNumber != layerStats[layerNumber].partnerLayer) { + if (shallRetroAnalysisBeUsed(layerNumber) && layerNumber != layerStats[layerNumber].partnerLayer) + { lastCalculatedLayer.push_back(layerStats[layerNumber].partnerLayer); } lastCalculatedLayer.push_back(layerNumber); @@ -263,7 +288,7 @@ bool MiniMax::calcLayer(unsigned int layerNumber) //----------------------------------------------------------------------------- // Name: pauseDatabaseCalculation() -// Desc: +// Desc: //----------------------------------------------------------------------------- void MiniMax::pauseDatabaseCalculation() { @@ -272,7 +297,7 @@ void MiniMax::pauseDatabaseCalculation() //----------------------------------------------------------------------------- // Name: cancelDatabaseCalculation() -// Desc: +// Desc: //----------------------------------------------------------------------------- void MiniMax::cancelDatabaseCalculation() { @@ -282,7 +307,7 @@ void MiniMax::cancelDatabaseCalculation() //----------------------------------------------------------------------------- // Name: wasDatabaseCalculationCancelled() -// Desc: +// Desc: //----------------------------------------------------------------------------- bool MiniMax::wasDatabaseCalculationCancelled() { diff --git a/src/perfect/miniMax.h b/src/perfect/miniMax.h index 1fb00daa..0296c394 100644 --- a/src/perfect/miniMax.h +++ b/src/perfect/miniMax.h @@ -24,9 +24,9 @@ #include "threadManager.h" #include "bufferedFile.h" -#pragma intrinsic(_rotl8, _rotr8) // for shifting bits +#pragma intrinsic(_rotl8, _rotr8) // for shifting bits -using namespace std; // use standard library namespace +using namespace std; // use standard library namespace /*** Wiki *************************************************************************************************************************** player: @@ -41,65 +41,82 @@ float point knot value: Each knot/state can be evaluated by a floating point val database: The database contains the arrays with the short knot values and the ply infos. /*** Constants ***************************************************************************************************************************/ -#define FPKV_MIN_VALUE -100000.0f // minimum float point knot value -#define FPKV_MAX_VALUE 100000.0f // maximum float point knot value -#define FPKV_THRESHOLD 0.001f // threshold used when choosing best move. knot values differing less than this threshold will be regarded as egal +#define FPKV_MIN_VALUE -100000.0f // minimum float point knot value +#define FPKV_MAX_VALUE 100000.0f // maximum float point knot value +#define FPKV_THRESHOLD 0.001f // threshold used when choosing best move. knot values differing less than this threshold will be regarded as egal -#define SKV_VALUE_INVALID 0 // short knot value: knot value is invalid -#define SKV_VALUE_GAME_LOST 1 // game lost means that there is no perfect move possible -#define SKV_VALUE_GAME_DRAWN 2 // the perfect move leads at least to a drawn game -#define SKV_VALUE_GAME_WON 3 // the perfect move will lead to a won game -#define SKV_MAX_VALUE 3 // highest short knot value -#define SKV_NUM_VALUES 4 // number of different short knot values -#define SKV_WHOLE_BYTE_IS_INVALID 0 // four short knot values are stored in one byte. so all four knot values are invalid +#define SKV_VALUE_INVALID 0 // short knot value: knot value is invalid +#define SKV_VALUE_GAME_LOST 1 // game lost means that there is no perfect move possible +#define SKV_VALUE_GAME_DRAWN 2 // the perfect move leads at least to a drawn game +#define SKV_VALUE_GAME_WON 3 // the perfect move will lead to a won game +#define SKV_MAX_VALUE 3 // highest short knot value +#define SKV_NUM_VALUES 4 // number of different short knot values +#define SKV_WHOLE_BYTE_IS_INVALID 0 // four short knot values are stored in one byte. so all four knot values are invalid -#define PLYINFO_EXP_VALUE 1000 // expected maximum number of plies -> user for vector initialization -#define PLYINFO_VALUE_DRAWN 65001 // knot value is drawn. since drawn means a never ending game, this is a special ply info -#define PLYINFO_VALUE_UNCALCULATED 65002 // ply info is not calculated yet for this game state -#define PLYINFO_VALUE_INVALID 65003 // ply info is invalid, since knot value is invalid +#define PLYINFO_EXP_VALUE 1000 // expected maximum number of plies -> user for vector initialization +#define PLYINFO_VALUE_DRAWN 65001 // knot value is drawn. since drawn means a never ending game, this is a special ply info +#define PLYINFO_VALUE_UNCALCULATED 65002 // ply info is not calculated yet for this game state +#define PLYINFO_VALUE_INVALID 65003 // ply info is invalid, since knot value is invalid -#define MAX_NUM_PRED_LAYERS 2 // each layer must have at maximum two preceding layers +#define MAX_NUM_PRED_LAYERS 2 // each layer must have at maximum two preceding layers -#define SKV_FILE_HEADER_CODE 0xF4F5 // constant to identify the header -#define PLYINFO_HEADER_CODE 0xF3F2 // '' +#define SKV_FILE_HEADER_CODE 0xF4F5 // constant to identify the header +#define PLYINFO_HEADER_CODE 0xF3F2 // '' -#define OUTPUT_EVERY_N_STATES 10000000 // print progress every n-th processed knot -#define BLOCK_SIZE_IN_CYCLIC_ARRAY 10000 // BLOCK_SIZE_IN_CYCLIC_ARRAY*sizeof(stateAdressStruct) = block size in bytes for the cyclic arrays -#define MAX_NUM_PREDECESSORS 10000 // maximum number of predecessors. important for array sizes -#define FILE_BUFFER_SIZE 1000000 // size in bytes +#define OUTPUT_EVERY_N_STATES 10000000 // print progress every n-th processed knot +#define BLOCK_SIZE_IN_CYCLIC_ARRAY 10000 // BLOCK_SIZE_IN_CYCLIC_ARRAY*sizeof(stateAdressStruct) = block size in bytes for the cyclic arrays +#define MAX_NUM_PREDECESSORS 10000 // maximum number of predecessors. important for array sizes +#define FILE_BUFFER_SIZE 1000000 // size in bytes -#define PL_TO_MOVE_CHANGED 1 // player to move changed - second index of the 2D-array skvPerspectiveMatrix[][] -#define PL_TO_MOVE_UNCHANGED 0 // player to move is still the same - second index of the 2D-array skvPerspectiveMatrix[][] +#define PL_TO_MOVE_CHANGED 1 // player to move changed - second index of the 2D-array skvPerspectiveMatrix[][] +#define PL_TO_MOVE_UNCHANGED 0 // player to move is still the same - second index of the 2D-array skvPerspectiveMatrix[][] -#define MEASURE_TIME_FREQUENCY 100000 // for io operations per second: measure time every n-th operations -#define MEASURE_IOPS false // true or false - for measurement of the input/output operations per second -#define MEASURE_ONLY_IO false // true or false - to indicate if only the io-operation shall be considered or also the calculating time inbetween +#define MEASURE_TIME_FREQUENCY 100000 // for io operations per second: measure time every n-th operations +#define MEASURE_IOPS false // true or false - for measurement of the input/output operations per second +#define MEASURE_ONLY_IO false // true or false - to indicate if only the io-operation shall be considered or also the calculating time inbetween -#define MM_ACTION_INIT_RETRO_ANAL 1 -#define MM_ACTION_PREPARE_COUNT_ARRAY 2 -#define MM_ACTION_PERFORM_RETRO_ANAL 3 -#define MM_ACTION_PERFORM_ALPHA_BETA 4 -#define MM_ACTION_TESTING_LAYER 5 -#define MM_ACTION_SAVING_LAYER_TO_FILE 6 -#define MM_ACTION_CALC_LAYER_STATS 7 -#define MM_ACTION_NONE 8 +#define MM_ACTION_INIT_RETRO_ANAL 1 +#define MM_ACTION_PREPARE_COUNT_ARRAY 2 +#define MM_ACTION_PERFORM_RETRO_ANAL 3 +#define MM_ACTION_PERFORM_ALPHA_BETA 4 +#define MM_ACTION_TESTING_LAYER 5 +#define MM_ACTION_SAVING_LAYER_TO_FILE 6 +#define MM_ACTION_CALC_LAYER_STATS 7 +#define MM_ACTION_NONE 8 /*** Macros ***************************************************************************************************************************/ -#define SAFE_DELETE(p) { if(p) { delete (p); (p)=nullptr; } } -#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=nullptr; } } +#define SAFE_DELETE(p) \ + { \ + if (p) \ + { \ + delete (p); \ + (p) = nullptr; \ + } \ + } +#define SAFE_DELETE_ARRAY(p) \ + { \ + if (p) \ + { \ + delete[](p); \ + (p) = nullptr; \ + } \ + } // here a macro is used instead of a function because the text 't' is passed like "blabla" << endl << aVariable -#define PRINT(v, c, t) \ -{ \ - if (c->verbosity > v) { \ - EnterCriticalSection(&c->csOsPrint); \ - *c->osPrint << endl << t; \ - if (c->userPrintFunc != nullptr) { \ - c->userPrintFunc(c->pDataForUserPrintFunc); \ - } \ - LeaveCriticalSection(&c->csOsPrint); \ - } \ -} +#define PRINT(v, c, t) \ + { \ + if (c->verbosity > v) \ + { \ + EnterCriticalSection(&c->csOsPrint); \ + *c->osPrint << endl \ + << t; \ + if (c->userPrintFunc != nullptr) \ + { \ + c->userPrintFunc(c->pDataForUserPrintFunc); \ + } \ + LeaveCriticalSection(&c->csOsPrint); \ + } \ + } /*** Klassen ***************************************************************************************************************************/ class MiniMax @@ -108,125 +125,123 @@ class MiniMax friend class MiniMaxWinCalcDb; public: - /*** typedefines ***************************************************************************************************************************/ - typedef unsigned char TwoBit; // 2-Bit variable ranging from 0 to 3 - typedef unsigned short PlyInfoVarType; // 2 Bytes for saving the ply info - typedef unsigned char CountArrayVarType; // 1 Byte for counting predesseccors - typedef unsigned int StateNumberVarType; // 4 Bytes for addressing states within a layer + typedef unsigned char TwoBit; // 2-Bit variable ranging from 0 to 3 + typedef unsigned short PlyInfoVarType; // 2 Bytes for saving the ply info + typedef unsigned char CountArrayVarType; // 1 Byte for counting predesseccors + typedef unsigned int StateNumberVarType; // 4 Bytes for addressing states within a layer /*** protected structures ********************************************************************************************************************/ - struct SkvFileHeader // header of the short knot value file + struct SkvFileHeader // header of the short knot value file { - bool completed; // true if all states have been calculated - unsigned int numLayers; // number of layers - unsigned int headerCode; // = SKV_FILE_HEADER_CODE - unsigned int headerAndStatsSize; // size in bytes of this struct plus the stats + bool completed; // true if all states have been calculated + unsigned int numLayers; // number of layers + unsigned int headerCode; // = SKV_FILE_HEADER_CODE + unsigned int headerAndStatsSize; // size in bytes of this struct plus the stats }; struct PlyInfoFileHeader { - bool plyInfoCompleted; // true if ply innformation has been calculated for all game states - unsigned int numLayers; // number of layers - unsigned int headerCode; // = PLYINFO_HEADER_CODE - unsigned int headerAndPlyInfosSize; // size in bytes of this struct plus ... + bool plyInfoCompleted; // true if ply innformation has been calculated for all game states + unsigned int numLayers; // number of layers + unsigned int headerCode; // = PLYINFO_HEADER_CODE + unsigned int headerAndPlyInfosSize; // size in bytes of this struct plus ... }; - struct PlyInfo // this struct is created for each layer + struct PlyInfo // this struct is created for each layer { - bool plyInfoIsLoaded; // the array plyInfo[] exists in memory. does not necessary mean that it contains only valid values - bool plyInfoIsCompletedAndInFile; // the array plyInfo[] contains only fully calculated valid values - long long layerOffset; // position of this struct in the ply info file - unsigned int sizeInBytes; // size of this struct plus the array plyInfo[] - StateNumberVarType knotsInLayer; // number of knots of the corresponding layer - PlyInfoVarType *plyInfo; // array of size [knotsInLayer] containing the ply info for each knot in this layer + bool plyInfoIsLoaded; // the array plyInfo[] exists in memory. does not necessary mean that it contains only valid values + bool plyInfoIsCompletedAndInFile; // the array plyInfo[] contains only fully calculated valid values + long long layerOffset; // position of this struct in the ply info file + unsigned int sizeInBytes; // size of this struct plus the array plyInfo[] + StateNumberVarType knotsInLayer; // number of knots of the corresponding layer + PlyInfoVarType *plyInfo; // array of size [knotsInLayer] containing the ply info for each knot in this layer // compressorClass::compressedArrayClass * plyInfoCompressed; // compressed array containing the ply info for each knot in this layer - void *plyInfoCompressed; // dummy pointer for padding + void *plyInfoCompressed; // dummy pointer for padding }; struct LayerStats { - bool layerIsLoaded; // the array shortKnotValueByte[] exists in memory. does not necessary mean that it contains only valid values - bool layerIsCompletedAndInFile; // the array shortKnotValueByte[] contains only fully calculated valid values - long long layerOffset; // position of this struct in the short knot value file - unsigned int numSuccLayers; // number of succeding layers. states of other layers are connected by a move of a player - unsigned int succLayers[MAX_NUM_PRED_LAYERS];// array containg the layer ids of the succeding layers - unsigned int partnerLayer; // layer id relevant when switching current and opponent player - StateNumberVarType knotsInLayer; // number of knots of the corresponding layer - StateNumberVarType numWonStates; // number of won states in this layer - StateNumberVarType numLostStates; // number of lost states in this layer - StateNumberVarType numDrawnStates; // number of drawn states in this layer - StateNumberVarType numInvalidStates; // number of invalid states in this layer - unsigned int sizeInBytes; // (knotsInLayer + 3) / 4 - TwoBit *shortKnotValueByte; // array of size [sizeInBytes] containg the short knot values + bool layerIsLoaded; // the array shortKnotValueByte[] exists in memory. does not necessary mean that it contains only valid values + bool layerIsCompletedAndInFile; // the array shortKnotValueByte[] contains only fully calculated valid values + long long layerOffset; // position of this struct in the short knot value file + unsigned int numSuccLayers; // number of succeding layers. states of other layers are connected by a move of a player + unsigned int succLayers[MAX_NUM_PRED_LAYERS]; // array containg the layer ids of the succeding layers + unsigned int partnerLayer; // layer id relevant when switching current and opponent player + StateNumberVarType knotsInLayer; // number of knots of the corresponding layer + StateNumberVarType numWonStates; // number of won states in this layer + StateNumberVarType numLostStates; // number of lost states in this layer + StateNumberVarType numDrawnStates; // number of drawn states in this layer + StateNumberVarType numInvalidStates; // number of invalid states in this layer + unsigned int sizeInBytes; // (knotsInLayer + 3) / 4 + TwoBit *shortKnotValueByte; // array of size [sizeInBytes] containg the short knot values //compressorClass::compressedArrayClass * skvCompressed; // compressed array containing the short knot values - void *skvCompressed; // dummy pointer for padding + void *skvCompressed; // dummy pointer for padding }; struct StateAdress { - StateNumberVarType stateNumber; // state id within the corresponding layer - unsigned char layerNumber; // layer id + StateNumberVarType stateNumber; // state id within the corresponding layer + unsigned char layerNumber; // layer id }; struct Node { - bool isOpponentLevel; // the current considered knot belongs to an opponent game state - float floatValue; // Value of knot (for normal mode) - TwoBit shortValue; // Value of knot (for database) - unsigned int bestMoveId; // for calling class - unsigned int bestBranch; // branch with highest value - unsigned int numPossibilities; // number of branches - PlyInfoVarType plyInfo; // number of moves till win/lost - Node *branches; // pointer to branches + bool isOpponentLevel; // the current considered knot belongs to an opponent game state + float floatValue; // Value of knot (for normal mode) + TwoBit shortValue; // Value of knot (for database) + unsigned int bestMoveId; // for calling class + unsigned int bestBranch; // branch with highest value + unsigned int numPossibilities; // number of branches + PlyInfoVarType plyInfo; // number of moves till win/lost + Node *branches; // pointer to branches }; struct RetroAnalysisPredVars { - unsigned int predStateNumbers; // - unsigned int predLayerNumbers; // - unsigned int predSymOperation; // - bool playerToMoveChanged; // + unsigned int predStateNumbers; // + unsigned int predLayerNumbers; // + unsigned int predSymOperation; // + bool playerToMoveChanged; // }; struct ArrayInfo { - unsigned int type; // - long long sizeInBytes; // - long long compressedSizeInBytes; // - unsigned int belongsToLayer; // - unsigned int updateCounter; + unsigned int type; // + long long sizeInBytes; // + long long compressedSizeInBytes; // + unsigned int belongsToLayer; // + unsigned int updateCounter; - static const unsigned int arrayType_invalid = 0; - static const unsigned int arrayType_knotAlreadyCalculated = 1; - static const unsigned int arrayType_countArray = 2; - static const unsigned int arrayType_plyInfos = 3; - static const unsigned int arrayType_layerStats = 4; - static const unsigned int numArrayTypes = 5; + static const unsigned int arrayType_invalid = 0; + static const unsigned int arrayType_knotAlreadyCalculated = 1; + static const unsigned int arrayType_countArray = 2; + static const unsigned int arrayType_plyInfos = 3; + static const unsigned int arrayType_layerStats = 4; + static const unsigned int numArrayTypes = 5; - static const unsigned int updateCounterThreshold = 100; + static const unsigned int updateCounterThreshold = 100; }; struct ArrayInfoChange { - unsigned int itemIndex; // - ArrayInfo *arrayInfo; // + unsigned int itemIndex; // + ArrayInfo *arrayInfo; // }; struct ArrayInfoContainer { MiniMax *c; - list arrayInfosToBeUpdated; // - list listArrays; // [itemIndex] - vector::iterator> vectorArrays; // [layerNumber*ArrayInfo::numArrayTypes + type] + list arrayInfosToBeUpdated; // + list listArrays; // [itemIndex] + vector::iterator> vectorArrays; // [layerNumber*ArrayInfo::numArrayTypes + type] - void addArray(unsigned int layerNumber, unsigned int type, long long size, long long compressedSize); - void removeArray(unsigned int layerNumber, unsigned int type, long long size, long long compressedSize); - void updateArray(unsigned int layerNumber, unsigned int type); + void addArray(unsigned int layerNumber, unsigned int type, long long size, long long compressedSize); + void removeArray(unsigned int layerNumber, unsigned int type, long long size, long long compressedSize); + void updateArray(unsigned int layerNumber, unsigned int type); }; - /*** public functions ***************************************************************************************************************************/ // Constructor / destructor @@ -234,155 +249,183 @@ public: ~MiniMax(); // Testing functions - bool testState(unsigned int layerNumber, unsigned int stateNumber); - bool testLayer(unsigned int layerNumber); - bool testIfSymStatesHaveSameValue(unsigned int layerNumber); - bool testSetSituationAndGetPoss(unsigned int layerNumber); + bool testState(unsigned int layerNumber, unsigned int stateNumber); + bool testLayer(unsigned int layerNumber); + bool testIfSymStatesHaveSameValue(unsigned int layerNumber); + bool testSetSituationAndGetPoss(unsigned int layerNumber); // Statistics - bool calcLayerStatistics(char *statisticsFileName); - void showMemoryStatus(); - unsigned int getNumThreads(); - bool anyFreshlyCalculatedLayer(); - unsigned int getLastCalculatedLayer(); - StateNumberVarType getNumWonStates(unsigned int layerNum); - StateNumberVarType getNumLostStates(unsigned int layerNum); - StateNumberVarType getNumDrawnStates(unsigned int layerNum); - StateNumberVarType getNumInvalidStates(unsigned int layerNum); - bool isLayerInDatabase(unsigned int layerNum); - long long getLayerSizeInBytes(unsigned int layerNum); - void setOutputStream(ostream *theStream, void(*printFunc)(void *pUserData), void *pUserData); - bool anyArrawInfoToUpdate(); - ArrayInfoChange getArrayInfoForUpdate(); - void getCurrentCalculatedLayer(vector &layers); - LPWSTR getCurrentActionStr(); + bool calcLayerStatistics(char *statisticsFileName); + void showMemoryStatus(); + unsigned int getNumThreads(); + bool anyFreshlyCalculatedLayer(); + unsigned int getLastCalculatedLayer(); + StateNumberVarType getNumWonStates(unsigned int layerNum); + StateNumberVarType getNumLostStates(unsigned int layerNum); + StateNumberVarType getNumDrawnStates(unsigned int layerNum); + StateNumberVarType getNumInvalidStates(unsigned int layerNum); + bool isLayerInDatabase(unsigned int layerNum); + long long getLayerSizeInBytes(unsigned int layerNum); + void setOutputStream(ostream *theStream, void (*printFunc)(void *pUserData), void *pUserData); + bool anyArrawInfoToUpdate(); + ArrayInfoChange getArrayInfoForUpdate(); + void getCurrentCalculatedLayer(vector &layers); + LPWSTR getCurrentActionStr(); // Main function for getting the best choice void *getBestChoice(unsigned int tilLevel, unsigned int *choice, unsigned int maximumNumberOfBranches); // Database functions - bool openDatabase(const char *directory, unsigned int maximumNumberOfBranches); - void calculateDatabase(unsigned int maxDepthOfTree, bool onlyPrepareLayer); - bool isCurrentStateInDatabase(unsigned int threadNo); - void closeDatabase(); - void unloadAllLayers(); - void unloadAllPlyInfos(); - void pauseDatabaseCalculation(); - void cancelDatabaseCalculation(); - bool wasDatabaseCalculationCancelled(); + bool openDatabase(const char *directory, unsigned int maximumNumberOfBranches); + void calculateDatabase(unsigned int maxDepthOfTree, bool onlyPrepareLayer); + bool isCurrentStateInDatabase(unsigned int threadNo); + void closeDatabase(); + void unloadAllLayers(); + void unloadAllPlyInfos(); + void pauseDatabaseCalculation(); + void cancelDatabaseCalculation(); + bool wasDatabaseCalculationCancelled(); // Virtual Functions - virtual void prepareBestChoiceCalculation() + virtual void prepareBestChoiceCalculation() { - while (true); - }; // is called once before building the tree + while (true) + ; + }; // is called once before building the tree virtual unsigned int *getPossibilities(unsigned int threadNo, unsigned int *numPossibilities, bool *opponentsMove, void **pPossibilities) { - while (true); return 0; - }; // returns a pointer to the possibility-IDs - virtual void deletePossibilities(unsigned int threadNo, void *pPossibilities) + while (true) + ; + return 0; + }; // returns a pointer to the possibility-IDs + virtual void deletePossibilities(unsigned int threadNo, void *pPossibilities) { - while (true); + while (true) + ; }; - virtual void storeValueOfMove(unsigned int threadNo, unsigned int idPossibility, void *pPossibilities, TwoBit value, unsigned int *freqValuesSubMoves, PlyInfoVarType plyInfo) + virtual void storeValueOfMove(unsigned int threadNo, unsigned int idPossibility, void *pPossibilities, TwoBit value, unsigned int *freqValuesSubMoves, PlyInfoVarType plyInfo){}; + virtual void move(unsigned int threadNo, unsigned int idPossibility, bool opponentsMove, void **pBackup, void *pPossibilities) { + while (true) + ; }; - virtual void move(unsigned int threadNo, unsigned int idPossibility, bool opponentsMove, void **pBackup, void *pPossibilities) + virtual void undo(unsigned int threadNo, unsigned int idPossibility, bool opponentsMove, void *pBackup, void *pPossibilities) { - while (true); - }; - virtual void undo(unsigned int threadNo, unsigned int idPossibility, bool opponentsMove, void *pBackup, void *pPossibilities) - { - while (true); + while (true) + ; }; - virtual bool shallRetroAnalysisBeUsed(unsigned int layerNum) + virtual bool shallRetroAnalysisBeUsed(unsigned int layerNum) { return false; }; - virtual unsigned int getNumberOfLayers() + virtual unsigned int getNumberOfLayers() { - while (true); return 0; + while (true) + ; + return 0; }; - virtual unsigned int getNumberOfKnotsInLayer(unsigned int layerNum) + virtual unsigned int getNumberOfKnotsInLayer(unsigned int layerNum) { - while (true); return 0; + while (true) + ; + return 0; }; - virtual void getSuccLayers(unsigned int layerNum, unsigned int *amountOfSuccLayers, unsigned int *succLayers) + virtual void getSuccLayers(unsigned int layerNum, unsigned int *amountOfSuccLayers, unsigned int *succLayers) { - while (true); + while (true) + ; }; - virtual unsigned int getPartnerLayer(unsigned int layerNum) + virtual unsigned int getPartnerLayer(unsigned int layerNum) { - while (true); return 0; + while (true) + ; + return 0; }; - virtual string getOutputInformation(unsigned int layerNum) + virtual string getOutputInformation(unsigned int layerNum) { - while (true); return string(""); + while (true) + ; + return string(""); }; - virtual void setOpponentLevel(unsigned int threadNo, bool isOpponentLevel) + virtual void setOpponentLevel(unsigned int threadNo, bool isOpponentLevel) { - while (true); + while (true) + ; }; - virtual bool setSituation(unsigned int threadNo, unsigned int layerNum, unsigned int stateNumber) + virtual bool setSituation(unsigned int threadNo, unsigned int layerNum, unsigned int stateNumber) { - while (true); return false; + while (true) + ; + return false; }; - virtual void getValueOfSituation(unsigned int threadNo, float &floatValue, TwoBit &shortValue) + virtual void getValueOfSituation(unsigned int threadNo, float &floatValue, TwoBit &shortValue) { - while (true); - }; // value of situation for the initial current player - virtual bool getOpponentLevel(unsigned int threadNo) + while (true) + ; + }; // value of situation for the initial current player + virtual bool getOpponentLevel(unsigned int threadNo) { - while (true); return false; + while (true) + ; + return false; }; - virtual unsigned int getLayerAndStateNumber(unsigned int threadNo, unsigned int &layerNum, unsigned int &stateNumber) + virtual unsigned int getLayerAndStateNumber(unsigned int threadNo, unsigned int &layerNum, unsigned int &stateNumber) { - while (true); return 0; + while (true) + ; + return 0; }; - virtual unsigned int getLayerNumber(unsigned int threadNo) + virtual unsigned int getLayerNumber(unsigned int threadNo) { - while (true); return 0; + while (true) + ; + return 0; }; - virtual void getSymStateNumWithDoubles(unsigned int threadNo, unsigned int *numSymmetricStates, unsigned int **symStateNumbers) + virtual void getSymStateNumWithDoubles(unsigned int threadNo, unsigned int *numSymmetricStates, unsigned int **symStateNumbers) { - while (true); + while (true) + ; }; - virtual void getPredecessors(unsigned int threadNo, unsigned int *amountOfPred, RetroAnalysisPredVars *predVars) + virtual void getPredecessors(unsigned int threadNo, unsigned int *amountOfPred, RetroAnalysisPredVars *predVars) { - while (true); + while (true) + ; }; - virtual void printBoard(unsigned int threadNo, unsigned char value) + virtual void printBoard(unsigned int threadNo, unsigned char value) { - while (true); + while (true) + ; }; - virtual void printMoveInformation(unsigned int threadNo, unsigned int idPossibility, void *pPossibilities) + virtual void printMoveInformation(unsigned int threadNo, unsigned int idPossibility, void *pPossibilities) { - while (true); + while (true) + ; }; - virtual void prepareDatabaseCalculation() + virtual void prepareDatabaseCalculation() { - while (true); + while (true) + ; }; - virtual void wrapUpDatabaseCalculation(bool calculationAborted) + virtual void wrapUpDatabaseCalculation(bool calculationAborted) { - while (true); + while (true) + ; }; private: - /*** classes for testing ********************************************************************************************************************/ struct TestLayersVars { MiniMax *pMiniMax; - unsigned int curThreadNo; - unsigned int layerNumber; - LONGLONG statesProcessed; + unsigned int curThreadNo; + unsigned int layerNumber; + LONGLONG statesProcessed; TwoBit *subValueInDatabase; PlyInfoVarType *subPlyInfos; bool *hasCurPlayerChanged; @@ -390,31 +433,33 @@ private: /*** classes for the alpha beta algorithmn ********************************************************************************************************************/ - struct AlphaBetaThreadVars // thread specific variables for each thread in the alpha beta algorithmn + struct AlphaBetaThreadVars // thread specific variables for each thread in the alpha beta algorithmn { - long long numStatesToProcess; // Number of states in 'statesToProcess' which have to be processed - unsigned int threadNo; + long long numStatesToProcess; // Number of states in 'statesToProcess' which have to be processed + unsigned int threadNo; }; - struct AlphaBetaGlobalVars // constant during calculation + struct AlphaBetaGlobalVars // constant during calculation { - unsigned int layerNumber; // layer number of the current process layer - long long totalNumKnots; // total numbers of knots which have to be stored in memory - long long numKnotsToCalc; // number of knots of all layers to be calculated - vector thread; - unsigned int statsValueCounter[SKV_NUM_VALUES]; + unsigned int layerNumber; // layer number of the current process layer + long long totalNumKnots; // total numbers of knots which have to be stored in memory + long long numKnotsToCalc; // number of knots of all layers to be calculated + vector thread; + unsigned int statsValueCounter[SKV_NUM_VALUES]; MiniMax *pMiniMax; AlphaBetaGlobalVars(MiniMax *pMiniMax, unsigned int layerNumber) { this->thread.resize(pMiniMax->threadManager.getNumThreads()); - for (unsigned int threadNo = 0; threadNo < pMiniMax->threadManager.getNumThreads(); threadNo++) { + for (unsigned int threadNo = 0; threadNo < pMiniMax->threadManager.getNumThreads(); threadNo++) + { this->thread[threadNo].numStatesToProcess = 0; this->thread[threadNo].threadNo = threadNo; } this->layerNumber = layerNumber; this->pMiniMax = pMiniMax; - if (pMiniMax->layerStats) { + if (pMiniMax->layerStats) + { this->numKnotsToCalc = pMiniMax->layerStats[layerNumber].knotsInLayer; this->totalNumKnots = pMiniMax->layerStats[layerNumber].knotsInLayer; } @@ -429,27 +474,27 @@ private: { MiniMax *pMiniMax; AlphaBetaGlobalVars *alphaBetaVars; - unsigned int layerNumber; - LONGLONG statesProcessed; - unsigned int statsValueCounter[SKV_NUM_VALUES]; + unsigned int layerNumber; + LONGLONG statesProcessed; + unsigned int statsValueCounter[SKV_NUM_VALUES]; - AlphaBetaDefaultThreadVars() - { - }; + AlphaBetaDefaultThreadVars(){}; AlphaBetaDefaultThreadVars(MiniMax *pMiniMax, AlphaBetaGlobalVars *alphaBetaVars, unsigned int layerNumber) { this->statesProcessed = 0; this->layerNumber = layerNumber; this->pMiniMax = pMiniMax; this->alphaBetaVars = alphaBetaVars; - for (unsigned int curStateValue = 0; curStateValue < SKV_NUM_VALUES; curStateValue++) { + for (unsigned int curStateValue = 0; curStateValue < SKV_NUM_VALUES; curStateValue++) + { this->statsValueCounter[curStateValue] = 0; } }; - void reduceDefault() + void reduceDefault() { pMiniMax->numStatesProcessed += this->statesProcessed; - for (unsigned int curStateValue = 0; curStateValue < SKV_NUM_VALUES; curStateValue++) { + for (unsigned int curStateValue = 0; curStateValue < SKV_NUM_VALUES; curStateValue++) + { alphaBetaVars->statsValueCounter[curStateValue] += this->statsValueCounter[curStateValue]; } }; @@ -458,21 +503,19 @@ private: struct InitAlphaBetaVars : public ThreadManager::ThreadVarsArrayItem, public AlphaBetaDefaultThreadVars { BufferedFile *bufferedFile; - bool initAlreadyDone; + bool initAlreadyDone; - InitAlphaBetaVars() - { - }; + InitAlphaBetaVars(){}; InitAlphaBetaVars(MiniMax *pMiniMax, AlphaBetaGlobalVars *alphaBetaVars, unsigned int layerNumber, BufferedFile *initArray, bool initAlreadyDone) : AlphaBetaDefaultThreadVars(pMiniMax, alphaBetaVars, layerNumber) { this->bufferedFile = initArray; this->initAlreadyDone = initAlreadyDone; }; - void initializeElement(InitAlphaBetaVars &master) + void initializeElement(InitAlphaBetaVars &master) { *this = master; }; - void reduce() + void reduce() { reduceDefault(); }; @@ -480,26 +523,25 @@ private: struct RunAlphaBetaVars : public ThreadManager::ThreadVarsArrayItem, public AlphaBetaDefaultThreadVars { - Node *branchArray = nullptr; // array of size [(depthOfFullTree - tilLevel) * maxNumBranches] for storage of the branches at each search depth - unsigned int *freqValuesSubMovesBranchWon = nullptr; // ... - unsigned int freqValuesSubMoves[4]; // ... + Node *branchArray = nullptr; // array of size [(depthOfFullTree - tilLevel) * maxNumBranches] for storage of the branches at each search depth + unsigned int *freqValuesSubMovesBranchWon = nullptr; // ... + unsigned int freqValuesSubMoves[4]; // ... - RunAlphaBetaVars() - { - }; + RunAlphaBetaVars(){}; RunAlphaBetaVars(MiniMax *pMiniMax, AlphaBetaGlobalVars *alphaBetaVars, unsigned int layerNumber) : AlphaBetaDefaultThreadVars(pMiniMax, alphaBetaVars, layerNumber) { initializeElement(*this); }; ~RunAlphaBetaVars() { - SAFE_DELETE_ARRAY(branchArray); SAFE_DELETE_ARRAY(freqValuesSubMovesBranchWon); + SAFE_DELETE_ARRAY(branchArray); + SAFE_DELETE_ARRAY(freqValuesSubMovesBranchWon); } - void reduce() + void reduce() { reduceDefault(); }; - void initializeElement(RunAlphaBetaVars &master) + void initializeElement(RunAlphaBetaVars &master) { *this = master; branchArray = new Node[alphaBetaVars->pMiniMax->maxNumBranches * alphaBetaVars->pMiniMax->depthOfFullTree]; @@ -511,27 +553,27 @@ private: struct RetroAnalysisQueueState { - StateNumberVarType stateNumber; // state stored in the retro analysis queue. the queue is a buffer containing states to be passed to 'RetroAnalysisThreadVars::statesToProcess' - PlyInfoVarType numPliesTillCurState; // ply number for the stored state + StateNumberVarType stateNumber; // state stored in the retro analysis queue. the queue is a buffer containing states to be passed to 'RetroAnalysisThreadVars::statesToProcess' + PlyInfoVarType numPliesTillCurState; // ply number for the stored state }; - struct RetroAnalysisThreadVars // thread specific variables for each thread in the retro analysis + struct RetroAnalysisThreadVars // thread specific variables for each thread in the retro analysis { - vector statesToProcess; // vector-queue containing the states, whose short knot value are known for sure. they have to be processed. if processed the state will be removed from list. indexing: [threadNo][plyNumber] - vector> stateQueue; // Queue containing states, whose 'count value' shall be increased by one. Before writing 'count value' to 'count array' the writing positions are sorted for faster processing. - long long numStatesToProcess; // Number of states in 'statesToProcess' which have to be processed - unsigned int threadNo; + vector statesToProcess; // vector-queue containing the states, whose short knot value are known for sure. they have to be processed. if processed the state will be removed from list. indexing: [threadNo][plyNumber] + vector> stateQueue; // Queue containing states, whose 'count value' shall be increased by one. Before writing 'count value' to 'count array' the writing positions are sorted for faster processing. + long long numStatesToProcess; // Number of states in 'statesToProcess' which have to be processed + unsigned int threadNo; }; - struct retroAnalysisGlobalVars // constant during calculation + struct retroAnalysisGlobalVars // constant during calculation { - vector countArrays; // One count array for each layer in 'layersToCalculate'. (For the nine men's morris game two layers have to considered at once.) - vector layerInitialized; // - vector layersToCalculate; // layers which shall be calculated - long long totalNumKnots; // total numbers of knots which have to be stored in memory - long long numKnotsToCalc; // number of knots of all layers to be calculated - vector thread; - unsigned int statsValueCounter[SKV_NUM_VALUES]; + vector countArrays; // One count array for each layer in 'layersToCalculate'. (For the nine men's morris game two layers have to considered at once.) + vector layerInitialized; // + vector layersToCalculate; // layers which shall be calculated + long long totalNumKnots; // total numbers of knots which have to be stored in memory + long long numKnotsToCalc; // number of knots of all layers to be calculated + vector thread; + unsigned int statsValueCounter[SKV_NUM_VALUES]; MiniMax *pMiniMax; }; @@ -539,27 +581,27 @@ private: { MiniMax *pMiniMax; retroAnalysisGlobalVars *retroVars; - unsigned int layerNumber; - LONGLONG statesProcessed; - unsigned int statsValueCounter[SKV_NUM_VALUES]; + unsigned int layerNumber; + LONGLONG statesProcessed; + unsigned int statsValueCounter[SKV_NUM_VALUES]; - RetroAnalysisDefaultThreadVars() - { - }; + RetroAnalysisDefaultThreadVars(){}; RetroAnalysisDefaultThreadVars(MiniMax *pMiniMax, retroAnalysisGlobalVars *retroVars, unsigned int layerNumber) { this->statesProcessed = 0; this->layerNumber = layerNumber; this->pMiniMax = pMiniMax; this->retroVars = retroVars; - for (unsigned int curStateValue = 0; curStateValue < SKV_NUM_VALUES; curStateValue++) { + for (unsigned int curStateValue = 0; curStateValue < SKV_NUM_VALUES; curStateValue++) + { this->statsValueCounter[curStateValue] = 0; } }; - void reduceDefault() + void reduceDefault() { pMiniMax->numStatesProcessed += this->statesProcessed; - for (unsigned int curStateValue = 0; curStateValue < SKV_NUM_VALUES; curStateValue++) { + for (unsigned int curStateValue = 0; curStateValue < SKV_NUM_VALUES; curStateValue++) + { retroVars->statsValueCounter[curStateValue] += this->statsValueCounter[curStateValue]; } }; @@ -568,21 +610,19 @@ private: struct InitRetroAnalysisVars : public ThreadManager::ThreadVarsArrayItem, public RetroAnalysisDefaultThreadVars { BufferedFile *bufferedFile; - bool initAlreadyDone; + bool initAlreadyDone; - InitRetroAnalysisVars() - { - }; + InitRetroAnalysisVars(){}; InitRetroAnalysisVars(MiniMax *pMiniMax, retroAnalysisGlobalVars *retroVars, unsigned int layerNumber, BufferedFile *initArray, bool initAlreadyDone) : RetroAnalysisDefaultThreadVars(pMiniMax, retroVars, layerNumber) { this->bufferedFile = initArray; this->initAlreadyDone = initAlreadyDone; }; - void initializeElement(InitRetroAnalysisVars &master) + void initializeElement(InitRetroAnalysisVars &master) { *this = master; }; - void reduce() + void reduce() { reduceDefault(); }; @@ -590,131 +630,126 @@ private: struct AddNumSuccedorsVars : public ThreadManager::ThreadVarsArrayItem, public RetroAnalysisDefaultThreadVars { - RetroAnalysisPredVars predVars[MAX_NUM_PREDECESSORS]; + RetroAnalysisPredVars predVars[MAX_NUM_PREDECESSORS]; - AddNumSuccedorsVars() - { - }; - AddNumSuccedorsVars(MiniMax *pMiniMax, retroAnalysisGlobalVars *retroVars, unsigned int layerNumber) : RetroAnalysisDefaultThreadVars(pMiniMax, retroVars, layerNumber) - { - }; - void initializeElement(AddNumSuccedorsVars &master) + AddNumSuccedorsVars(){}; + AddNumSuccedorsVars(MiniMax *pMiniMax, retroAnalysisGlobalVars *retroVars, unsigned int layerNumber) : RetroAnalysisDefaultThreadVars(pMiniMax, retroVars, layerNumber){}; + void initializeElement(AddNumSuccedorsVars &master) { *this = master; }; - void reduce() + void reduce() { reduceDefault(); }; }; - /*** private variables ***************************************************************************************************************************/ // variables, which are constant during database calculation - int verbosity = 2; // output detail level. default is 2 - unsigned char skvPerspectiveMatrix[4][2]; // [short knot value][current or opponent player] - A winning situation is a loosing situation for the opponent and so on ... - bool calcDatabase = false; // true, if the database is currently beeing calculated - HANDLE hFileShortKnotValues = nullptr; // handle of the file for the short knot value - HANDLE hFilePlyInfo = nullptr; // handle of the file for the ply info - SkvFileHeader skvfHeader; // short knot value file header - PlyInfoFileHeader plyInfoHeader; // header of the ply info file - string fileDirectory; // path of the folder where the database files are located - ostream *osPrint = nullptr; // stream for output. default is cout - list lastCalculatedLayer; // - vector layersToCalculate; // used in calcLayer() and getCurrentCalculatedLayers() - bool onlyPrepareLayer = false; // - bool stopOnCriticalError = true; // if true then process will stay in while loop - ThreadManager threadManager; // - CRITICAL_SECTION csDatabase; // - CRITICAL_SECTION csOsPrint; // for thread safety when output is passed to osPrint - void (*userPrintFunc)(void *) = nullptr; // called every time output is passed to osPrint - void *pDataForUserPrintFunc = nullptr; // pointer passed when calling userPrintFunc - ArrayInfoContainer arrayInfos; // information about the arrays in memory + int verbosity = 2; // output detail level. default is 2 + unsigned char skvPerspectiveMatrix[4][2]; // [short knot value][current or opponent player] - A winning situation is a loosing situation for the opponent and so on ... + bool calcDatabase = false; // true, if the database is currently beeing calculated + HANDLE hFileShortKnotValues = nullptr; // handle of the file for the short knot value + HANDLE hFilePlyInfo = nullptr; // handle of the file for the ply info + SkvFileHeader skvfHeader; // short knot value file header + PlyInfoFileHeader plyInfoHeader; // header of the ply info file + string fileDirectory; // path of the folder where the database files are located + ostream *osPrint = nullptr; // stream for output. default is cout + list lastCalculatedLayer; // + vector layersToCalculate; // used in calcLayer() and getCurrentCalculatedLayers() + bool onlyPrepareLayer = false; // + bool stopOnCriticalError = true; // if true then process will stay in while loop + ThreadManager threadManager; // + CRITICAL_SECTION csDatabase; // + CRITICAL_SECTION csOsPrint; // for thread safety when output is passed to osPrint + void (*userPrintFunc)(void *) = nullptr; // called every time output is passed to osPrint + void *pDataForUserPrintFunc = nullptr; // pointer passed when calling userPrintFunc + ArrayInfoContainer arrayInfos; // information about the arrays in memory // thread specific or non-constant variables - LONGLONG memoryUsed2 = 0; // memory in bytes used for storing: ply information, short knot value and ... - LONGLONG numStatesProcessed = 0; // - unsigned int maxNumBranches = 0; // maximum number of branches/moves - unsigned int depthOfFullTree = 0; // maxumim search depth - unsigned int curCalculatedLayer = 0; // id of the currently calculated layer - unsigned int curCalculationActionId = 0; // one of ... - bool layerInDatabase = false; // true if the current considered layer has already been calculated and stored in the database - void *pRootPossibilities = nullptr; // pointer to the structure passed by getPossibilities() for the state at which getBestChoice() has been called - LayerStats *layerStats = nullptr; // array of size [] containing general layer information and the skv of all layers - PlyInfo *plyInfos = nullptr; // array of size [] containing ply information + LONGLONG memoryUsed2 = 0; // memory in bytes used for storing: ply information, short knot value and ... + LONGLONG numStatesProcessed = 0; // + unsigned int maxNumBranches = 0; // maximum number of branches/moves + unsigned int depthOfFullTree = 0; // maxumim search depth + unsigned int curCalculatedLayer = 0; // id of the currently calculated layer + unsigned int curCalculationActionId = 0; // one of ... + bool layerInDatabase = false; // true if the current considered layer has already been calculated and stored in the database + void *pRootPossibilities = nullptr; // pointer to the structure passed by getPossibilities() for the state at which getBestChoice() has been called + LayerStats *layerStats = nullptr; // array of size [] containing general layer information and the skv of all layers + PlyInfo *plyInfos = nullptr; // array of size [] containing ply information // variables concerning the compression of the database // compressorClass * compressor = nullptr; // unsigned int compressionAlgorithmnId = 0; // 0 or one of the COMPRESSOR_ALG_... constants // database io operations per second - long long numReadSkvOperations = 0; // number of read operations done since start of the programm - long long numWriteSkvOperations = 0; // number of write operations done since start of the programm - long long numReadPlyOperations = 0; // number of read operations done since start of the programm - long long numWritePlyOperations = 0; // number of write operations done since start of the programm - LARGE_INTEGER readSkvInterval; // time of interval for read operations - LARGE_INTEGER writeSkvInterval; // '' - LARGE_INTEGER readPlyInterval; // '' - LARGE_INTEGER writePlyInterval; // '' - LARGE_INTEGER frequency; // performance-counter frequency, in counts per second + long long numReadSkvOperations = 0; // number of read operations done since start of the programm + long long numWriteSkvOperations = 0; // number of write operations done since start of the programm + long long numReadPlyOperations = 0; // number of read operations done since start of the programm + long long numWritePlyOperations = 0; // number of write operations done since start of the programm + LARGE_INTEGER readSkvInterval; // time of interval for read operations + LARGE_INTEGER writeSkvInterval; // '' + LARGE_INTEGER readPlyInterval; // '' + LARGE_INTEGER writePlyInterval; // '' + LARGE_INTEGER frequency; // performance-counter frequency, in counts per second /*** private functions ***************************************************************************************************************************/ // database functions - void openSkvFile(const char *path, unsigned int maximumNumberOfBranches); - void openPlyInfoFile(const char *path); - bool calcLayer(unsigned int layerNumber); - void unloadPlyInfo(unsigned int layerNumber); - void unloadLayer(unsigned int layerNumber); - void saveHeader(SkvFileHeader *dbH, LayerStats *lStats); - void saveHeader(PlyInfoFileHeader *piH, PlyInfo *pInfo); - void readKnotValueFromDatabase(unsigned int threadNo, unsigned int &layerNumber, unsigned int &stateNumber, TwoBit &knotValue, bool &invalidLayerOrStateNumber, bool &layerInDatabaseAndCompleted); - void readKnotValueFromDatabase(unsigned int layerNumber, unsigned int stateNumber, TwoBit &knotValue); - void readPlyInfoFromDatabase(unsigned int layerNumber, unsigned int stateNumber, PlyInfoVarType &value); - void saveKnotValueInDatabase(unsigned int layerNumber, unsigned int stateNumber, TwoBit knotValue); - void savePlyInfoInDatabase(unsigned int layerNumber, unsigned int stateNumber, PlyInfoVarType value); - void loadBytesFromFile(HANDLE hFile, long long offset, unsigned int numBytes, void *pBytes); - void saveBytesToFile(HANDLE hFile, long long offset, unsigned int numBytes, void *pBytes); - void saveLayerToFile(unsigned int layerNumber); - inline void measureIops(long long &numOperations, LARGE_INTEGER &interval, LARGE_INTEGER &curTimeBefore, char text[]); + void openSkvFile(const char *path, unsigned int maximumNumberOfBranches); + void openPlyInfoFile(const char *path); + bool calcLayer(unsigned int layerNumber); + void unloadPlyInfo(unsigned int layerNumber); + void unloadLayer(unsigned int layerNumber); + void saveHeader(SkvFileHeader *dbH, LayerStats *lStats); + void saveHeader(PlyInfoFileHeader *piH, PlyInfo *pInfo); + void readKnotValueFromDatabase(unsigned int threadNo, unsigned int &layerNumber, unsigned int &stateNumber, TwoBit &knotValue, bool &invalidLayerOrStateNumber, bool &layerInDatabaseAndCompleted); + void readKnotValueFromDatabase(unsigned int layerNumber, unsigned int stateNumber, TwoBit &knotValue); + void readPlyInfoFromDatabase(unsigned int layerNumber, unsigned int stateNumber, PlyInfoVarType &value); + void saveKnotValueInDatabase(unsigned int layerNumber, unsigned int stateNumber, TwoBit knotValue); + void savePlyInfoInDatabase(unsigned int layerNumber, unsigned int stateNumber, PlyInfoVarType value); + void loadBytesFromFile(HANDLE hFile, long long offset, unsigned int numBytes, void *pBytes); + void saveBytesToFile(HANDLE hFile, long long offset, unsigned int numBytes, void *pBytes); + void saveLayerToFile(unsigned int layerNumber); + inline void measureIops(long long &numOperations, LARGE_INTEGER &interval, LARGE_INTEGER &curTimeBefore, char text[]); // Testing functions - static DWORD testLayerThreadProc(void *pParameter, int index); - static DWORD testSetSituationThreadProc(void *pParameter, int index); + static DWORD testLayerThreadProc(void *pParameter, int index); + static DWORD testSetSituationThreadProc(void *pParameter, int index); // Alpha-Beta-Algorithmn - bool calcKnotValuesByAlphaBeta(unsigned int layerNumber); - bool initAlphaBeta(AlphaBetaGlobalVars &retroVars); - bool runAlphaBeta(AlphaBetaGlobalVars &retroVars); - void letTheTreeGrow(Node *knot, RunAlphaBetaVars *rabVars, unsigned int tilLevel, float alpha, float beta); - bool alphaBetaTryDataBase(Node *knot, RunAlphaBetaVars *rabVars, unsigned int tilLevel, unsigned int &layerNumber, unsigned int &stateNumber); - void alphaBetaTryPossibilites(Node *knot, RunAlphaBetaVars *rabVars, unsigned int tilLevel, unsigned int *idPossibility, void *pPossibilities, unsigned int &maxWonfreqValuesSubMoves, float &alpha, float &beta); - void alphaBetaCalcPlyInfo(Node *knot); - void alphaBetaCalcKnotValue(Node *knot); - void alphaBetaChooseBestMove(Node *knot, RunAlphaBetaVars *rabVars, unsigned int tilLevel, unsigned int *idPossibility, unsigned int maxWonfreqValuesSubMoves); - void alphaBetaSaveInDatabase(unsigned int threadNo, unsigned int layerNumber, unsigned int stateNumber, TwoBit knotValue, PlyInfoVarType plyValue, bool invertValue); - static DWORD initAlphaBetaThreadProc(void *pParameter, int index); - static DWORD runAlphaBetaThreadProc(void *pParameter, int index); + bool calcKnotValuesByAlphaBeta(unsigned int layerNumber); + bool initAlphaBeta(AlphaBetaGlobalVars &retroVars); + bool runAlphaBeta(AlphaBetaGlobalVars &retroVars); + void letTheTreeGrow(Node *knot, RunAlphaBetaVars *rabVars, unsigned int tilLevel, float alpha, float beta); + bool alphaBetaTryDataBase(Node *knot, RunAlphaBetaVars *rabVars, unsigned int tilLevel, unsigned int &layerNumber, unsigned int &stateNumber); + void alphaBetaTryPossibilites(Node *knot, RunAlphaBetaVars *rabVars, unsigned int tilLevel, unsigned int *idPossibility, void *pPossibilities, unsigned int &maxWonfreqValuesSubMoves, float &alpha, float &beta); + void alphaBetaCalcPlyInfo(Node *knot); + void alphaBetaCalcKnotValue(Node *knot); + void alphaBetaChooseBestMove(Node *knot, RunAlphaBetaVars *rabVars, unsigned int tilLevel, unsigned int *idPossibility, unsigned int maxWonfreqValuesSubMoves); + void alphaBetaSaveInDatabase(unsigned int threadNo, unsigned int layerNumber, unsigned int stateNumber, TwoBit knotValue, PlyInfoVarType plyValue, bool invertValue); + static DWORD initAlphaBetaThreadProc(void *pParameter, int index); + static DWORD runAlphaBetaThreadProc(void *pParameter, int index); - // Retro Analysis - bool calcKnotValuesByRetroAnalysis(vector &layersToCalculate); - bool initRetroAnalysis(retroAnalysisGlobalVars &retroVars); - bool prepareCountArrays(retroAnalysisGlobalVars &retroVars); - bool calcNumSuccedors(retroAnalysisGlobalVars &retroVars); - bool performRetroAnalysis(retroAnalysisGlobalVars &retroVars); - bool addStateToProcessQueue(retroAnalysisGlobalVars &retroVars, RetroAnalysisThreadVars &threadVars, unsigned int plyNumber, StateAdress *pState); - static bool retroAnalysisQueueStateComp(const RetroAnalysisQueueState &a, const RetroAnalysisQueueState &b) + // Retro Analysis + bool calcKnotValuesByRetroAnalysis(vector &layersToCalculate); + bool initRetroAnalysis(retroAnalysisGlobalVars &retroVars); + bool prepareCountArrays(retroAnalysisGlobalVars &retroVars); + bool calcNumSuccedors(retroAnalysisGlobalVars &retroVars); + bool performRetroAnalysis(retroAnalysisGlobalVars &retroVars); + bool addStateToProcessQueue(retroAnalysisGlobalVars &retroVars, RetroAnalysisThreadVars &threadVars, unsigned int plyNumber, StateAdress *pState); + static bool retroAnalysisQueueStateComp(const RetroAnalysisQueueState &a, const RetroAnalysisQueueState &b) { return a.stateNumber < b.stateNumber; }; - static DWORD initRetroAnalysisThreadProc(void *pParameter, int index); - static DWORD addNumSuccedorsThreadProc(void *pParameter, int index); - static DWORD performRetroAnalysisThreadProc(void *pParameter); + static DWORD initRetroAnalysisThreadProc(void *pParameter, int index); + static DWORD addNumSuccedorsThreadProc(void *pParameter, int index); + static DWORD performRetroAnalysisThreadProc(void *pParameter); // Progress report functions - void showLayerStats(unsigned int layerNumber); - bool falseOrStop(); + void showLayerStats(unsigned int layerNumber); + bool falseOrStop(); }; #endif diff --git a/src/perfect/miniMaxAI.h b/src/perfect/miniMaxAI.h index e8e6288d..adb59c2b 100644 --- a/src/perfect/miniMaxAI.h +++ b/src/perfect/miniMaxAI.h @@ -17,14 +17,13 @@ //using namespace std; -#define VALUE_GAME_LOST -1000.0f -#define VALUE_GAME_WON 1000.0f +#define VALUE_GAME_LOST -1000.0f +#define VALUE_GAME_WON 1000.0f /*** Klassen *********************************************************/ class MiniMaxAI : public MillAI, MiniMax { protected: - // structs struct Possibility { @@ -34,32 +33,32 @@ protected: struct Backup { - float value; - bool gameHasFinished; - bool settingPhase; - int fieldFrom, fieldTo; // value of board - unsigned int from, to; // index of board - unsigned int curNumStones, oppNumStones; - unsigned int curPosMoves, oppPosMoves; - unsigned int curMissStones, oppMissStones; - unsigned int stonesSet; - unsigned int stoneMustBeRemoved; - unsigned int stonePartOfMill[fieldStruct::size]; - unsigned int warnings[fieldStruct::size]; + float value; + bool gameHasFinished; + bool settingPhase; + int fieldFrom, fieldTo; // value of board + unsigned int from, to; // index of board + unsigned int curNumStones, oppNumStones; + unsigned int curPosMoves, oppPosMoves; + unsigned int curMissStones, oppMissStones; + unsigned int stonesSet; + unsigned int stoneMustBeRemoved; + unsigned int stonePartOfMill[fieldStruct::size]; + unsigned int warnings[fieldStruct::size]; Player *curPlayer, *oppPlayer; }; // Variables - fieldStruct *field; // pointer of the current board [changed by move()] - float currentValue; // value of current situation for board->currentPlayer - bool gameHasFinished; // someone has won or current board is full + fieldStruct *field; // pointer of the current board [changed by move()] + float currentValue; // value of current situation for board->currentPlayer + bool gameHasFinished; // someone has won or current board is full - int ownId; // id of the player who called the play()-function - unsigned int curSearchDepth; // current level - unsigned int depthOfFullTree; // search depth where the whole tree is explored - unsigned int *idPossibilities; // returned pointer of getPossibilities()-function - Backup *oldStates; // for undo()-function - Possibility *possibilities; // for getPossNormalMove()-function + int ownId; // id of the player who called the play()-function + unsigned int curSearchDepth; // current level + unsigned int depthOfFullTree; // search depth where the whole tree is explored + unsigned int *idPossibilities; // returned pointer of getPossibilities()-function + Backup *oldStates; // for undo()-function + Possibility *possibilities; // for getPossNormalMove()-function // Functions unsigned int *getPossSettingPhase(unsigned int *numPossibilities, void **pPossibilities); @@ -67,75 +66,61 @@ protected: unsigned int *getPossStoneRemove(unsigned int *numPossibilities, void **pPossibilities); // move functions - inline void updatePossibleMoves(unsigned int stone, Player *stoneOwner, bool stoneRemoved, unsigned int ignoreStone); - inline void updateWarning(unsigned int firstStone, unsigned int secondStone); - inline void setWarning(unsigned int stoneOne, unsigned int stoneTwo, unsigned int stoneThree); - inline void removeStone(unsigned int from, Backup *backup); - inline void setStone(unsigned int to, Backup *backup); - inline void normalMove(unsigned int from, unsigned int to, Backup *backup); + inline void updatePossibleMoves(unsigned int stone, Player *stoneOwner, bool stoneRemoved, unsigned int ignoreStone); + inline void updateWarning(unsigned int firstStone, unsigned int secondStone); + inline void setWarning(unsigned int stoneOne, unsigned int stoneTwo, unsigned int stoneThree); + inline void removeStone(unsigned int from, Backup *backup); + inline void setStone(unsigned int to, Backup *backup); + inline void normalMove(unsigned int from, unsigned int to, Backup *backup); // Virtual Functions - void prepareBestChoiceCalculation(); + void prepareBestChoiceCalculation(); unsigned int *getPossibilities(unsigned int threadNo, unsigned int *numPossibilities, bool *opponentsMove, void **pPossibilities); - void deletePossibilities(unsigned int threadNo, void *pPossibilities); - void move(unsigned int threadNo, unsigned int idPossibility, bool opponentsMove, void **pBackup, void *pPossibilities); - void undo(unsigned int threadNo, unsigned int idPossibility, bool opponentsMove, void *pBackup, void *pPossibilities); - void getValueOfSituation(unsigned int threadNo, float &floatValue, TwoBit &shortValue); - void printMoveInformation(unsigned int threadNo, unsigned int idPossibility, void *pPossibilities); + void deletePossibilities(unsigned int threadNo, void *pPossibilities); + void move(unsigned int threadNo, unsigned int idPossibility, bool opponentsMove, void **pBackup, void *pPossibilities); + void undo(unsigned int threadNo, unsigned int idPossibility, bool opponentsMove, void *pBackup, void *pPossibilities); + void getValueOfSituation(unsigned int threadNo, float &floatValue, TwoBit &shortValue); + void printMoveInformation(unsigned int threadNo, unsigned int idPossibility, void *pPossibilities); - unsigned int getNumberOfLayers() + unsigned int getNumberOfLayers() { return 0; }; - unsigned int getNumberOfKnotsInLayer(unsigned int layerNum) + unsigned int getNumberOfKnotsInLayer(unsigned int layerNum) { return 0; }; - void getSuccLayers(unsigned int layerNum, unsigned int *amountOfSuccLayers, unsigned int *succLayers) - { - }; - unsigned int getPartnerLayer(unsigned int layerNum) + void getSuccLayers(unsigned int layerNum, unsigned int *amountOfSuccLayers, unsigned int *succLayers){}; + unsigned int getPartnerLayer(unsigned int layerNum) { return 0; }; - string getOutputInformation(unsigned int layerNum) + string getOutputInformation(unsigned int layerNum) { return string(""); }; - void setOpponentLevel(unsigned int threadNo, bool isOpponentLevel) - { - }; - bool setSituation(unsigned int threadNo, unsigned int layerNum, unsigned int stateNumber) + void setOpponentLevel(unsigned int threadNo, bool isOpponentLevel){}; + bool setSituation(unsigned int threadNo, unsigned int layerNum, unsigned int stateNumber) { return false; }; - bool getOpponentLevel(unsigned int threadNo) + bool getOpponentLevel(unsigned int threadNo) { return false; }; - unsigned int getLayerAndStateNumber(unsigned int threadNo, unsigned int &layerNum, unsigned int &stateNumber) + unsigned int getLayerAndStateNumber(unsigned int threadNo, unsigned int &layerNum, unsigned int &stateNumber) { return 0; }; - unsigned int getLayerNumber(unsigned int threadNo) + unsigned int getLayerNumber(unsigned int threadNo) { return 0; }; - void getSymStateNumWithDoubles(unsigned int threadNo, unsigned int *numSymmetricStates, unsigned int **symStateNumbers) - { - }; - void getPredecessors(unsigned int threadNo, unsigned int *amountOfPred, RetroAnalysisPredVars *predVars) - { - }; - void printBoard(unsigned int threadNo, unsigned char value) - { - }; - void prepareDatabaseCalculation() - { - }; - void wrapUpDatabaseCalculation(bool calculationAborted) - { - }; + void getSymStateNumWithDoubles(unsigned int threadNo, unsigned int *numSymmetricStates, unsigned int **symStateNumbers){}; + void getPredecessors(unsigned int threadNo, unsigned int *amountOfPred, RetroAnalysisPredVars *predVars){}; + void printBoard(unsigned int threadNo, unsigned char value){}; + void prepareDatabaseCalculation(){}; + void wrapUpDatabaseCalculation(bool calculationAborted){}; public: // Constructor / destructor @@ -143,8 +128,8 @@ public: ~MiniMaxAI(); // Functions - void play(fieldStruct *theField, unsigned int *pushFrom, unsigned int *pushTo); - void setSearchDepth(unsigned int depth); + void play(fieldStruct *theField, unsigned int *pushFrom, unsigned int *pushTo); + void setSearchDepth(unsigned int depth); }; #endif \ No newline at end of file diff --git a/src/perfect/miniMaxWin.h b/src/perfect/miniMaxWin.h index 4aa8a41a..155e0e1e 100644 --- a/src/perfect/miniMaxWin.h +++ b/src/perfect/miniMaxWin.h @@ -19,15 +19,9 @@ class MiniMaxGuiField { public: - virtual void setAlignment(wildWeasel::alignment &newAlignment) - { - }; - virtual void setVisibility(bool visible) - { - }; - virtual void setState(unsigned int curShowedLayer, MiniMax::StateNumberVarType curShowedState) - { - }; + virtual void setAlignment(wildWeasel::alignment &newAlignment){}; + virtual void setVisibility(bool visible){}; + virtual void setState(unsigned int curShowedLayer, MiniMax::StateNumberVarType curShowedState){}; }; /*------------------------------------------------------------------------------------ @@ -58,25 +52,23 @@ public: class MiniMaxWinInspectDb { protected: - // General Variables - MiniMax *pMiniMax = nullptr; // pointer to perfect AI class granting the access to the database + MiniMax *pMiniMax = nullptr; // pointer to perfect AI class granting the access to the database MiniMaxGuiField *pGuiField = nullptr; - bool showingInspectionControls = false; - unsigned int curShowedLayer = 0; // current showed layer - MiniMax::StateNumberVarType curShowedState = 0; // current showed state - const unsigned int scrollBarWidth = 20; + bool showingInspectionControls = false; + unsigned int curShowedLayer = 0; // current showed layer + MiniMax::StateNumberVarType curShowedState = 0; // current showed state + const unsigned int scrollBarWidth = 20; public: - // Constructor / destructor MiniMaxWinInspectDb(wildWeasel::masterMind *ww, MiniMax *pMiniMax, wildWeasel::alignment &amInspectDb, wildWeasel::font2D *font, wildWeasel::texture *textureLine, MiniMaxGuiField &guiField); ~MiniMaxWinInspectDb(); // Generals Functions - bool createControls(); - bool showControls(bool visible); - void resize(wildWeasel::alignment &rcNewArea); + bool createControls(); + bool showControls(bool visible); + void resize(wildWeasel::alignment &rcNewArea); }; /*------------------------------------------------------------------------------------ @@ -110,55 +102,51 @@ public: class MiniMaxWinCalcDb { protected: - // Calculation variables - wildWeasel::masterMind *ww = nullptr; // pointer to engine - MiniMax *pMiniMax = nullptr; // pointer to perfect AI class granting the access to the database - ostream *outputStream = nullptr; // pointer to a stream for the console output of the calculation done by the class MiniMax - stringbuf outputStringBuf; // buffer linked to the stream, for reading out of the stream into the buffer - locale myLocale; // for formatting the output - queue layersToTest; // layer numbers to be tested - thread hThreadSolve; - thread hThreadTestLayer; - bool showingCalculationControls = false; - bool threadSolveIsRunning = false; - bool threadTestLayerIsRunning = false; - condition_variable threadConditionVariable; - mutex threadMutex; + wildWeasel::masterMind *ww = nullptr; // pointer to engine + MiniMax *pMiniMax = nullptr; // pointer to perfect AI class granting the access to the database + ostream *outputStream = nullptr; // pointer to a stream for the console output of the calculation done by the class MiniMax + stringbuf outputStringBuf; // buffer linked to the stream, for reading out of the stream into the buffer + locale myLocale; // for formatting the output + queue layersToTest; // layer numbers to be tested + thread hThreadSolve; + thread hThreadTestLayer; + bool showingCalculationControls = false; + bool threadSolveIsRunning = false; + bool threadTestLayerIsRunning = false; + condition_variable threadConditionVariable; + mutex threadMutex; // positions, metrics, sizes, dimensions - unsigned int listViewRowHeight = 20; // height in pixel of a single row - const float defPixelDist = 15; // - const float labelHeight = 30; // - const float buttonHeight = 30; // - - + unsigned int listViewRowHeight = 20; // height in pixel of a single row + const float defPixelDist = 15; // + const float labelHeight = 30; // + const float buttonHeight = 30; // // Calculation Functions - void buttonFuncCalcStartOrContinue(void *pUser); - void buttonFuncCalcCancel(void *pUser); - void buttonFuncCalcPause(void *pUser); - void buttonFuncCalcTest(); - void buttonFuncCalcTestAll(void *pUser); - void buttonFuncCalcTestLayer(void *pUser); - void lvSelectedLayerChanged(unsigned int row, unsigned int col, wildWeasel::guiElemEvFol *guiElem, void *pUser); - static void updateOutputControls(void *pUser); - void updateListItemLayer(unsigned int layerNumber); - void updateListItemArray(MiniMax::ArrayInfoChange infoChange); - void threadSolve(); - void threadProcTestLayer(); + void buttonFuncCalcStartOrContinue(void *pUser); + void buttonFuncCalcCancel(void *pUser); + void buttonFuncCalcPause(void *pUser); + void buttonFuncCalcTest(); + void buttonFuncCalcTestAll(void *pUser); + void buttonFuncCalcTestLayer(void *pUser); + void lvSelectedLayerChanged(unsigned int row, unsigned int col, wildWeasel::guiElemEvFol *guiElem, void *pUser); + static void updateOutputControls(void *pUser); + void updateListItemLayer(unsigned int layerNumber); + void updateListItemArray(MiniMax::ArrayInfoChange infoChange); + void threadSolve(); + void threadProcTestLayer(); public: - // Constructor / destructor MiniMaxWinCalcDb(wildWeasel::masterMind *ww, MiniMax *pMiniMax, wildWeasel::alignment &amCalculation, wildWeasel::font2D *font, wildWeasel::texture *textureLine); ~MiniMaxWinCalcDb(); // Generals Functions - bool createControls(); - void resize(wildWeasel::alignment &amNewArea); - bool showControls(bool visible); - bool isCalculationOngoing(); + bool createControls(); + void resize(wildWeasel::alignment &amNewArea); + bool showControls(bool visible); + bool isCalculationOngoing(); MiniMax *getMinimaxPointer() { return pMiniMax; diff --git a/src/perfect/miniMax_alphaBetaAlgorithmn.cpp b/src/perfect/miniMax_alphaBetaAlgorithmn.cpp index ae3b82ee..1162a872 100644 --- a/src/perfect/miniMax_alphaBetaAlgorithmn.cpp +++ b/src/perfect/miniMax_alphaBetaAlgorithmn.cpp @@ -15,21 +15,23 @@ bool MiniMax::calcKnotValuesByAlphaBeta(unsigned int layerNumber) { // locals - AlphaBetaGlobalVars alphaBetaVars(this, layerNumber); // multi-thread vars + AlphaBetaGlobalVars alphaBetaVars(this, layerNumber); // multi-thread vars - // Version 10: + // Version 10: PRINT(1, this, "*** Calculate layer " << layerNumber << " by alpha-beta-algorithmn ***" << endl); curCalculationActionId = MM_ACTION_PERFORM_ALPHA_BETA; // initialization PRINT(2, this, " Bytes in memory: " << memoryUsed2 << endl); - if (!initAlphaBeta(alphaBetaVars)) { + if (!initAlphaBeta(alphaBetaVars)) + { return false; } // run alpha-beta algorithmn PRINT(2, this, " Bytes in memory: " << memoryUsed2 << endl); - if (!runAlphaBeta(alphaBetaVars)) { + if (!runAlphaBeta(alphaBetaVars)) + { return false; } @@ -42,19 +44,22 @@ bool MiniMax::calcKnotValuesByAlphaBeta(unsigned int layerNumber) //----------------------------------------------------------------------------- // Name: saveKnotValueInDatabase() -// Desc: +// Desc: //----------------------------------------------------------------------------- -void MiniMax::alphaBetaSaveInDatabase(unsigned int threadNo, unsigned int layerNumber, unsigned int stateNumber, TwoBit knotValue, PlyInfoVarType plyValue, bool invertValue) +void MiniMax::alphaBetaSaveInDatabase(unsigned int threadNo, unsigned int layerNumber, unsigned int stateNumber, TwoBit knotValue, PlyInfoVarType plyValue, bool invertValue) { // locals unsigned int *symStateNumbers = nullptr; - unsigned int numSymmetricStates; - unsigned int sysStateNumber; - unsigned int i; + unsigned int numSymmetricStates; + unsigned int sysStateNumber; + unsigned int i; // invert value ? - if (knotValue > SKV_VALUE_GAME_WON) while (true); - if (invertValue) knotValue = skvPerspectiveMatrix[knotValue][PL_TO_MOVE_UNCHANGED]; + if (knotValue > SKV_VALUE_GAME_WON) + while (true) + ; + if (invertValue) + knotValue = skvPerspectiveMatrix[knotValue][PL_TO_MOVE_UNCHANGED]; // get numbers of symmetric states getSymStateNumWithDoubles(threadNo, &numSymmetricStates, &symStateNumbers); @@ -64,13 +69,15 @@ void MiniMax::alphaBetaSaveInDatabase(unsigned int threadNo, unsigned int layerN savePlyInfoInDatabase(layerNumber, stateNumber, plyValue); // save value for all symmetric states - for (i = 0; i < numSymmetricStates; i++) { + for (i = 0; i < numSymmetricStates; i++) + { // get state number sysStateNumber = symStateNumbers[i]; // don't save original state twice - if (sysStateNumber == stateNumber) continue; + if (sysStateNumber == stateNumber) + continue; // save saveKnotValueInDatabase(layerNumber, sysStateNumber, knotValue); @@ -85,22 +92,25 @@ void MiniMax::alphaBetaSaveInDatabase(unsigned int threadNo, unsigned int layerN bool MiniMax::initAlphaBeta(AlphaBetaGlobalVars &alphaBetaVars) { // locals - BufferedFile *invalidArray; // - bool initAlreadyDone = false; // true if the initialization information is already available in a file - stringstream ssInvArrayDirectory; // - stringstream ssInvArrayFilePath; // + BufferedFile *invalidArray; // + bool initAlreadyDone = false; // true if the initialization information is already available in a file + stringstream ssInvArrayDirectory; // + stringstream ssInvArrayFilePath; // // set current processed layer number PRINT(1, this, endl << " *** Signing of invalid states for layer " << alphaBetaVars.layerNumber << " (" << (getOutputInformation(alphaBetaVars.layerNumber)) << ") which has " << layerStats[alphaBetaVars.layerNumber].knotsInLayer << " knots ***"); // file names - ssInvArrayDirectory.str(""); ssInvArrayDirectory << fileDirectory << (fileDirectory.size() ? "\\" : "") << "invalidStates"; - ssInvArrayFilePath.str(""); ssInvArrayFilePath << fileDirectory << (fileDirectory.size() ? "\\" : "") << "invalidStates\\invalidStatesOfLayer" << alphaBetaVars.layerNumber << ".dat"; + ssInvArrayDirectory.str(""); + ssInvArrayDirectory << fileDirectory << (fileDirectory.size() ? "\\" : "") << "invalidStates"; + ssInvArrayFilePath.str(""); + ssInvArrayFilePath << fileDirectory << (fileDirectory.size() ? "\\" : "") << "invalidStates\\invalidStatesOfLayer" << alphaBetaVars.layerNumber << ".dat"; // does initialization file exist ? CreateDirectoryA(ssInvArrayDirectory.str().c_str(), nullptr); invalidArray = new BufferedFile(threadManager.getNumThreads(), FILE_BUFFER_SIZE, ssInvArrayFilePath.str().c_str()); - if (invalidArray->getFileSize() == (LONGLONG)layerStats[alphaBetaVars.layerNumber].knotsInLayer) { + if (invalidArray->getFileSize() == (LONGLONG)layerStats[alphaBetaVars.layerNumber].knotsInLayer) + { PRINT(2, this, " Loading invalid states from file: " << ssInvArrayFilePath.str()); initAlreadyDone = true; } @@ -114,7 +124,8 @@ bool MiniMax::initAlphaBeta(AlphaBetaGlobalVars &alphaBetaVars) ThreadManager::ThreadVarsArray tva(threadManager.getNumThreads(), InitAlphaBetaVars(this, &alphaBetaVars, alphaBetaVars.layerNumber, invalidArray, initAlreadyDone)); // process each state in the current layer - switch (threadManager.executeParallelLoop(initAlphaBetaThreadProc, tva.getPointerToArray(), tva.getSizeOfArray(), TM_SCHEDULE_STATIC, 0, layerStats[alphaBetaVars.layerNumber].knotsInLayer - 1, 1)) { + switch (threadManager.executeParallelLoop(initAlphaBetaThreadProc, tva.getPointerToArray(), tva.getSizeOfArray(), TM_SCHEDULE_STATIC, 0, layerStats[alphaBetaVars.layerNumber].knotsInLayer - 1, 1)) + { case TM_RETURN_VALUE_OK: break; case TM_RETURN_VALUE_EXECUTION_CANCELLED: @@ -130,7 +141,8 @@ bool MiniMax::initAlphaBeta(AlphaBetaGlobalVars &alphaBetaVars) // reduce and delete thread specific data tva.reduce(); - if (numStatesProcessed < layerStats[alphaBetaVars.layerNumber].knotsInLayer) { + if (numStatesProcessed < layerStats[alphaBetaVars.layerNumber].knotsInLayer) + { SAFE_DELETE(invalidArray); return falseOrStop(); } @@ -158,44 +170,57 @@ DWORD MiniMax::initAlphaBetaThreadProc(void *pParameter, int index) // locals InitAlphaBetaVars *iabVars = (InitAlphaBetaVars *)pParameter; MiniMax *m = iabVars->pMiniMax; - float floatValue; // dummy variable for calls of getValueOfSituation() - StateAdress curState; // current state counter for loops - TwoBit curStateValue = 0; // for calls of getValueOfSituation() - PlyInfoVarType plyInfo; // depends on the curStateValue + float floatValue; // dummy variable for calls of getValueOfSituation() + StateAdress curState; // current state counter for loops + TwoBit curStateValue = 0; // for calls of getValueOfSituation() + PlyInfoVarType plyInfo; // depends on the curStateValue curState.layerNumber = iabVars->layerNumber; curState.stateNumber = index; iabVars->statesProcessed++; // print status - if (iabVars->statesProcessed % OUTPUT_EVERY_N_STATES == 0) { + if (iabVars->statesProcessed % OUTPUT_EVERY_N_STATES == 0) + { m->numStatesProcessed += OUTPUT_EVERY_N_STATES; PRINT(2, m, "Already initialized " << m->numStatesProcessed << " of " << m->layerStats[curState.layerNumber].knotsInLayer << " states"); } // layer initialization already done ? if so, then read from file - if (iabVars->initAlreadyDone) { - if (!iabVars->bufferedFile->readBytes(iabVars->curThreadNo, index * sizeof(TwoBit), sizeof(TwoBit), (unsigned char *)&curStateValue)) { + if (iabVars->initAlreadyDone) + { + if (!iabVars->bufferedFile->readBytes(iabVars->curThreadNo, index * sizeof(TwoBit), sizeof(TwoBit), (unsigned char *)&curStateValue)) + { PRINT(0, m, "ERROR: initArray->takeBytes() failed"); return m->falseOrStop(); } // initialization not done - } else { + } + else + { // set current selected situation - if (!m->setSituation(iabVars->curThreadNo, curState.layerNumber, curState.stateNumber)) { + if (!m->setSituation(iabVars->curThreadNo, curState.layerNumber, curState.stateNumber)) + { curStateValue = SKV_VALUE_INVALID; - } else { + } + else + { // get value of current situation m->getValueOfSituation(iabVars->curThreadNo, floatValue, curStateValue); } } // calc ply info - if (curStateValue == SKV_VALUE_GAME_WON || curStateValue == SKV_VALUE_GAME_LOST) { + if (curStateValue == SKV_VALUE_GAME_WON || curStateValue == SKV_VALUE_GAME_LOST) + { plyInfo = 0; - } else if (curStateValue == SKV_VALUE_INVALID) { + } + else if (curStateValue == SKV_VALUE_INVALID) + { plyInfo = PLYINFO_VALUE_INVALID; - } else { + } + else + { plyInfo = PLYINFO_VALUE_UNCALCULATED; } @@ -204,8 +229,10 @@ DWORD MiniMax::initAlphaBetaThreadProc(void *pParameter, int index) m->savePlyInfoInDatabase(curState.layerNumber, curState.stateNumber, plyInfo); // write data to file - if (!iabVars->initAlreadyDone) { - if (!iabVars->bufferedFile->writeBytes(iabVars->curThreadNo, index * sizeof(TwoBit), sizeof(TwoBit), (unsigned char *)&curStateValue)) { + if (!iabVars->initAlreadyDone) + { + if (!iabVars->bufferedFile->writeBytes(iabVars->curThreadNo, index * sizeof(TwoBit), sizeof(TwoBit), (unsigned char *)&curStateValue)) + { PRINT(0, m, "ERROR: bufferedFile->writeBytes failed!"); return m->falseOrStop(); } @@ -217,7 +244,7 @@ DWORD MiniMax::initAlphaBetaThreadProc(void *pParameter, int index) //----------------------------------------------------------------------------- // Name: runAlphaBeta() -// Desc: +// Desc: //----------------------------------------------------------------------------- bool MiniMax::runAlphaBeta(AlphaBetaGlobalVars &alphaBetaVars) { @@ -234,7 +261,8 @@ bool MiniMax::runAlphaBeta(AlphaBetaGlobalVars &alphaBetaVars) threadManager.setNumThreads(1); // process each state in the current layer - switch (threadManager.executeParallelLoop(runAlphaBetaThreadProc, tva.getPointerToArray(), tva.getSizeOfArray(), TM_SCHEDULE_STATIC, 0, layerStats[alphaBetaVars.layerNumber].knotsInLayer - 1, 1)) { + switch (threadManager.executeParallelLoop(runAlphaBetaThreadProc, tva.getPointerToArray(), tva.getSizeOfArray(), TM_SCHEDULE_STATIC, 0, layerStats[alphaBetaVars.layerNumber].knotsInLayer - 1, 1)) + { case TM_RETURN_VALUE_OK: break; case TM_RETURN_VALUE_EXECUTION_CANCELLED: @@ -249,7 +277,8 @@ bool MiniMax::runAlphaBeta(AlphaBetaGlobalVars &alphaBetaVars) // reduce and delete thread specific data tva.reduce(); - if (numStatesProcessed < layerStats[alphaBetaVars.layerNumber].knotsInLayer) return falseOrStop(); + if (numStatesProcessed < layerStats[alphaBetaVars.layerNumber].knotsInLayer) + return falseOrStop(); // show statistics PRINT(2, this, " won states: " << alphaBetaVars.statsValueCounter[SKV_VALUE_GAME_WON]); @@ -262,38 +291,42 @@ bool MiniMax::runAlphaBeta(AlphaBetaGlobalVars &alphaBetaVars) //----------------------------------------------------------------------------- // Name: runAlphaBetaThreadProc() -// Desc: +// Desc: //----------------------------------------------------------------------------- DWORD MiniMax::runAlphaBetaThreadProc(void *pParameter, int index) { // locals RunAlphaBetaVars *rabVars = (RunAlphaBetaVars *)pParameter; MiniMax *m = rabVars->pMiniMax; - StateAdress curState; // current state counter for loops - Node root; // - PlyInfoVarType plyInfo; // depends on the curStateValue + StateAdress curState; // current state counter for loops + Node root; // + PlyInfoVarType plyInfo; // depends on the curStateValue curState.layerNumber = rabVars->layerNumber; curState.stateNumber = index; rabVars->statesProcessed++; // print status - if (rabVars->statesProcessed % OUTPUT_EVERY_N_STATES == 0) { + if (rabVars->statesProcessed % OUTPUT_EVERY_N_STATES == 0) + { m->numStatesProcessed += OUTPUT_EVERY_N_STATES; PRINT(2, m, " Processed " << m->numStatesProcessed << " of " << m->layerStats[curState.layerNumber].knotsInLayer << " states"); } // Version 10: state already calculated? if so leave. m->readPlyInfoFromDatabase(curState.layerNumber, curState.stateNumber, plyInfo); - if (plyInfo != PLYINFO_VALUE_UNCALCULATED) return TM_RETURN_VALUE_OK; + if (plyInfo != PLYINFO_VALUE_UNCALCULATED) + return TM_RETURN_VALUE_OK; // set current selected situation - if (m->setSituation(rabVars->curThreadNo, curState.layerNumber, curState.stateNumber)) { + if (m->setSituation(rabVars->curThreadNo, curState.layerNumber, curState.stateNumber)) + { // calc value of situation m->letTheTreeGrow(&root, rabVars, m->depthOfFullTree, SKV_VALUE_GAME_LOST, SKV_VALUE_GAME_WON); - - } else { + } + else + { // should not occur, because already tested by plyInfo == PLYINFO_VALUE_UNCALCULATED MessageBoxW(nullptr, L"This event should never occur. if (!m->setSituation())", L"ERROR", MB_OK); } @@ -302,16 +335,16 @@ DWORD MiniMax::runAlphaBetaThreadProc(void *pParameter, int index) //----------------------------------------------------------------------------- // Name: letTheTreeGrow() -// Desc: +// Desc: //----------------------------------------------------------------------------- void MiniMax::letTheTreeGrow(Node *knot, RunAlphaBetaVars *rabVars, unsigned int tilLevel, float alpha, float beta) { // Locals void *pPossibilities; unsigned int *idPossibility; - unsigned int layerNumber = 0; // layer number of current state - unsigned int stateNumber = 0; // state number of current state - unsigned int maxWonfreqValuesSubMoves = 0; + unsigned int layerNumber = 0; // layer number of current state + unsigned int stateNumber = 0; // state number of current state + unsigned int maxWonfreqValuesSubMoves = 0; // standard values knot->branches = &rabVars->branchArray[(depthOfFullTree - tilLevel) * maxNumBranches]; @@ -324,43 +357,55 @@ void MiniMax::letTheTreeGrow(Node *knot, RunAlphaBetaVars *rabVars, unsigned int knot->floatValue = (float)knot->shortValue; // evaluate situation, musn't occur while calculating database - if (tilLevel == 0) { - if (calcDatabase) { + if (tilLevel == 0) + { + if (calcDatabase) + { // if tilLevel is equal zero it means that memory is gone out, since each recursive step needs memory PRINT(0, this, "ERROR: tilLevel == 0"); knot->shortValue = SKV_VALUE_INVALID; knot->plyInfo = PLYINFO_VALUE_INVALID; knot->floatValue = (float)knot->shortValue; falseOrStop(); - } else { + } + else + { getValueOfSituation(rabVars->curThreadNo, knot->floatValue, knot->shortValue); } // investigate branches - } else { + } + else + { // get layer and state number of current state and look if short knot value can be found in database or in an array - if (alphaBetaTryDataBase(knot, rabVars, tilLevel, layerNumber, stateNumber)) return; + if (alphaBetaTryDataBase(knot, rabVars, tilLevel, layerNumber, stateNumber)) + return; // get number of possiblities idPossibility = getPossibilities(rabVars->curThreadNo, &knot->numPossibilities, &knot->isOpponentLevel, &pPossibilities); // unable to move - if (knot->numPossibilities == 0) { + if (knot->numPossibilities == 0) + { // if unable to move a final state is reached knot->plyInfo = 0; getValueOfSituation(rabVars->curThreadNo, knot->floatValue, knot->shortValue); - if (tilLevel == depthOfFullTree - 1) rabVars->freqValuesSubMoves[knot->shortValue]++; + if (tilLevel == depthOfFullTree - 1) + rabVars->freqValuesSubMoves[knot->shortValue]++; // if unable to move an invalid state was reached if nobody has won - if (calcDatabase && knot->shortValue == SKV_VALUE_GAME_DRAWN) { + if (calcDatabase && knot->shortValue == SKV_VALUE_GAME_DRAWN) + { knot->shortValue = SKV_VALUE_INVALID; knot->plyInfo = PLYINFO_VALUE_INVALID; knot->floatValue = (float)knot->shortValue; } // movement is possible - } else { + } + else + { // move, letTreeGroe, undo alphaBetaTryPossibilites(knot, rabVars, tilLevel, idPossibility, pPossibilities, maxWonfreqValuesSubMoves, alpha, beta); @@ -375,14 +420,15 @@ void MiniMax::letTheTreeGrow(Node *knot, RunAlphaBetaVars *rabVars, unsigned int alphaBetaChooseBestMove(knot, rabVars, tilLevel, idPossibility, maxWonfreqValuesSubMoves); } - // save value and best branch into database and set value as valid - if (calcDatabase && hFileShortKnotValues && hFilePlyInfo) alphaBetaSaveInDatabase(rabVars->curThreadNo, layerNumber, stateNumber, knot->shortValue, knot->plyInfo, knot->isOpponentLevel); + // save value and best branch into database and set value as valid + if (calcDatabase && hFileShortKnotValues && hFilePlyInfo) + alphaBetaSaveInDatabase(rabVars->curThreadNo, layerNumber, stateNumber, knot->shortValue, knot->plyInfo, knot->isOpponentLevel); } } //----------------------------------------------------------------------------- // Name: alphaBetaTryDataBase() -// Desc: +// Desc: // 1 - Determines layerNumber and stateNumber for the given game situation. // 2 - Look into database if knot value and ply info are already calculated. If so sets knot->shortValue, knot->floatValue and knot->plyInfo. // CAUTION: knot->isOpponentLevel must be set and valid. @@ -390,13 +436,14 @@ void MiniMax::letTheTreeGrow(Node *knot, RunAlphaBetaVars *rabVars, unsigned int bool MiniMax::alphaBetaTryDataBase(Node *knot, RunAlphaBetaVars *rabVars, unsigned int tilLevel, unsigned int &layerNumber, unsigned int &stateNumber) { // locals - bool invalidLayerOrStateNumber; - bool subLayerInDatabaseAndCompleted; - TwoBit shortKnotValue = SKV_VALUE_INVALID; - PlyInfoVarType plyInfo = PLYINFO_VALUE_UNCALCULATED; + bool invalidLayerOrStateNumber; + bool subLayerInDatabaseAndCompleted; + TwoBit shortKnotValue = SKV_VALUE_INVALID; + PlyInfoVarType plyInfo = PLYINFO_VALUE_UNCALCULATED; // use database ? - if (hFilePlyInfo != nullptr && hFileShortKnotValues != nullptr && (calcDatabase || layerInDatabase)) { + if (hFilePlyInfo != nullptr && hFileShortKnotValues != nullptr && (calcDatabase || layerInDatabase)) + { // situation already existend in database ? readKnotValueFromDatabase(rabVars->curThreadNo, layerNumber, stateNumber, shortKnotValue, invalidLayerOrStateNumber, subLayerInDatabaseAndCompleted); @@ -404,9 +451,8 @@ bool MiniMax::alphaBetaTryDataBase(Node *knot, RunAlphaBetaVars *rabVars, unsign // it was possible to achieve an invalid state using move(), // so the original state was an invalid one - if ((tilLevel < depthOfFullTree && invalidLayerOrStateNumber) - || (tilLevel < depthOfFullTree && shortKnotValue == SKV_VALUE_INVALID && subLayerInDatabaseAndCompleted) - || (tilLevel < depthOfFullTree && shortKnotValue == SKV_VALUE_INVALID && plyInfo != PLYINFO_VALUE_UNCALCULATED)) { // version 22: replaced: curCalculatedLayer == layerNumber && knot->plyInfo != PLYINFO_VALUE_UNCALCULATED)) { + if ((tilLevel < depthOfFullTree && invalidLayerOrStateNumber) || (tilLevel < depthOfFullTree && shortKnotValue == SKV_VALUE_INVALID && subLayerInDatabaseAndCompleted) || (tilLevel < depthOfFullTree && shortKnotValue == SKV_VALUE_INVALID && plyInfo != PLYINFO_VALUE_UNCALCULATED)) + { // version 22: replaced: curCalculatedLayer == layerNumber && knot->plyInfo != PLYINFO_VALUE_UNCALCULATED)) { knot->shortValue = SKV_VALUE_INVALID; knot->plyInfo = PLYINFO_VALUE_INVALID; knot->floatValue = (float)knot->shortValue; @@ -414,17 +460,20 @@ bool MiniMax::alphaBetaTryDataBase(Node *knot, RunAlphaBetaVars *rabVars, unsign } // print out put, if not calculating database, but requesting a knot value - if (shortKnotValue != SKV_VALUE_INVALID && tilLevel == depthOfFullTree && !calcDatabase && subLayerInDatabaseAndCompleted) { + if (shortKnotValue != SKV_VALUE_INVALID && tilLevel == depthOfFullTree && !calcDatabase && subLayerInDatabaseAndCompleted) + { PRINT(2, this, "This state is marked as " << ((shortKnotValue == SKV_VALUE_GAME_WON) ? "WON" : ((shortKnotValue == SKV_VALUE_GAME_LOST) ? "LOST" : ((shortKnotValue == SKV_VALUE_GAME_DRAWN) ? "DRAW" : "INVALID"))) << endl); } // when knot value is valid then return best branch - if (calcDatabase && tilLevel < depthOfFullTree && shortKnotValue != SKV_VALUE_INVALID && plyInfo != PLYINFO_VALUE_UNCALCULATED - || !calcDatabase && tilLevel < depthOfFullTree - 1 && shortKnotValue != SKV_VALUE_INVALID) { + if (calcDatabase && tilLevel < depthOfFullTree && shortKnotValue != SKV_VALUE_INVALID && plyInfo != PLYINFO_VALUE_UNCALCULATED || !calcDatabase && tilLevel < depthOfFullTree - 1 && shortKnotValue != SKV_VALUE_INVALID) + { // switch if is not opponent level - if (knot->isOpponentLevel) knot->shortValue = skvPerspectiveMatrix[shortKnotValue][PL_TO_MOVE_UNCHANGED]; - else knot->shortValue = skvPerspectiveMatrix[shortKnotValue][PL_TO_MOVE_CHANGED]; + if (knot->isOpponentLevel) + knot->shortValue = skvPerspectiveMatrix[shortKnotValue][PL_TO_MOVE_UNCHANGED]; + else + knot->shortValue = skvPerspectiveMatrix[shortKnotValue][PL_TO_MOVE_CHANGED]; knot->floatValue = (float)knot->shortValue; knot->plyInfo = plyInfo; return true; @@ -435,18 +484,20 @@ bool MiniMax::alphaBetaTryDataBase(Node *knot, RunAlphaBetaVars *rabVars, unsign //----------------------------------------------------------------------------- // Name: alphaBetaTryPossibilites() -// Desc: +// Desc: //----------------------------------------------------------------------------- void MiniMax::alphaBetaTryPossibilites(Node *knot, RunAlphaBetaVars *rabVars, unsigned int tilLevel, unsigned int *idPossibility, void *pPossibilities, unsigned int &maxWonfreqValuesSubMoves, float &alpha, float &beta) { // locals void *pBackup; - unsigned int curPoss; + unsigned int curPoss; - for (curPoss = 0; curPoss < knot->numPossibilities; curPoss++) { + for (curPoss = 0; curPoss < knot->numPossibilities; curPoss++) + { // output - if (tilLevel == depthOfFullTree && !calcDatabase) { + if (tilLevel == depthOfFullTree && !calcDatabase) + { printMoveInformation(rabVars->curThreadNo, idPossibility[curPoss], pPossibilities); rabVars->freqValuesSubMoves[SKV_VALUE_INVALID] = 0; rabVars->freqValuesSubMoves[SKV_VALUE_GAME_LOST] = 0; @@ -463,76 +514,104 @@ void MiniMax::alphaBetaTryPossibilites(Node *knot, RunAlphaBetaVars *rabVars, un // undo move undo(rabVars->curThreadNo, idPossibility[curPoss], knot->isOpponentLevel, pBackup, pPossibilities); - // output - if (tilLevel == depthOfFullTree && !calcDatabase) { + // output + if (tilLevel == depthOfFullTree && !calcDatabase) + { rabVars->freqValuesSubMovesBranchWon[curPoss] = rabVars->freqValuesSubMoves[SKV_VALUE_GAME_WON]; - if (rabVars->freqValuesSubMoves[SKV_VALUE_GAME_WON] > maxWonfreqValuesSubMoves && knot->branches[curPoss].shortValue == SKV_VALUE_GAME_DRAWN) { + if (rabVars->freqValuesSubMoves[SKV_VALUE_GAME_WON] > maxWonfreqValuesSubMoves && knot->branches[curPoss].shortValue == SKV_VALUE_GAME_DRAWN) + { maxWonfreqValuesSubMoves = rabVars->freqValuesSubMoves[SKV_VALUE_GAME_WON]; } - if (hFileShortKnotValues != nullptr && layerInDatabase) { + if (hFileShortKnotValues != nullptr && layerInDatabase) + { storeValueOfMove(rabVars->curThreadNo, idPossibility[curPoss], pPossibilities, knot->branches[curPoss].shortValue, rabVars->freqValuesSubMoves, knot->branches[curPoss].plyInfo); PRINT(0, this, "\t: " << ((knot->branches[curPoss].shortValue == SKV_VALUE_GAME_WON) ? "WON" : ((knot->branches[curPoss].shortValue == SKV_VALUE_GAME_LOST) ? "LOST" : ((knot->branches[curPoss].shortValue == SKV_VALUE_GAME_DRAWN) ? "DRAW" : "INVALID"))) << endl); - } else { + } + else + { PRINT(0, this, "\t: " << knot->branches[curPoss].floatValue << endl); } - } else if (tilLevel == depthOfFullTree - 1 && !calcDatabase) { + } + else if (tilLevel == depthOfFullTree - 1 && !calcDatabase) + { rabVars->freqValuesSubMoves[knot->branches[curPoss].shortValue]++; } // don't use alpha beta if using database - if (hFileShortKnotValues != nullptr && calcDatabase) continue; - if (hFileShortKnotValues != nullptr && tilLevel + 1 >= depthOfFullTree) continue; + if (hFileShortKnotValues != nullptr && calcDatabase) + continue; + if (hFileShortKnotValues != nullptr && tilLevel + 1 >= depthOfFullTree) + continue; // alpha beta algorithmn - if (!knot->isOpponentLevel) { - if (knot->branches[curPoss].floatValue >= beta) { + if (!knot->isOpponentLevel) + { + if (knot->branches[curPoss].floatValue >= beta) + { knot->numPossibilities = curPoss + 1; break; - } else if (knot->branches[curPoss].floatValue > alpha) { + } + else if (knot->branches[curPoss].floatValue > alpha) + { alpha = knot->branches[curPoss].floatValue; } - } else { - if (knot->branches[curPoss].floatValue <= alpha) { + } + else + { + if (knot->branches[curPoss].floatValue <= alpha) + { knot->numPossibilities = curPoss + 1; break; - } else if (knot->branches[curPoss].floatValue < beta) { + } + else if (knot->branches[curPoss].floatValue < beta) + { beta = knot->branches[curPoss].floatValue; } } } // let delete pPossibilities - if (tilLevel < depthOfFullTree) { + if (tilLevel < depthOfFullTree) + { deletePossibilities(rabVars->curThreadNo, pPossibilities); - } else { + } + else + { pRootPossibilities = pPossibilities; } } //----------------------------------------------------------------------------- // Name: alphaBetaCalcKnotValue() -// Desc: +// Desc: //----------------------------------------------------------------------------- void MiniMax::alphaBetaCalcKnotValue(Node *knot) { // locals - float maxValue = knot->branches[0].floatValue; - unsigned int maxBranch = 0; - unsigned int i; + float maxValue = knot->branches[0].floatValue; + unsigned int maxBranch = 0; + unsigned int i; // opponent tries to minimize the value - if (knot->isOpponentLevel) { - for (i = 1; i < knot->numPossibilities; i++) { + if (knot->isOpponentLevel) + { + for (i = 1; i < knot->numPossibilities; i++) + { // version 21: it should be impossible that knot->shortValue is equal SKV_VALUE_INVALID - if (/*knot->shortValue != SKV_VALUE_INVALID && */knot->branches[i].floatValue < maxValue) { + if (/*knot->shortValue != SKV_VALUE_INVALID && */ knot->branches[i].floatValue < maxValue) + { maxValue = knot->branches[i].floatValue; maxBranch = i; } } // maximize the value - } else { - for (i = 1; i < knot->numPossibilities; i++) { - if (/*knot->shortValue != SKV_VALUE_INVALID && */knot->branches[i].floatValue > maxValue) { + } + else + { + for (i = 1; i < knot->numPossibilities; i++) + { + if (/*knot->shortValue != SKV_VALUE_INVALID && */ knot->branches[i].floatValue > maxValue) + { maxValue = knot->branches[i].floatValue; maxBranch = i; } @@ -546,22 +625,27 @@ void MiniMax::alphaBetaCalcKnotValue(Node *knot) //----------------------------------------------------------------------------- // Name: alphaBetaCalcPlyInfo() -// Desc: +// Desc: //----------------------------------------------------------------------------- void MiniMax::alphaBetaCalcPlyInfo(Node *knot) { // locals - unsigned int i; - unsigned int maxBranch; - PlyInfoVarType maxPlyInfo; - TwoBit shortKnotValue; + unsigned int i; + unsigned int maxBranch; + PlyInfoVarType maxPlyInfo; + TwoBit shortKnotValue; - // - if (knot->shortValue == SKV_VALUE_GAME_DRAWN) { + // + if (knot->shortValue == SKV_VALUE_GAME_DRAWN) + { knot->plyInfo = PLYINFO_VALUE_DRAWN; - } else if (knot->shortValue == SKV_VALUE_INVALID) { + } + else if (knot->shortValue == SKV_VALUE_INVALID) + { knot->plyInfo = PLYINFO_VALUE_INVALID; - } else { + } + else + { // calculate value of knot shortKnotValue = (knot->isOpponentLevel) ? skvPerspectiveMatrix[knot->shortValue][PL_TO_MOVE_UNCHANGED] : knot->shortValue; @@ -569,9 +653,11 @@ void MiniMax::alphaBetaCalcPlyInfo(Node *knot) maxBranch = 0; // when current knot is a won state - if (shortKnotValue == SKV_VALUE_GAME_WON) { + if (shortKnotValue == SKV_VALUE_GAME_WON) + { - for (i = 0; i < knot->numPossibilities; i++) { + for (i = 0; i < knot->numPossibilities; i++) + { // invert knot value if necessary shortKnotValue = (knot->branches[i].isOpponentLevel) ? skvPerspectiveMatrix[knot->branches[i].shortValue][PL_TO_MOVE_UNCHANGED] : knot->branches[i].shortValue; @@ -580,7 +666,8 @@ void MiniMax::alphaBetaCalcPlyInfo(Node *knot) if ((knot->branches[i].plyInfo < maxPlyInfo && shortKnotValue == SKV_VALUE_GAME_LOST && knot->isOpponentLevel != knot->branches[i].isOpponentLevel) // after this move the same player will continue, so take the minimum of the won states - || (knot->branches[i].plyInfo < maxPlyInfo && shortKnotValue == SKV_VALUE_GAME_WON && knot->isOpponentLevel == knot->branches[i].isOpponentLevel)) { + || (knot->branches[i].plyInfo < maxPlyInfo && shortKnotValue == SKV_VALUE_GAME_WON && knot->isOpponentLevel == knot->branches[i].isOpponentLevel)) + { maxPlyInfo = knot->branches[i].plyInfo; maxBranch = i; @@ -588,9 +675,12 @@ void MiniMax::alphaBetaCalcPlyInfo(Node *knot) } // current state is a lost state - } else { + } + else + { - for (i = 0; i < knot->numPossibilities; i++) { + for (i = 0; i < knot->numPossibilities; i++) + { // invert knot value if necessary shortKnotValue = (knot->branches[i].isOpponentLevel) ? skvPerspectiveMatrix[knot->branches[i].shortValue][PL_TO_MOVE_UNCHANGED] : knot->branches[i].shortValue; @@ -599,7 +689,8 @@ void MiniMax::alphaBetaCalcPlyInfo(Node *knot) if ((knot->branches[i].plyInfo > maxPlyInfo && shortKnotValue == SKV_VALUE_GAME_WON && knot->isOpponentLevel != knot->branches[i].isOpponentLevel) // take the maximum of the won states, since that's the longest path - || (knot->branches[i].plyInfo > maxPlyInfo && shortKnotValue == SKV_VALUE_GAME_LOST && knot->isOpponentLevel == knot->branches[i].isOpponentLevel)) { + || (knot->branches[i].plyInfo > maxPlyInfo && shortKnotValue == SKV_VALUE_GAME_LOST && knot->isOpponentLevel == knot->branches[i].isOpponentLevel)) + { maxPlyInfo = knot->branches[i].plyInfo; maxBranch = i; @@ -619,44 +710,56 @@ void MiniMax::alphaBetaCalcPlyInfo(Node *knot) void MiniMax::alphaBetaChooseBestMove(Node *knot, RunAlphaBetaVars *rabVars, unsigned int tilLevel, unsigned int *idPossibility, unsigned int maxWonfreqValuesSubMoves) { // locals - float dif; - unsigned int numBestChoices = 0; + float dif; + unsigned int numBestChoices = 0; unsigned int *bestBranches = new unsigned int[maxNumBranches]; - unsigned int i; - unsigned int maxBranch; + unsigned int i; + unsigned int maxBranch; // select randomly one of the best moves, if they are equivalent - if (tilLevel == depthOfFullTree && !calcDatabase) { + if (tilLevel == depthOfFullTree && !calcDatabase) + { // check every possible move - for (numBestChoices = 0, i = 0; i < knot->numPossibilities; i++) { + for (numBestChoices = 0, i = 0; i < knot->numPossibilities; i++) + { // use information in database - if (layerInDatabase && hFileShortKnotValues != nullptr) { + if (layerInDatabase && hFileShortKnotValues != nullptr) + { // selected move with equal knot value - if (knot->branches[i].shortValue == knot->shortValue) { + if (knot->branches[i].shortValue == knot->shortValue) + { // best move lead to drawn state - if (knot->shortValue == SKV_VALUE_GAME_DRAWN) { - if (maxWonfreqValuesSubMoves == rabVars->freqValuesSubMovesBranchWon[i]) { + if (knot->shortValue == SKV_VALUE_GAME_DRAWN) + { + if (maxWonfreqValuesSubMoves == rabVars->freqValuesSubMovesBranchWon[i]) + { bestBranches[numBestChoices] = i; numBestChoices++; } // best move lead to lost or won state - } else { - if (knot->plyInfo == knot->branches[i].plyInfo + 1) { + } + else + { + if (knot->plyInfo == knot->branches[i].plyInfo + 1) + { bestBranches[numBestChoices] = i; numBestChoices++; } } } // conventionell mini-max algorithm - } else { + } + else + { dif = knot->branches[i].floatValue - knot->floatValue; dif = (dif > 0) ? dif : -1.0f * dif; - if (dif < FPKV_THRESHOLD) { + if (dif < FPKV_THRESHOLD) + { bestBranches[numBestChoices] = i; numBestChoices++; } diff --git a/src/perfect/miniMax_database.cpp b/src/perfect/miniMax_database.cpp index 6d7a329d..e8f60b1d 100644 --- a/src/perfect/miniMax_database.cpp +++ b/src/perfect/miniMax_database.cpp @@ -15,7 +15,8 @@ void MiniMax::closeDatabase() { // close database - if (hFileShortKnotValues != nullptr) { + if (hFileShortKnotValues != nullptr) + { unloadAllLayers(); SAFE_DELETE_ARRAY(layerStats); CloseHandle(hFileShortKnotValues); @@ -23,7 +24,8 @@ void MiniMax::closeDatabase() } // close ply information file - if (hFilePlyInfo != nullptr) { + if (hFilePlyInfo != nullptr) + { unloadAllPlyInfos(); SAFE_DELETE_ARRAY(plyInfos); CloseHandle(hFilePlyInfo); @@ -33,7 +35,7 @@ void MiniMax::closeDatabase() //----------------------------------------------------------------------------- // Name: unloadPlyInfo() -// Desc: +// Desc: //----------------------------------------------------------------------------- void MiniMax::unloadPlyInfo(unsigned int layerNumber) { @@ -46,7 +48,7 @@ void MiniMax::unloadPlyInfo(unsigned int layerNumber) //----------------------------------------------------------------------------- // Name: unloadLayer() -// Desc: +// Desc: //----------------------------------------------------------------------------- void MiniMax::unloadLayer(unsigned int layerNumber) { @@ -59,51 +61,61 @@ void MiniMax::unloadLayer(unsigned int layerNumber) //----------------------------------------------------------------------------- // Name: unloadAllPlyInfos() -// Desc: +// Desc: //----------------------------------------------------------------------------- void MiniMax::unloadAllPlyInfos() { - for (unsigned int i = 0; i < plyInfoHeader.numLayers; i++) { + for (unsigned int i = 0; i < plyInfoHeader.numLayers; i++) + { unloadPlyInfo(i); } } //----------------------------------------------------------------------------- // Name: unloadAllLayers() -// Desc: +// Desc: //----------------------------------------------------------------------------- void MiniMax::unloadAllLayers() { - for (unsigned int i = 0; i < skvfHeader.numLayers; i++) { + for (unsigned int i = 0; i < skvfHeader.numLayers; i++) + { unloadLayer(i); } } //----------------------------------------------------------------------------- // Name: saveBytesToFile() -// Desc: +// Desc: //----------------------------------------------------------------------------- void MiniMax::saveBytesToFile(HANDLE hFile, long long offset, unsigned int numBytes, void *pBytes) { - DWORD dwBytesWritten; - LARGE_INTEGER liDistanceToMove; - unsigned int restingBytes = numBytes; + DWORD dwBytesWritten; + LARGE_INTEGER liDistanceToMove; + unsigned int restingBytes = numBytes; void *myPointer = pBytes; - bool errorPrint = false; + bool errorPrint = false; liDistanceToMove.QuadPart = offset; - while (errorPrint = !SetFilePointerEx(hFile, liDistanceToMove, nullptr, FILE_BEGIN)) { - if (!errorPrint) PRINT(1, this, "ERROR: SetFilePointerEx failed!"); + while (errorPrint = !SetFilePointerEx(hFile, liDistanceToMove, nullptr, FILE_BEGIN)) + { + if (!errorPrint) + PRINT(1, this, "ERROR: SetFilePointerEx failed!"); } - while (restingBytes > 0) { - if (WriteFile(hFile, myPointer, restingBytes, &dwBytesWritten, nullptr) == TRUE) { + while (restingBytes > 0) + { + if (WriteFile(hFile, myPointer, restingBytes, &dwBytesWritten, nullptr) == TRUE) + { restingBytes -= dwBytesWritten; myPointer = (void *)(((unsigned char *)myPointer) + dwBytesWritten); - if (restingBytes > 0) PRINT(2, this, "Still " << restingBytes << " to write!"); - } else { - if (!errorPrint) PRINT(0, this, "ERROR: WriteFile Failed!"); + if (restingBytes > 0) + PRINT(2, this, "Still " << restingBytes << " to write!"); + } + else + { + if (!errorPrint) + PRINT(0, this, "ERROR: WriteFile Failed!"); errorPrint = true; } } @@ -111,31 +123,39 @@ void MiniMax::saveBytesToFile(HANDLE hFile, long long offset, unsigned int numBy //----------------------------------------------------------------------------- // Name: loadBytesFromFile() -// Desc: +// Desc: //----------------------------------------------------------------------------- void MiniMax::loadBytesFromFile(HANDLE hFile, long long offset, unsigned int numBytes, void *pBytes) { - DWORD dwBytesRead; - LARGE_INTEGER liDistanceToMove; - unsigned int restingBytes = numBytes; + DWORD dwBytesRead; + LARGE_INTEGER liDistanceToMove; + unsigned int restingBytes = numBytes; void *myPointer = pBytes; - bool errorPrint = false; + bool errorPrint = false; liDistanceToMove.QuadPart = offset; - while (errorPrint = !SetFilePointerEx(hFile, liDistanceToMove, nullptr, FILE_BEGIN)) { - if (!errorPrint) PRINT(0, this, "ERROR: SetFilePointerEx failed!"); + while (errorPrint = !SetFilePointerEx(hFile, liDistanceToMove, nullptr, FILE_BEGIN)) + { + if (!errorPrint) + PRINT(0, this, "ERROR: SetFilePointerEx failed!"); } - while (restingBytes > 0) { - if (ReadFile(hFile, pBytes, restingBytes, &dwBytesRead, nullptr) == TRUE) { + while (restingBytes > 0) + { + if (ReadFile(hFile, pBytes, restingBytes, &dwBytesRead, nullptr) == TRUE) + { restingBytes -= dwBytesRead; myPointer = (void *)(((unsigned char *)myPointer) + dwBytesRead); - if (restingBytes > 0) { + if (restingBytes > 0) + { PRINT(2, this, "Still " << restingBytes << " bytes to read!"); } - } else { - if (!errorPrint) PRINT(0, this, "ERROR: ReadFile Failed!"); + } + else + { + if (!errorPrint) + PRINT(0, this, "ERROR: ReadFile Failed!"); errorPrint = true; } } @@ -143,15 +163,18 @@ void MiniMax::loadBytesFromFile(HANDLE hFile, long long offset, unsigned int num //----------------------------------------------------------------------------- // Name: isCurrentStateInDatabase() -// Desc: +// Desc: //----------------------------------------------------------------------------- bool MiniMax::isCurrentStateInDatabase(unsigned int threadNo) { unsigned int layerNum, stateNumber; - if (hFileShortKnotValues == nullptr) { + if (hFileShortKnotValues == nullptr) + { return false; - } else { + } + else + { getLayerAndStateNumber(threadNo, layerNum, stateNumber); return layerStats[layerNum].layerIsCompletedAndInFile; } @@ -159,7 +182,7 @@ bool MiniMax::isCurrentStateInDatabase(unsigned int threadNo) //----------------------------------------------------------------------------- // Name: saveHeader() -// Desc: +// Desc: //----------------------------------------------------------------------------- void MiniMax::saveHeader(SkvFileHeader *dbH, LayerStats *lStats) { @@ -171,7 +194,7 @@ void MiniMax::saveHeader(SkvFileHeader *dbH, LayerStats *lStats) //----------------------------------------------------------------------------- // Name: saveHeader() -// Desc: +// Desc: //----------------------------------------------------------------------------- void MiniMax::saveHeader(PlyInfoFileHeader *piH, PlyInfo *pInfo) { @@ -183,11 +206,12 @@ void MiniMax::saveHeader(PlyInfoFileHeader *piH, PlyInfo *pInfo) //----------------------------------------------------------------------------- // Name: openDatabase() -// Desc: +// Desc: //----------------------------------------------------------------------------- bool MiniMax::openDatabase(const char *directory, unsigned int maximumNumberOfBranches) { - if (strlen(directory) && !PathFileExistsA(directory)) { + if (strlen(directory) && !PathFileExistsA(directory)) + { PRINT(0, this, "ERROR: Database path " << directory << " not valid!"); return falseOrStop(); } @@ -198,17 +222,18 @@ bool MiniMax::openDatabase(const char *directory, unsigned int maximumNumberOfBr //----------------------------------------------------------------------------- // Name: openSkvFile() -// Desc: +// Desc: //----------------------------------------------------------------------------- void MiniMax::openSkvFile(const char *directory, unsigned int maximumNumberOfBranches) { // locals - stringstream ssDatabaseFile; - DWORD dwBytesRead; - unsigned int i; + stringstream ssDatabaseFile; + DWORD dwBytesRead; + unsigned int i; // don't open file twice - if (hFileShortKnotValues != nullptr) return; + if (hFileShortKnotValues != nullptr) + return; // remember directory name fileDirectory.assign(directory); @@ -219,7 +244,8 @@ void MiniMax::openSkvFile(const char *directory, unsigned int maximumNumberOfBra hFileShortKnotValues = CreateFileA(ssDatabaseFile.str().c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); // opened file succesfully - if (hFileShortKnotValues == INVALID_HANDLE_VALUE) { + if (hFileShortKnotValues == INVALID_HANDLE_VALUE) + { hFileShortKnotValues = nullptr; return; } @@ -232,7 +258,8 @@ void MiniMax::openSkvFile(const char *directory, unsigned int maximumNumberOfBra ReadFile(hFileShortKnotValues, &skvfHeader, sizeof(SkvFileHeader), &dwBytesRead, nullptr); // invalid file ? - if (dwBytesRead != sizeof(SkvFileHeader) || skvfHeader.headerCode != SKV_FILE_HEADER_CODE) { + if (dwBytesRead != sizeof(SkvFileHeader) || skvfHeader.headerCode != SKV_FILE_HEADER_CODE) + { // create default header skvfHeader.completed = false; @@ -242,7 +269,8 @@ void MiniMax::openSkvFile(const char *directory, unsigned int maximumNumberOfBra layerStats = new LayerStats[skvfHeader.numLayers]; layerStats[0].layerOffset = 0; - for (i = 0; i < skvfHeader.numLayers; i++) { + for (i = 0; i < skvfHeader.numLayers; i++) + { getSuccLayers(i, &layerStats[i].numSuccLayers, &layerStats[i].succLayers[0]); layerStats[i].partnerLayer = getPartnerLayer(i); layerStats[i].knotsInLayer = getNumberOfKnotsInLayer(i); @@ -257,7 +285,8 @@ void MiniMax::openSkvFile(const char *directory, unsigned int maximumNumberOfBra layerStats[i].numInvalidStates = 0; } - for (i = 1; i < skvfHeader.numLayers; i++) { + for (i = 1; i < skvfHeader.numLayers; i++) + { layerStats[i].layerOffset = layerStats[i - 1].layerOffset + layerStats[i - 1].sizeInBytes; } @@ -265,10 +294,13 @@ void MiniMax::openSkvFile(const char *directory, unsigned int maximumNumberOfBra saveHeader(&skvfHeader, layerStats); // read layer stats - } else { + } + else + { layerStats = new LayerStats[skvfHeader.numLayers]; ReadFile(hFileShortKnotValues, layerStats, sizeof(LayerStats) * skvfHeader.numLayers, &dwBytesRead, nullptr); - for (i = 0; i < skvfHeader.numLayers; i++) { + for (i = 0; i < skvfHeader.numLayers; i++) + { layerStats[i].shortKnotValueByte = nullptr; layerStats[i].skvCompressed = nullptr; } @@ -277,27 +309,30 @@ void MiniMax::openSkvFile(const char *directory, unsigned int maximumNumberOfBra //----------------------------------------------------------------------------- // Name: openPlyInfoFile() -// Desc: +// Desc: //----------------------------------------------------------------------------- void MiniMax::openPlyInfoFile(const char *directory) { // locals - stringstream ssFile; - DWORD dwBytesRead; - unsigned int i; + stringstream ssFile; + DWORD dwBytesRead; + unsigned int i; // don't open file twice - if (hFilePlyInfo != nullptr) return; + if (hFilePlyInfo != nullptr) + return; // remember directory name ssFile << directory << (strlen(directory) ? "\\" : "") << "plyInfo.dat"; - PRINT(2, this, "Open ply info file: " << ssFile.str() << endl << endl); + PRINT(2, this, "Open ply info file: " << ssFile.str() << endl + << endl); // Open Database-File (FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_RANDOM_ACCESS) hFilePlyInfo = CreateFileA(ssFile.str().c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); // opened file succesfully - if (hFilePlyInfo == INVALID_HANDLE_VALUE) { + if (hFilePlyInfo == INVALID_HANDLE_VALUE) + { hFilePlyInfo = nullptr; return; } @@ -309,7 +344,8 @@ void MiniMax::openPlyInfoFile(const char *directory) ReadFile(hFilePlyInfo, &plyInfoHeader, sizeof(plyInfoHeader), &dwBytesRead, nullptr); // invalid file ? - if (dwBytesRead != sizeof(plyInfoHeader) || plyInfoHeader.headerCode != PLYINFO_HEADER_CODE) { + if (dwBytesRead != sizeof(plyInfoHeader) || plyInfoHeader.headerCode != PLYINFO_HEADER_CODE) + { // create default header plyInfoHeader.plyInfoCompleted = false; @@ -319,7 +355,8 @@ void MiniMax::openPlyInfoFile(const char *directory) plyInfos = new PlyInfo[plyInfoHeader.numLayers]; plyInfos[0].layerOffset = 0; - for (i = 0; i < plyInfoHeader.numLayers; i++) { + for (i = 0; i < plyInfoHeader.numLayers; i++) + { plyInfos[i].knotsInLayer = getNumberOfKnotsInLayer(i); plyInfos[i].plyInfo = nullptr; plyInfos[i].plyInfoCompressed = nullptr; @@ -328,7 +365,8 @@ void MiniMax::openPlyInfoFile(const char *directory) plyInfos[i].sizeInBytes = plyInfos[i].knotsInLayer * sizeof(PlyInfoVarType); } - for (i = 1; i < plyInfoHeader.numLayers; i++) { + for (i = 1; i < plyInfoHeader.numLayers; i++) + { plyInfos[i].layerOffset = plyInfos[i - 1].layerOffset + plyInfos[i - 1].sizeInBytes; } @@ -336,10 +374,13 @@ void MiniMax::openPlyInfoFile(const char *directory) saveHeader(&plyInfoHeader, plyInfos); // read layer stats - } else { + } + else + { plyInfos = new PlyInfo[plyInfoHeader.numLayers]; ReadFile(hFilePlyInfo, plyInfos, sizeof(PlyInfo) * plyInfoHeader.numLayers, &dwBytesRead, nullptr); - for (i = 0; i < plyInfoHeader.numLayers; i++) { + for (i = 0; i < plyInfoHeader.numLayers; i++) + { plyInfos[i].plyInfo = nullptr; plyInfos[i].plyInfoCompressed = nullptr; } @@ -348,17 +389,19 @@ void MiniMax::openPlyInfoFile(const char *directory) //----------------------------------------------------------------------------- // Name: saveLayerToFile() -// Desc: +// Desc: //----------------------------------------------------------------------------- void MiniMax::saveLayerToFile(unsigned int layerNumber) { // don't save layer and header when only preparing layers PlyInfo *myPis = &plyInfos[layerNumber]; LayerStats *myLss = &layerStats[layerNumber]; - if (onlyPrepareLayer) return; + if (onlyPrepareLayer) + return; // save layer if there are any states - if (myLss->sizeInBytes) { + if (myLss->sizeInBytes) + { // short knot values & ply info curCalculationActionId = MM_ACTION_SAVING_LAYER_TO_FILE; @@ -373,39 +416,44 @@ void MiniMax::saveLayerToFile(unsigned int layerNumber) //----------------------------------------------------------------------------- // Name: measureIops() -// Desc: +// Desc: //----------------------------------------------------------------------------- inline void MiniMax::measureIops(long long &numOperations, LARGE_INTEGER &interval, LARGE_INTEGER &curTimeBefore, char text[]) { // locals LARGE_INTEGER curTimeAfter; - if (!MEASURE_IOPS) return; - numOperations++; // ... not thread-safe !!! + if (!MEASURE_IOPS) + return; + numOperations++; // ... not thread-safe !!! // only the time for the io-operation is considered and accumulated - if (MEASURE_ONLY_IO) { + if (MEASURE_ONLY_IO) + { QueryPerformanceCounter(&curTimeAfter); - interval.QuadPart += curTimeAfter.QuadPart - curTimeBefore.QuadPart; // ... not thread-safe !!! - double totalTimeGone = (double)interval.QuadPart / frequency.QuadPart; // ... not thread-safe !!! - if (totalTimeGone >= 5.0) { + interval.QuadPart += curTimeAfter.QuadPart - curTimeBefore.QuadPart; // ... not thread-safe !!! + double totalTimeGone = (double)interval.QuadPart / frequency.QuadPart; // ... not thread-safe !!! + if (totalTimeGone >= 5.0) + { PRINT(0, this, text << "operations per second for last interval: " << (int)(numOperations / totalTimeGone)); - interval.QuadPart = 0; // ... not thread-safe !!! - numOperations = 0; // ... not thread-safe !!! + interval.QuadPart = 0; // ... not thread-safe !!! + numOperations = 0; // ... not thread-safe !!! } // the whole time passed since the beginning of the interval is considered - } else if (numOperations >= MEASURE_TIME_FREQUENCY) { + } + else if (numOperations >= MEASURE_TIME_FREQUENCY) + { QueryPerformanceCounter(&curTimeAfter); - double totalTimeGone = (double)(curTimeAfter.QuadPart - interval.QuadPart) / frequency.QuadPart; // ... not thread-safe !!! + double totalTimeGone = (double)(curTimeAfter.QuadPart - interval.QuadPart) / frequency.QuadPart; // ... not thread-safe !!! PRINT(0, this, text << "operations per second for last interval: " << numOperations / totalTimeGone); - interval.QuadPart = curTimeAfter.QuadPart; // ... not thread-safe !!! - numOperations = 0; // ... not thread-safe !!! + interval.QuadPart = curTimeAfter.QuadPart; // ... not thread-safe !!! + numOperations = 0; // ... not thread-safe !!! } } //----------------------------------------------------------------------------- // Name: readKnotValueFromDatabase() -// Desc: +// Desc: //----------------------------------------------------------------------------- void MiniMax::readKnotValueFromDatabase(unsigned int threadNo, unsigned int &layerNumber, unsigned int &stateNumber, TwoBit &knotValue, bool &invalidLayerOrStateNumber, bool &layerInDatabaseAndCompleted) { @@ -417,13 +465,17 @@ void MiniMax::readKnotValueFromDatabase(unsigned int threadNo, unsigned int &lay layerInDatabaseAndCompleted = myLss->layerIsCompletedAndInFile; // valid state and layer number ? - if (layerNumber > skvfHeader.numLayers || stateNumber > myLss->knotsInLayer) { + if (layerNumber > skvfHeader.numLayers || stateNumber > myLss->knotsInLayer) + { invalidLayerOrStateNumber = true; - } else { + } + else + { invalidLayerOrStateNumber = false; // checkStateIntegrity(); } - if (invalidLayerOrStateNumber) { + if (invalidLayerOrStateNumber) + { knotValue = SKV_VALUE_INVALID; return; } @@ -434,40 +486,49 @@ void MiniMax::readKnotValueFromDatabase(unsigned int threadNo, unsigned int &lay //----------------------------------------------------------------------------- // Name: readKnotValueFromDatabase() -// Desc: +// Desc: //----------------------------------------------------------------------------- void MiniMax::readKnotValueFromDatabase(unsigned int layerNumber, unsigned int stateNumber, TwoBit &knotValue) { // locals - TwoBit databaseByte; - long long bytesAllocated; - TwoBit defValue = SKV_WHOLE_BYTE_IS_INVALID; + TwoBit databaseByte; + long long bytesAllocated; + TwoBit defValue = SKV_WHOLE_BYTE_IS_INVALID; LayerStats *myLss = &layerStats[layerNumber]; // valid state and layer number ? - if (layerNumber > skvfHeader.numLayers || stateNumber > myLss->knotsInLayer) { + if (layerNumber > skvfHeader.numLayers || stateNumber > myLss->knotsInLayer) + { PRINT(0, this, "ERROR: INVALID layerNumber OR stateNumber in readKnotValueFromDatabase()!"); knotValue = SKV_VALUE_INVALID; return; } // if database is complete get whole byte from file - if (skvfHeader.completed || layerInDatabase || myLss->layerIsCompletedAndInFile) { + if (skvfHeader.completed || layerInDatabase || myLss->layerIsCompletedAndInFile) + { EnterCriticalSection(&csDatabase); loadBytesFromFile(hFileShortKnotValues, skvfHeader.headerAndStatsSize + myLss->layerOffset + stateNumber / 4, 1, &databaseByte); LeaveCriticalSection(&csDatabase); - } else { + } + else + { // is layer already loaded - if (!myLss->layerIsLoaded) { + if (!myLss->layerIsLoaded) + { EnterCriticalSection(&csDatabase); - if (!myLss->layerIsLoaded) { + if (!myLss->layerIsLoaded) + { // if layer is in database and completed, then load layer from file into memory, set default value otherwise myLss->shortKnotValueByte = new unsigned char[myLss->sizeInBytes]; - if (myLss->layerIsCompletedAndInFile) { + if (myLss->layerIsCompletedAndInFile) + { loadBytesFromFile(hFileShortKnotValues, skvfHeader.headerAndStatsSize + myLss->layerOffset, myLss->sizeInBytes, myLss->shortKnotValueByte); - } else { + } + else + { memset(myLss->shortKnotValueByte, SKV_WHOLE_BYTE_IS_INVALID, myLss->sizeInBytes); } bytesAllocated = myLss->sizeInBytes; @@ -483,7 +544,8 @@ void MiniMax::readKnotValueFromDatabase(unsigned int layerNumber, unsigned int s // measure io-operations per second LARGE_INTEGER curTimeBefore; - if (MEASURE_IOPS && MEASURE_ONLY_IO) { + if (MEASURE_IOPS && MEASURE_ONLY_IO) + { QueryPerformanceCounter(&curTimeBefore); } @@ -500,40 +562,50 @@ void MiniMax::readKnotValueFromDatabase(unsigned int layerNumber, unsigned int s //----------------------------------------------------------------------------- // Name: readPlyInfoFromDatabase() -// Desc: +// Desc: //----------------------------------------------------------------------------- void MiniMax::readPlyInfoFromDatabase(unsigned int layerNumber, unsigned int stateNumber, PlyInfoVarType &value) { // locals - unsigned int curKnot; - PlyInfoVarType defValue = PLYINFO_VALUE_UNCALCULATED; - long long bytesAllocated; + unsigned int curKnot; + PlyInfoVarType defValue = PLYINFO_VALUE_UNCALCULATED; + long long bytesAllocated; PlyInfo *myPis = &plyInfos[layerNumber]; // valid state and layer number ? - if (layerNumber > plyInfoHeader.numLayers || stateNumber > myPis->knotsInLayer) { + if (layerNumber > plyInfoHeader.numLayers || stateNumber > myPis->knotsInLayer) + { PRINT(0, this, "ERROR: INVALID layerNumber OR stateNumber in readPlyInfoFromDatabase()!"); value = PLYINFO_VALUE_INVALID; return; } // if database is complete get whole byte from file - if (plyInfoHeader.plyInfoCompleted || layerInDatabase || myPis->plyInfoIsCompletedAndInFile) { + if (plyInfoHeader.plyInfoCompleted || layerInDatabase || myPis->plyInfoIsCompletedAndInFile) + { EnterCriticalSection(&csDatabase); loadBytesFromFile(hFilePlyInfo, plyInfoHeader.headerAndPlyInfosSize + myPis->layerOffset + sizeof(PlyInfoVarType) * stateNumber, sizeof(PlyInfoVarType), &value); LeaveCriticalSection(&csDatabase); - } else { + } + else + { // is layer already in memory? - if (!myPis->plyInfoIsLoaded) { + if (!myPis->plyInfoIsLoaded) + { EnterCriticalSection(&csDatabase); - if (!myPis->plyInfoIsLoaded) { + if (!myPis->plyInfoIsLoaded) + { // if layer is in database and completed, then load layer from file into memory; set default value otherwise myPis->plyInfo = new PlyInfoVarType[myPis->knotsInLayer]; - if (myPis->plyInfoIsCompletedAndInFile) { + if (myPis->plyInfoIsCompletedAndInFile) + { loadBytesFromFile(hFilePlyInfo, plyInfoHeader.headerAndPlyInfosSize + myPis->layerOffset, myPis->sizeInBytes, myPis->plyInfo); - } else { - for (curKnot = 0; curKnot < myPis->knotsInLayer; curKnot++) { + } + else + { + for (curKnot = 0; curKnot < myPis->knotsInLayer; curKnot++) + { myPis->plyInfo[curKnot] = defValue; } } @@ -548,7 +620,8 @@ void MiniMax::readPlyInfoFromDatabase(unsigned int layerNumber, unsigned int sta // measure io-operations per second LARGE_INTEGER curTimeBefore; - if (MEASURE_IOPS && MEASURE_ONLY_IO) { + if (MEASURE_IOPS && MEASURE_ONLY_IO) + { QueryPerformanceCounter(&curTimeBefore); } @@ -562,32 +635,36 @@ void MiniMax::readPlyInfoFromDatabase(unsigned int layerNumber, unsigned int sta //----------------------------------------------------------------------------- // Name: saveKnotValueInDatabase() -// Desc: +// Desc: //----------------------------------------------------------------------------- void MiniMax::saveKnotValueInDatabase(unsigned int layerNumber, unsigned int stateNumber, TwoBit knotValue) { // locals - long long bytesAllocated; - TwoBit defValue = SKV_WHOLE_BYTE_IS_INVALID; + long long bytesAllocated; + TwoBit defValue = SKV_WHOLE_BYTE_IS_INVALID; LayerStats *myLss = &layerStats[layerNumber]; // valid state and layer number ? - if (layerNumber > skvfHeader.numLayers || stateNumber > myLss->knotsInLayer) { + if (layerNumber > skvfHeader.numLayers || stateNumber > myLss->knotsInLayer) + { PRINT(0, this, "ERROR: INVALID layerNumber OR stateNumber in saveKnotValueInDatabase()!"); return; } // is layer already completed ? - if (myLss->layerIsCompletedAndInFile) { + if (myLss->layerIsCompletedAndInFile) + { PRINT(0, this, "ERROR: layer already completed and in file! function: saveKnotValueInDatabase()!"); return; } // is layer already loaded? - if (!myLss->layerIsLoaded) { + if (!myLss->layerIsLoaded) + { EnterCriticalSection(&csDatabase); - if (!myLss->layerIsLoaded) { + if (!myLss->layerIsLoaded) + { // reserve memory for this layer & create array for ply info with default value myLss->shortKnotValueByte = new TwoBit[myLss->sizeInBytes]; memset(myLss->shortKnotValueByte, SKV_WHOLE_BYTE_IS_INVALID, myLss->sizeInBytes); @@ -604,17 +681,19 @@ void MiniMax::saveKnotValueInDatabase(unsigned int layerNumber, unsigned int sta // measure io-operations per second LARGE_INTEGER curTimeBefore; - if (MEASURE_IOPS && MEASURE_ONLY_IO) { + if (MEASURE_IOPS && MEASURE_ONLY_IO) + { QueryPerformanceCounter(&curTimeBefore); } // set value long *pShortKnotValue = ((long *)myLss->shortKnotValueByte) + stateNumber / ((sizeof(long) * 8) / 2); - long numBitsToShift = 2 * (stateNumber % ((sizeof(long) * 8) / 2)); // little-endian byte-order - long mask = 0x00000003 << numBitsToShift; - long curShortKnotValueLong, newShortKnotValueLong; + long numBitsToShift = 2 * (stateNumber % ((sizeof(long) * 8) / 2)); // little-endian byte-order + long mask = 0x00000003 << numBitsToShift; + long curShortKnotValueLong, newShortKnotValueLong; - do { + do + { curShortKnotValueLong = *pShortKnotValue; newShortKnotValueLong = (curShortKnotValueLong & (~mask)) + (knotValue << numBitsToShift); } while (InterlockedCompareExchange(pShortKnotValue, newShortKnotValueLong, curShortKnotValueLong) != curShortKnotValueLong); @@ -625,36 +704,41 @@ void MiniMax::saveKnotValueInDatabase(unsigned int layerNumber, unsigned int sta //----------------------------------------------------------------------------- // Name: savePlyInfoInDatabase() -// Desc: +// Desc: //----------------------------------------------------------------------------- void MiniMax::savePlyInfoInDatabase(unsigned int layerNumber, unsigned int stateNumber, PlyInfoVarType value) { // locals - unsigned int curKnot; - PlyInfoVarType defValue = PLYINFO_VALUE_UNCALCULATED; - long long bytesAllocated; + unsigned int curKnot; + PlyInfoVarType defValue = PLYINFO_VALUE_UNCALCULATED; + long long bytesAllocated; PlyInfo *myPis = &plyInfos[layerNumber]; // valid state and layer number ? - if (layerNumber > plyInfoHeader.numLayers || stateNumber > myPis->knotsInLayer) { + if (layerNumber > plyInfoHeader.numLayers || stateNumber > myPis->knotsInLayer) + { PRINT(0, this, "ERROR: INVALID layerNumber OR stateNumber in savePlyInfoInDatabase()!"); return; } // is layer already completed ? - if (myPis->plyInfoIsCompletedAndInFile) { + if (myPis->plyInfoIsCompletedAndInFile) + { PRINT(0, this, "ERROR: layer already completed and in file! function: savePlyInfoInDatabase()!"); return; } // is layer already loaded - if (!myPis->plyInfoIsLoaded) { + if (!myPis->plyInfoIsLoaded) + { EnterCriticalSection(&csDatabase); - if (!myPis->plyInfoIsLoaded) { + if (!myPis->plyInfoIsLoaded) + { // reserve memory for this layer & create array for ply info with default value myPis->plyInfo = new PlyInfoVarType[myPis->knotsInLayer]; - for (curKnot = 0; curKnot < myPis->knotsInLayer; curKnot++) { + for (curKnot = 0; curKnot < myPis->knotsInLayer; curKnot++) + { myPis->plyInfo[curKnot] = defValue; } bytesAllocated = myPis->sizeInBytes; @@ -668,7 +752,8 @@ void MiniMax::savePlyInfoInDatabase(unsigned int layerNumber, unsigned int state // measure io-operations per second LARGE_INTEGER curTimeBefore; - if (MEASURE_IOPS && MEASURE_ONLY_IO) { + if (MEASURE_IOPS && MEASURE_ONLY_IO) + { QueryPerformanceCounter(&curTimeBefore); } diff --git a/src/perfect/miniMax_retroAnalysis.cpp b/src/perfect/miniMax_retroAnalysis.cpp index 230c17c7..543d1522 100644 --- a/src/perfect/miniMax_retroAnalysis.cpp +++ b/src/perfect/miniMax_retroAnalysis.cpp @@ -10,7 +10,7 @@ s\*********************************************************************/ //----------------------------------------------------------------------------- // Name: calcKnotValuesByRetroAnalysis() -// Desc: +// Desc: // The COUNT-ARRAY is the main element of the algorithmn. It contains the number of succeding states for the drawn gamestates, // whose short knot value has to be determined. If all succeding states (branches representing possible moves) are for example won than, // a state can be marked as lost, since no branch will lead to a drawn or won situation any more. @@ -20,17 +20,18 @@ s\*********************************************************************/ bool MiniMax::calcKnotValuesByRetroAnalysis(vector &layersToCalculate) { // locals - bool abortCalculation = false; - unsigned int curLayer = 0; // Counter variable - unsigned int curSubLayer = 0; // Counter variable - unsigned int plyCounter = 0; // Counter variable - unsigned int threadNo; - stringstream ssLayers; - retroAnalysisGlobalVars retroVars; + bool abortCalculation = false; + unsigned int curLayer = 0; // Counter variable + unsigned int curSubLayer = 0; // Counter variable + unsigned int plyCounter = 0; // Counter variable + unsigned int threadNo; + stringstream ssLayers; + retroAnalysisGlobalVars retroVars; // init retro vars retroVars.thread.resize(threadManager.getNumThreads()); - for (threadNo = 0; threadNo < threadManager.getNumThreads(); threadNo++) { + for (threadNo = 0; threadNo < threadManager.getNumThreads(); threadNo++) + { retroVars.thread[threadNo].statesToProcess.resize(PLYINFO_EXP_VALUE, nullptr); retroVars.thread[threadNo].numStatesToProcess = 0; retroVars.thread[threadNo].threadNo = threadNo; @@ -39,65 +40,83 @@ bool MiniMax::calcKnotValuesByRetroAnalysis(vector &layersToCalcul retroVars.layerInitialized.resize(skvfHeader.numLayers, false); retroVars.layersToCalculate = layersToCalculate; retroVars.pMiniMax = this; - for (retroVars.totalNumKnots = 0, retroVars.numKnotsToCalc = 0, curLayer = 0; curLayer < layersToCalculate.size(); curLayer++) { + for (retroVars.totalNumKnots = 0, retroVars.numKnotsToCalc = 0, curLayer = 0; curLayer < layersToCalculate.size(); curLayer++) + { retroVars.numKnotsToCalc += layerStats[layersToCalculate[curLayer]].knotsInLayer; retroVars.totalNumKnots += layerStats[layersToCalculate[curLayer]].knotsInLayer; retroVars.layerInitialized[layersToCalculate[curLayer]] = true; - for (curSubLayer = 0; curSubLayer < layerStats[layersToCalculate[curLayer]].numSuccLayers; curSubLayer++) { - if (retroVars.layerInitialized[layerStats[layersToCalculate[curLayer]].succLayers[curSubLayer]]) continue; - else retroVars.layerInitialized[layerStats[layersToCalculate[curLayer]].succLayers[curSubLayer]] = true; + for (curSubLayer = 0; curSubLayer < layerStats[layersToCalculate[curLayer]].numSuccLayers; curSubLayer++) + { + if (retroVars.layerInitialized[layerStats[layersToCalculate[curLayer]].succLayers[curSubLayer]]) + continue; + else + retroVars.layerInitialized[layerStats[layersToCalculate[curLayer]].succLayers[curSubLayer]] = true; retroVars.totalNumKnots += layerStats[layerStats[layersToCalculate[curLayer]].succLayers[curSubLayer]].knotsInLayer; } } retroVars.layerInitialized.assign(skvfHeader.numLayers, false); // output & filenames - for (curLayer = 0; curLayer < layersToCalculate.size(); curLayer++) ssLayers << " " << layersToCalculate[curLayer]; + for (curLayer = 0; curLayer < layersToCalculate.size(); curLayer++) + ssLayers << " " << layersToCalculate[curLayer]; PRINT(0, this, "*** Calculate layers" << ssLayers.str() << " by retro analysis ***"); // initialization PRINT(2, this, " Bytes in memory: " << memoryUsed2 << endl); - if (!initRetroAnalysis(retroVars)) { - abortCalculation = true; goto freeMem; + if (!initRetroAnalysis(retroVars)) + { + abortCalculation = true; + goto freeMem; } // prepare count arrays PRINT(2, this, " Bytes in memory: " << memoryUsed2 << endl); - if (!prepareCountArrays(retroVars)) { - abortCalculation = true; goto freeMem; + if (!prepareCountArrays(retroVars)) + { + abortCalculation = true; + goto freeMem; } // stop here if only preparing layer - if (onlyPrepareLayer) goto freeMem; + if (onlyPrepareLayer) + goto freeMem; // iteration PRINT(2, this, " Bytes in memory: " << memoryUsed2 << endl); - if (!performRetroAnalysis(retroVars)) { - abortCalculation = true; goto freeMem; + if (!performRetroAnalysis(retroVars)) + { + abortCalculation = true; + goto freeMem; } // show output PRINT(2, this, " Bytes in memory: " << memoryUsed2); - for (curLayer = 0; curLayer < layersToCalculate.size(); curLayer++) { + for (curLayer = 0; curLayer < layersToCalculate.size(); curLayer++) + { showLayerStats(layersToCalculate[curLayer]); } PRINT(2, this, ""); // free memory freeMem: - for (threadNo = 0; threadNo < threadManager.getNumThreads(); threadNo++) { - for (plyCounter = 0; plyCounter < retroVars.thread[threadNo].statesToProcess.size(); plyCounter++) { + for (threadNo = 0; threadNo < threadManager.getNumThreads(); threadNo++) + { + for (plyCounter = 0; plyCounter < retroVars.thread[threadNo].statesToProcess.size(); plyCounter++) + { SAFE_DELETE(retroVars.thread[threadNo].statesToProcess[plyCounter]); } } - for (curLayer = 0; curLayer < layersToCalculate.size(); curLayer++) { - if (retroVars.countArrays[curLayer] != nullptr) { + for (curLayer = 0; curLayer < layersToCalculate.size(); curLayer++) + { + if (retroVars.countArrays[curLayer] != nullptr) + { memoryUsed2 -= layerStats[layersToCalculate[curLayer]].knotsInLayer * sizeof(CountArrayVarType); arrayInfos.removeArray(layersToCalculate[curLayer], ArrayInfo::arrayType_countArray, layerStats[layersToCalculate[curLayer]].knotsInLayer * sizeof(CountArrayVarType), 0); } SAFE_DELETE_ARRAY(retroVars.countArrays[curLayer]); } - if (!abortCalculation) PRINT(2, this, " Bytes in memory: " << memoryUsed2); + if (!abortCalculation) + PRINT(2, this, " Bytes in memory: " << memoryUsed2); return !abortCalculation; } @@ -108,15 +127,16 @@ freeMem: bool MiniMax::initRetroAnalysis(retroAnalysisGlobalVars &retroVars) { // locals - unsigned int curLayerId; // current processed layer within 'layersToCalculate' - unsigned int layerNumber; // layer number of the current process layer - stringstream ssInitArrayPath; // path of the working directory - stringstream ssInitArrayFilePath; // filename corresponding to a cyclic array file which is used for storage - BufferedFile *initArray; // - bool initAlreadyDone = false; // true if the initialization information is already available in a file + unsigned int curLayerId; // current processed layer within 'layersToCalculate' + unsigned int layerNumber; // layer number of the current process layer + stringstream ssInitArrayPath; // path of the working directory + stringstream ssInitArrayFilePath; // filename corresponding to a cyclic array file which is used for storage + BufferedFile *initArray; // + bool initAlreadyDone = false; // true if the initialization information is already available in a file // process each layer - for (curLayerId = 0; curLayerId < retroVars.layersToCalculate.size(); curLayerId++) { + for (curLayerId = 0; curLayerId < retroVars.layersToCalculate.size(); curLayerId++) + { // set current processed layer number layerNumber = retroVars.layersToCalculate[curLayerId]; @@ -124,20 +144,25 @@ bool MiniMax::initRetroAnalysis(retroAnalysisGlobalVars &retroVars) PRINT(1, this, endl << " *** Initialization of layer " << layerNumber << " (" << (getOutputInformation(layerNumber)) << ") which has " << layerStats[layerNumber].knotsInLayer << " knots ***"); // file names - ssInitArrayPath.str(""); ssInitArrayPath << fileDirectory << (fileDirectory.size() ? "\\" : "") << "initLayer"; - ssInitArrayFilePath.str(""); ssInitArrayFilePath << fileDirectory << (fileDirectory.size() ? "\\" : "") << "initLayer\\initLayer" << layerNumber << ".dat"; + ssInitArrayPath.str(""); + ssInitArrayPath << fileDirectory << (fileDirectory.size() ? "\\" : "") << "initLayer"; + ssInitArrayFilePath.str(""); + ssInitArrayFilePath << fileDirectory << (fileDirectory.size() ? "\\" : "") << "initLayer\\initLayer" << layerNumber << ".dat"; // does initialization file exist ? CreateDirectoryA(ssInitArrayPath.str().c_str(), nullptr); initArray = new BufferedFile(threadManager.getNumThreads(), FILE_BUFFER_SIZE, ssInitArrayFilePath.str().c_str()); - if (initArray->getFileSize() == (LONGLONG)layerStats[layerNumber].knotsInLayer) { + if (initArray->getFileSize() == (LONGLONG)layerStats[layerNumber].knotsInLayer) + { PRINT(2, this, " Loading init states from file: " << ssInitArrayFilePath.str()); initAlreadyDone = true; } // don't add layers twice - if (retroVars.layerInitialized[layerNumber]) continue; - else retroVars.layerInitialized[layerNumber] = true; + if (retroVars.layerInitialized[layerNumber]) + continue; + else + retroVars.layerInitialized[layerNumber] = true; // prepare parameters numStatesProcessed = 0; @@ -148,7 +173,8 @@ bool MiniMax::initRetroAnalysis(retroAnalysisGlobalVars &retroVars) ThreadManager::ThreadVarsArray tva(threadManager.getNumThreads(), InitRetroAnalysisVars(this, &retroVars, layerNumber, initArray, initAlreadyDone)); // process each state in the current layer - switch (threadManager.executeParallelLoop(initRetroAnalysisThreadProc, tva.getPointerToArray(), tva.getSizeOfArray(), TM_SCHEDULE_STATIC, 0, layerStats[layerNumber].knotsInLayer - 1, 1)) { + switch (threadManager.executeParallelLoop(initRetroAnalysisThreadProc, tva.getPointerToArray(), tva.getSizeOfArray(), TM_SCHEDULE_STATIC, 0, layerStats[layerNumber].knotsInLayer - 1, 1)) + { case TM_RETURN_VALUE_OK: break; case TM_RETURN_VALUE_EXECUTION_CANCELLED: @@ -166,7 +192,8 @@ bool MiniMax::initRetroAnalysis(retroAnalysisGlobalVars &retroVars) initAlreadyDone = false; initArray->flushBuffers(); SAFE_DELETE(initArray); - if (numStatesProcessed < layerStats[layerNumber].knotsInLayer) return falseOrStop(); + if (numStatesProcessed < layerStats[layerNumber].knotsInLayer) + return falseOrStop(); // when init file was created new then save it now PRINT(2, this, " Saved initialized states to file: " << ssInitArrayFilePath.str()); @@ -182,54 +209,64 @@ bool MiniMax::initRetroAnalysis(retroAnalysisGlobalVars &retroVars) //----------------------------------------------------------------------------- // Name: initRetroAnalysisParallelSub() -// Desc: +// Desc: //----------------------------------------------------------------------------- DWORD MiniMax::initRetroAnalysisThreadProc(void *pParameter, int index) { // locals InitRetroAnalysisVars *iraVars = (InitRetroAnalysisVars *)pParameter; MiniMax *m = iraVars->pMiniMax; - float floatValue; // dummy variable for calls of getValueOfSituation() - StateAdress curState; // current state counter for loops - TwoBit curStateValue; // for calls of getValueOfSituation() + float floatValue; // dummy variable for calls of getValueOfSituation() + StateAdress curState; // current state counter for loops + TwoBit curStateValue; // for calls of getValueOfSituation() curState.layerNumber = iraVars->layerNumber; curState.stateNumber = index; iraVars->statesProcessed++; // print status - if (iraVars->statesProcessed % OUTPUT_EVERY_N_STATES == 0) { + if (iraVars->statesProcessed % OUTPUT_EVERY_N_STATES == 0) + { m->numStatesProcessed += OUTPUT_EVERY_N_STATES; PRINT(2, m, "Already initialized " << m->numStatesProcessed << " of " << m->layerStats[curState.layerNumber].knotsInLayer << " states"); } // layer initialization already done ? if so, then read from file - if (iraVars->initAlreadyDone) { - if (!iraVars->bufferedFile->readBytes(iraVars->curThreadNo, index * sizeof(TwoBit), sizeof(TwoBit), (unsigned char *)&curStateValue)) { + if (iraVars->initAlreadyDone) + { + if (!iraVars->bufferedFile->readBytes(iraVars->curThreadNo, index * sizeof(TwoBit), sizeof(TwoBit), (unsigned char *)&curStateValue)) + { PRINT(0, m, "ERROR: initArray->takeBytes() failed"); return m->falseOrStop(); } // initialization not done - } else { + } + else + { // set current selected situation - if (!m->setSituation(iraVars->curThreadNo, curState.layerNumber, curState.stateNumber)) { + if (!m->setSituation(iraVars->curThreadNo, curState.layerNumber, curState.stateNumber)) + { curStateValue = SKV_VALUE_INVALID; - } else { + } + else + { // get value of current situation m->getValueOfSituation(iraVars->curThreadNo, floatValue, curStateValue); } } // save init value - if (curStateValue != SKV_VALUE_INVALID) { + if (curStateValue != SKV_VALUE_INVALID) + { // save short knot value m->saveKnotValueInDatabase(curState.layerNumber, curState.stateNumber, curStateValue); // put in list if state is final - if (curStateValue == SKV_VALUE_GAME_WON || curStateValue == SKV_VALUE_GAME_LOST) { + if (curStateValue == SKV_VALUE_GAME_WON || curStateValue == SKV_VALUE_GAME_LOST) + { // ply info m->savePlyInfoInDatabase(curState.layerNumber, curState.stateNumber, 0); @@ -240,9 +277,11 @@ DWORD MiniMax::initRetroAnalysisThreadProc(void *pParameter, int index) } // write data to file - if (!iraVars->initAlreadyDone) { + if (!iraVars->initAlreadyDone) + { // curStateValue sollte 2 sein bei index == 1329322 - if (!iraVars->bufferedFile->writeBytes(iraVars->curThreadNo, index * sizeof(TwoBit), sizeof(TwoBit), (unsigned char *)&curStateValue)) { + if (!iraVars->bufferedFile->writeBytes(iraVars->curThreadNo, index * sizeof(TwoBit), sizeof(TwoBit), (unsigned char *)&curStateValue)) + { PRINT(0, m, "ERROR: bufferedFile->writeBytes failed!"); return m->falseOrStop(); } @@ -254,25 +293,26 @@ DWORD MiniMax::initRetroAnalysisThreadProc(void *pParameter, int index) //----------------------------------------------------------------------------- // Name: prepareCountArrays() -// Desc: +// Desc: //----------------------------------------------------------------------------- bool MiniMax::prepareCountArrays(retroAnalysisGlobalVars &retroVars) { // locals - unsigned int numKnotsInCurLayer; - StateAdress curState; // current state counter for loops - unsigned int curLayer = 0; // Counter variable - CountArrayVarType defValue = 0; // default counter array value - DWORD dwWritten; - DWORD dwRead; - LARGE_INTEGER fileSize; - HANDLE hFileCountArray = nullptr; // file handle for loading and saving the arrays in 'countArrays' - stringstream ssCountArrayPath; - stringstream ssCountArrayFilePath; - stringstream ssLayers; + unsigned int numKnotsInCurLayer; + StateAdress curState; // current state counter for loops + unsigned int curLayer = 0; // Counter variable + CountArrayVarType defValue = 0; // default counter array value + DWORD dwWritten; + DWORD dwRead; + LARGE_INTEGER fileSize; + HANDLE hFileCountArray = nullptr; // file handle for loading and saving the arrays in 'countArrays' + stringstream ssCountArrayPath; + stringstream ssCountArrayFilePath; + stringstream ssLayers; // output & filenames - for (curLayer = 0; curLayer < retroVars.layersToCalculate.size(); curLayer++) ssLayers << " " << retroVars.layersToCalculate[curLayer]; + for (curLayer = 0; curLayer < retroVars.layersToCalculate.size(); curLayer++) + ssLayers << " " << retroVars.layersToCalculate[curLayer]; ssCountArrayPath << fileDirectory << (fileDirectory.size() ? "\\" : "") << "countArray"; ssCountArrayFilePath << fileDirectory << (fileDirectory.size() ? "\\" : "") << "countArray\\countArray" << ssLayers.str() << ".dat"; PRINT(2, this, " *** Prepare count arrays for layers " << ssLayers.str() << " ***" << endl); @@ -280,13 +320,15 @@ bool MiniMax::prepareCountArrays(retroAnalysisGlobalVars &retroVars) // prepare count arrays CreateDirectoryA(ssCountArrayPath.str().c_str(), nullptr); - if ((hFileCountArray = CreateFileA(ssCountArrayFilePath.str().c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr)) == INVALID_HANDLE_VALUE) { + if ((hFileCountArray = CreateFileA(ssCountArrayFilePath.str().c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr)) == INVALID_HANDLE_VALUE) + { PRINT(0, this, "ERROR: Could not open File " << ssCountArrayFilePath.str() << "!"); return falseOrStop(); } // allocate memory for count arrays - for (curLayer = 0; curLayer < retroVars.layersToCalculate.size(); curLayer++) { + for (curLayer = 0; curLayer < retroVars.layersToCalculate.size(); curLayer++) + { numKnotsInCurLayer = layerStats[retroVars.layersToCalculate[curLayer]].knotsInLayer; retroVars.countArrays[curLayer] = new CountArrayVarType[numKnotsInCurLayer]; memoryUsed2 += numKnotsInCurLayer * sizeof(CountArrayVarType); @@ -294,37 +336,49 @@ bool MiniMax::prepareCountArrays(retroAnalysisGlobalVars &retroVars) } // load file if already existend - if (GetFileSizeEx(hFileCountArray, &fileSize) && fileSize.QuadPart == retroVars.numKnotsToCalc) { + if (GetFileSizeEx(hFileCountArray, &fileSize) && fileSize.QuadPart == retroVars.numKnotsToCalc) + { PRINT(2, this, " Load number of succedors from file: " << ssCountArrayFilePath.str().c_str()); - for (curLayer = 0; curLayer < retroVars.layersToCalculate.size(); curLayer++) { + for (curLayer = 0; curLayer < retroVars.layersToCalculate.size(); curLayer++) + { numKnotsInCurLayer = layerStats[retroVars.layersToCalculate[curLayer]].knotsInLayer; - if (!ReadFile(hFileCountArray, retroVars.countArrays[curLayer], numKnotsInCurLayer * sizeof(CountArrayVarType), &dwRead, nullptr)) return falseOrStop(); - if (dwRead != numKnotsInCurLayer * sizeof(CountArrayVarType)) return falseOrStop(); + if (!ReadFile(hFileCountArray, retroVars.countArrays[curLayer], numKnotsInCurLayer * sizeof(CountArrayVarType), &dwRead, nullptr)) + return falseOrStop(); + if (dwRead != numKnotsInCurLayer * sizeof(CountArrayVarType)) + return falseOrStop(); } // else calculate number of succedding states - } else { + } + else + { // Set default value 0 - for (curLayer = 0; curLayer < retroVars.layersToCalculate.size(); curLayer++) { + for (curLayer = 0; curLayer < retroVars.layersToCalculate.size(); curLayer++) + { numKnotsInCurLayer = layerStats[retroVars.layersToCalculate[curLayer]].knotsInLayer; - for (curState.stateNumber = 0; curState.stateNumber < numKnotsInCurLayer; curState.stateNumber++) { + for (curState.stateNumber = 0; curState.stateNumber < numKnotsInCurLayer; curState.stateNumber++) + { retroVars.countArrays[curLayer][curState.stateNumber] = defValue; } } // calc values - if (!calcNumSuccedors(retroVars)) { + if (!calcNumSuccedors(retroVars)) + { CloseHandle(hFileCountArray); return false; } // save to file - for (curLayer = 0, dwWritten = 0; curLayer < retroVars.layersToCalculate.size(); curLayer++) { + for (curLayer = 0, dwWritten = 0; curLayer < retroVars.layersToCalculate.size(); curLayer++) + { numKnotsInCurLayer = layerStats[retroVars.layersToCalculate[curLayer]].knotsInLayer; - if (!WriteFile(hFileCountArray, retroVars.countArrays[curLayer], numKnotsInCurLayer * sizeof(CountArrayVarType), &dwWritten, nullptr)) return falseOrStop(); - if (dwWritten != numKnotsInCurLayer * sizeof(CountArrayVarType)) return falseOrStop(); + if (!WriteFile(hFileCountArray, retroVars.countArrays[curLayer], numKnotsInCurLayer * sizeof(CountArrayVarType), &dwWritten, nullptr)) + return falseOrStop(); + if (dwWritten != numKnotsInCurLayer * sizeof(CountArrayVarType)) + return falseOrStop(); } PRINT(2, this, " Count array saved to file: " << ssCountArrayFilePath.str()); } @@ -336,26 +390,28 @@ bool MiniMax::prepareCountArrays(retroAnalysisGlobalVars &retroVars) //----------------------------------------------------------------------------- // Name: calcNumSuccedors() -// Desc: +// Desc: //----------------------------------------------------------------------------- bool MiniMax::calcNumSuccedors(retroAnalysisGlobalVars &retroVars) { // locals - unsigned int curLayerId; // current processed layer within 'layersToCalculate' - unsigned int layerNumber; // layer number of the current process layer - StateAdress curState; // current state counter for loops - StateAdress succState; // current succeding state counter for loops - vector succCalculated(skvfHeader.numLayers, false); // + unsigned int curLayerId; // current processed layer within 'layersToCalculate' + unsigned int layerNumber; // layer number of the current process layer + StateAdress curState; // current state counter for loops + StateAdress succState; // current succeding state counter for loops + vector succCalculated(skvfHeader.numLayers, false); // // process each layer - for (curLayerId = 0; curLayerId < retroVars.layersToCalculate.size(); curLayerId++) { + for (curLayerId = 0; curLayerId < retroVars.layersToCalculate.size(); curLayerId++) + { // set current processed layer number layerNumber = retroVars.layersToCalculate[curLayerId]; PRINT(0, this, " *** Calculate number of succeding states for each state of layer " << layerNumber << " ***"); - // process layer ... - if (!succCalculated[layerNumber]) { + // process layer ... + if (!succCalculated[layerNumber]) + { // prepare parameters for multithreading succCalculated[layerNumber] = true; @@ -363,7 +419,8 @@ bool MiniMax::calcNumSuccedors(retroAnalysisGlobalVars &retroVars) ThreadManager::ThreadVarsArray tva(threadManager.getNumThreads(), AddNumSuccedorsVars(this, &retroVars, layerNumber)); // process each state in the current layer - switch (threadManager.executeParallelLoop(addNumSuccedorsThreadProc, tva.getPointerToArray(), tva.getSizeOfArray(), TM_SCHEDULE_STATIC, 0, layerStats[layerNumber].knotsInLayer - 1, 1)) { + switch (threadManager.executeParallelLoop(addNumSuccedorsThreadProc, tva.getPointerToArray(), tva.getSizeOfArray(), TM_SCHEDULE_STATIC, 0, layerStats[layerNumber].knotsInLayer - 1, 1)) + { case TM_RETURN_VALUE_OK: break; case TM_RETURN_VALUE_EXECUTION_CANCELLED: @@ -377,25 +434,32 @@ bool MiniMax::calcNumSuccedors(retroAnalysisGlobalVars &retroVars) // reduce and delete thread specific data tva.reduce(); - if (numStatesProcessed < layerStats[layerNumber].knotsInLayer) return falseOrStop(); + if (numStatesProcessed < layerStats[layerNumber].knotsInLayer) + return falseOrStop(); // don't calc layers twice - } else { + } + else + { return falseOrStop(); } // ... and process succeding layers - for (curState.layerNumber = 0; curState.layerNumber < layerStats[layerNumber].numSuccLayers; curState.layerNumber++) { + for (curState.layerNumber = 0; curState.layerNumber < layerStats[layerNumber].numSuccLayers; curState.layerNumber++) + { // get current pred. layer succState.layerNumber = layerStats[layerNumber].succLayers[curState.layerNumber]; // don't add layers twice - if (succCalculated[succState.layerNumber]) continue; - else succCalculated[succState.layerNumber] = true; + if (succCalculated[succState.layerNumber]) + continue; + else + succCalculated[succState.layerNumber] = true; // don't process layers without states - if (!layerStats[succState.layerNumber].knotsInLayer) continue; + if (!layerStats[succState.layerNumber].knotsInLayer) + continue; // check all states of pred. layer PRINT(2, this, " - Do the same for the succeding layer " << (int)succState.layerNumber); @@ -405,7 +469,8 @@ bool MiniMax::calcNumSuccedors(retroAnalysisGlobalVars &retroVars) ThreadManager::ThreadVarsArray tva(threadManager.getNumThreads(), AddNumSuccedorsVars(this, &retroVars, succState.layerNumber)); // process each state in the current layer - switch (threadManager.executeParallelLoop(addNumSuccedorsThreadProc, tva.getPointerToArray(), tva.getSizeOfArray(), TM_SCHEDULE_STATIC, 0, layerStats[succState.layerNumber].knotsInLayer - 1, 1)) { + switch (threadManager.executeParallelLoop(addNumSuccedorsThreadProc, tva.getPointerToArray(), tva.getSizeOfArray(), TM_SCHEDULE_STATIC, 0, layerStats[succState.layerNumber].knotsInLayer - 1, 1)) + { case TM_RETURN_VALUE_OK: break; case TM_RETURN_VALUE_EXECUTION_CANCELLED: @@ -419,7 +484,8 @@ bool MiniMax::calcNumSuccedors(retroAnalysisGlobalVars &retroVars) // reduce and delete thread specific data tva.reduce(); - if (numStatesProcessed < layerStats[succState.layerNumber].knotsInLayer) return falseOrStop(); + if (numStatesProcessed < layerStats[succState.layerNumber].knotsInLayer) + return falseOrStop(); } } @@ -429,40 +495,43 @@ bool MiniMax::calcNumSuccedors(retroAnalysisGlobalVars &retroVars) //----------------------------------------------------------------------------- // Name: addNumSuccedorsThreadProc() -// Desc: +// Desc: //----------------------------------------------------------------------------- DWORD MiniMax::addNumSuccedorsThreadProc(void *pParameter, int index) { // locals AddNumSuccedorsVars *ansVars = (AddNumSuccedorsVars *)pParameter; MiniMax *m = ansVars->pMiniMax; - unsigned int numLayersToCalculate = (unsigned int)ansVars->retroVars->layersToCalculate.size(); - unsigned int curLayerId; // current processed layer within 'layersToCalculate' - unsigned int amountOfPred; - unsigned int curPred; - CountArrayVarType countValue; - StateAdress predState; - StateAdress curState; - TwoBit curStateValue; - PlyInfoVarType numPlies; // number of plies of the current considered succeding state - bool cuStateAddedToProcessQueue = false; + unsigned int numLayersToCalculate = (unsigned int)ansVars->retroVars->layersToCalculate.size(); + unsigned int curLayerId; // current processed layer within 'layersToCalculate' + unsigned int amountOfPred; + unsigned int curPred; + CountArrayVarType countValue; + StateAdress predState; + StateAdress curState; + TwoBit curStateValue; + PlyInfoVarType numPlies; // number of plies of the current considered succeding state + bool cuStateAddedToProcessQueue = false; curState.layerNumber = ansVars->layerNumber; curState.stateNumber = (StateNumberVarType)index; // print status ansVars->statesProcessed++; - if (ansVars->statesProcessed % OUTPUT_EVERY_N_STATES == 0) { + if (ansVars->statesProcessed % OUTPUT_EVERY_N_STATES == 0) + { m->numStatesProcessed += OUTPUT_EVERY_N_STATES; PRINT(2, m, " Already processed " << m->numStatesProcessed << " of " << m->layerStats[curState.layerNumber].knotsInLayer << " states"); } // invalid state ? m->readKnotValueFromDatabase(curState.layerNumber, curState.stateNumber, curStateValue); - if (curStateValue == SKV_VALUE_INVALID) return TM_RETURN_VALUE_OK; + if (curStateValue == SKV_VALUE_INVALID) + return TM_RETURN_VALUE_OK; // set current selected situation - if (!m->setSituation(ansVars->curThreadNo, curState.layerNumber, curState.stateNumber)) { + if (!m->setSituation(ansVars->curThreadNo, curState.layerNumber, curState.stateNumber)) + { PRINT(0, m, "ERROR: setSituation() returned false!"); return TM_RETURN_VALUE_TERMINATE_ALL_THREADS; } @@ -471,20 +540,25 @@ DWORD MiniMax::addNumSuccedorsThreadProc(void *pParameter, int index) m->getPredecessors(ansVars->curThreadNo, &amountOfPred, ansVars->predVars); // iteration - for (curPred = 0; curPred < amountOfPred; curPred++) { + for (curPred = 0; curPred < amountOfPred; curPred++) + { // current predecessor predState.layerNumber = ansVars->predVars[curPred].predLayerNumbers; predState.stateNumber = ansVars->predVars[curPred].predStateNumbers; // don't calculate states from layers above yet - for (curLayerId = 0; curLayerId < numLayersToCalculate; curLayerId++) { - if (ansVars->retroVars->layersToCalculate[curLayerId] == predState.layerNumber) break; + for (curLayerId = 0; curLayerId < numLayersToCalculate; curLayerId++) + { + if (ansVars->retroVars->layersToCalculate[curLayerId] == predState.layerNumber) + break; } - if (curLayerId == numLayersToCalculate) continue; + if (curLayerId == numLayersToCalculate) + continue; // put in list (with states to be processed) if state is final - if (!cuStateAddedToProcessQueue && (curStateValue == SKV_VALUE_GAME_WON || curStateValue == SKV_VALUE_GAME_LOST)) { + if (!cuStateAddedToProcessQueue && (curStateValue == SKV_VALUE_GAME_WON || curStateValue == SKV_VALUE_GAME_LOST)) + { m->readPlyInfoFromDatabase(curState.layerNumber, curState.stateNumber, numPlies); m->addStateToProcessQueue(*ansVars->retroVars, ansVars->retroVars->thread[ansVars->curThreadNo], numPlies, &curState); cuStateAddedToProcessQueue = true; @@ -492,17 +566,21 @@ DWORD MiniMax::addNumSuccedorsThreadProc(void *pParameter, int index) // add this state as possible move long *pCountValue = ((long *)ansVars->retroVars->countArrays[curLayerId]) + predState.stateNumber / (sizeof(long) / sizeof(CountArrayVarType)); - long numBitsToShift = sizeof(CountArrayVarType) * 8 * (predState.stateNumber % (sizeof(long) / sizeof(CountArrayVarType))); // little-endian byte-order - long mask = 0x000000ff << numBitsToShift; - long curCountLong, newCountLong; + long numBitsToShift = sizeof(CountArrayVarType) * 8 * (predState.stateNumber % (sizeof(long) / sizeof(CountArrayVarType))); // little-endian byte-order + long mask = 0x000000ff << numBitsToShift; + long curCountLong, newCountLong; - do { + do + { curCountLong = *pCountValue; countValue = (CountArrayVarType)((curCountLong & mask) >> numBitsToShift); - if (countValue == 255) { + if (countValue == 255) + { PRINT(0, m, "ERROR: maximum value for Count[] reached!"); return TM_RETURN_VALUE_TERMINATE_ALL_THREADS; - } else { + } + else + { countValue++; newCountLong = (curCountLong & (~mask)) + (countValue << numBitsToShift); } @@ -515,21 +593,22 @@ DWORD MiniMax::addNumSuccedorsThreadProc(void *pParameter, int index) //----------------------------------------------------------------------------- // Name: performRetroAnalysis() -// Desc: +// Desc: //----------------------------------------------------------------------------- bool MiniMax::performRetroAnalysis(retroAnalysisGlobalVars &retroVars) { // locals - StateAdress curState; // current state counter for loops - TwoBit curStateValue; // current state value - unsigned int curLayerId; // current processed layer within 'layersToCalculate' + StateAdress curState; // current state counter for loops + TwoBit curStateValue; // current state value + unsigned int curLayerId; // current processed layer within 'layersToCalculate' PRINT(2, this, " *** Begin Iteration ***"); numStatesProcessed = 0; curCalculationActionId = MM_ACTION_PERFORM_RETRO_ANAL; // process each state in the current layer - switch (threadManager.executeInParallel(performRetroAnalysisThreadProc, (void **)&retroVars, 0)) { + switch (threadManager.executeInParallel(performRetroAnalysisThreadProc, (void **)&retroVars, 0)) + { case TM_RETURN_VALUE_OK: break; case TM_RETURN_VALUE_EXECUTION_CANCELLED: @@ -542,8 +621,10 @@ bool MiniMax::performRetroAnalysis(retroAnalysisGlobalVars &retroVars) } // if there are still states to process, than something went wrong - for (unsigned int curThreadNo = 0; curThreadNo < threadManager.getNumThreads(); curThreadNo++) { - if (retroVars.thread[curThreadNo].numStatesToProcess) { + for (unsigned int curThreadNo = 0; curThreadNo < threadManager.getNumThreads(); curThreadNo++) + { + if (retroVars.thread[curThreadNo].numStatesToProcess) + { PRINT(0, this, "ERROR: There are still states to process after performing retro analysis!"); return falseOrStop(); } @@ -551,11 +632,15 @@ bool MiniMax::performRetroAnalysis(retroAnalysisGlobalVars &retroVars) // copy drawn and invalid states to ply info PRINT(2, this, " Copy drawn and invalid states to ply info database..."); - for (curLayerId = 0; curLayerId < retroVars.layersToCalculate.size(); curLayerId++) { - for (curState.layerNumber = retroVars.layersToCalculate[curLayerId], curState.stateNumber = 0; curState.stateNumber < layerStats[curState.layerNumber].knotsInLayer; curState.stateNumber++) { + for (curLayerId = 0; curLayerId < retroVars.layersToCalculate.size(); curLayerId++) + { + for (curState.layerNumber = retroVars.layersToCalculate[curLayerId], curState.stateNumber = 0; curState.stateNumber < layerStats[curState.layerNumber].knotsInLayer; curState.stateNumber++) + { readKnotValueFromDatabase(curState.layerNumber, curState.stateNumber, curStateValue); - if (curStateValue == SKV_VALUE_GAME_DRAWN) savePlyInfoInDatabase(curState.layerNumber, curState.stateNumber, PLYINFO_VALUE_DRAWN); - if (curStateValue == SKV_VALUE_INVALID) savePlyInfoInDatabase(curState.layerNumber, curState.stateNumber, PLYINFO_VALUE_INVALID); + if (curStateValue == SKV_VALUE_GAME_DRAWN) + savePlyInfoInDatabase(curState.layerNumber, curState.stateNumber, PLYINFO_VALUE_DRAWN); + if (curStateValue == SKV_VALUE_INVALID) + savePlyInfoInDatabase(curState.layerNumber, curState.stateNumber, PLYINFO_VALUE_INVALID); } } PRINT(1, this, " *** Iteration finished! ***"); @@ -566,48 +651,54 @@ bool MiniMax::performRetroAnalysis(retroAnalysisGlobalVars &retroVars) //----------------------------------------------------------------------------- // Name: performRetroAnalysisThreadProc() -// Desc: +// Desc: //----------------------------------------------------------------------------- DWORD MiniMax::performRetroAnalysisThreadProc(void *pParameter) { // locals retroAnalysisGlobalVars *retroVars = (retroAnalysisGlobalVars *)pParameter; MiniMax *m = retroVars->pMiniMax; - unsigned int threadNo = m->threadManager.getThreadNumber(); + unsigned int threadNo = m->threadManager.getThreadNumber(); RetroAnalysisThreadVars *threadVars = &retroVars->thread[threadNo]; - TwoBit predStateValue; - unsigned int curLayerId; // current processed layer within 'layersToCalculate' - unsigned int amountOfPred; // total numbers of predecessors and current considered one - unsigned int curPred; - unsigned int threadCounter; - long long numStatesProcessed; - long long totalNumStatesToProcess; - PlyInfoVarType curNumPlies; - PlyInfoVarType numPliesTillCurState; - PlyInfoVarType numPliesTillPredState; - CountArrayVarType countValue; - StateAdress predState; - StateAdress curState; // current state counter for while-loop - TwoBit curStateValue; // current state value - RetroAnalysisPredVars predVars[MAX_NUM_PREDECESSORS]; + TwoBit predStateValue; + unsigned int curLayerId; // current processed layer within 'layersToCalculate' + unsigned int amountOfPred; // total numbers of predecessors and current considered one + unsigned int curPred; + unsigned int threadCounter; + long long numStatesProcessed; + long long totalNumStatesToProcess; + PlyInfoVarType curNumPlies; + PlyInfoVarType numPliesTillCurState; + PlyInfoVarType numPliesTillPredState; + CountArrayVarType countValue; + StateAdress predState; + StateAdress curState; // current state counter for while-loop + TwoBit curStateValue; // current state value + RetroAnalysisPredVars predVars[MAX_NUM_PREDECESSORS]; - for (numStatesProcessed = 0, curNumPlies = 0; curNumPlies < threadVars->statesToProcess.size(); curNumPlies++) { + for (numStatesProcessed = 0, curNumPlies = 0; curNumPlies < threadVars->statesToProcess.size(); curNumPlies++) + { // skip empty and uninitialized cyclic arrays - if (threadVars->statesToProcess[curNumPlies] != nullptr) { + if (threadVars->statesToProcess[curNumPlies] != nullptr) + { - if (threadNo == 0) { + if (threadNo == 0) + { PRINT(0, m, " Current number of plies: " << (unsigned int)curNumPlies << "/" << threadVars->statesToProcess.size()); - for (threadCounter = 0; threadCounter < m->threadManager.getNumThreads(); threadCounter++) { + for (threadCounter = 0; threadCounter < m->threadManager.getNumThreads(); threadCounter++) + { PRINT(0, m, " States to process for thread " << threadCounter << ": " << retroVars->thread[threadCounter].numStatesToProcess); } } - while (threadVars->statesToProcess[curNumPlies]->takeBytes(sizeof(StateAdress), (unsigned char *)&curState)) { + while (threadVars->statesToProcess[curNumPlies]->takeBytes(sizeof(StateAdress), (unsigned char *)&curState)) + { // execution cancelled by user? - if (m->threadManager.wasExecutionCancelled()) { + if (m->threadManager.wasExecutionCancelled()) + { PRINT(0, m, "\n****************************************\nSub-thread no. " << threadNo << ": Execution cancelled by user!\n****************************************\n"); return TM_RETURN_VALUE_EXECUTION_CANCELLED; } @@ -616,7 +707,8 @@ DWORD MiniMax::performRetroAnalysisThreadProc(void *pParameter) m->readKnotValueFromDatabase(curState.layerNumber, curState.stateNumber, curStateValue); m->readPlyInfoFromDatabase(curState.layerNumber, curState.stateNumber, numPliesTillCurState); - if (numPliesTillCurState != curNumPlies) { + if (numPliesTillCurState != curNumPlies) + { PRINT(0, m, "ERROR: numPliesTillCurState != curNumPlies"); return TM_RETURN_VALUE_TERMINATE_ALL_THREADS; } @@ -624,16 +716,19 @@ DWORD MiniMax::performRetroAnalysisThreadProc(void *pParameter) // console output numStatesProcessed++; threadVars->numStatesToProcess--; - if (numStatesProcessed % OUTPUT_EVERY_N_STATES == 0) { + if (numStatesProcessed % OUTPUT_EVERY_N_STATES == 0) + { m->numStatesProcessed += OUTPUT_EVERY_N_STATES; - for (totalNumStatesToProcess = 0, threadCounter = 0; threadCounter < m->threadManager.getNumThreads(); threadCounter++) { + for (totalNumStatesToProcess = 0, threadCounter = 0; threadCounter < m->threadManager.getNumThreads(); threadCounter++) + { totalNumStatesToProcess += retroVars->thread[threadCounter].numStatesToProcess; } PRINT(2, m, " states already processed: " << m->numStatesProcessed << " \t states still in list: " << totalNumStatesToProcess); } // set current selected situation - if (!m->setSituation(threadNo, curState.layerNumber, curState.stateNumber)) { + if (!m->setSituation(threadNo, curState.layerNumber, curState.stateNumber)) + { PRINT(0, m, "ERROR: setSituation() returned false!"); return TM_RETURN_VALUE_TERMINATE_ALL_THREADS; } @@ -642,48 +737,61 @@ DWORD MiniMax::performRetroAnalysisThreadProc(void *pParameter) m->getPredecessors(threadNo, &amountOfPred, predVars); // iteration - for (curPred = 0; curPred < amountOfPred; curPred++) { + for (curPred = 0; curPred < amountOfPred; curPred++) + { // current predecessor predState.layerNumber = predVars[curPred].predLayerNumbers; predState.stateNumber = predVars[curPred].predStateNumbers; // don't calculate states from layers above yet - for (curLayerId = 0; curLayerId < retroVars->layersToCalculate.size(); curLayerId++) { - if (retroVars->layersToCalculate[curLayerId] == predState.layerNumber) break; + for (curLayerId = 0; curLayerId < retroVars->layersToCalculate.size(); curLayerId++) + { + if (retroVars->layersToCalculate[curLayerId] == predState.layerNumber) + break; } - if (curLayerId == retroVars->layersToCalculate.size()) continue; + if (curLayerId == retroVars->layersToCalculate.size()) + continue; // get value of predecessor m->readKnotValueFromDatabase(predState.layerNumber, predState.stateNumber, predStateValue); // only drawn states are relevant here, since the other are already calculated - if (predStateValue == SKV_VALUE_GAME_DRAWN) { + if (predStateValue == SKV_VALUE_GAME_DRAWN) + { // if current considered state is a lost game then all predecessors are a won game - if (curStateValue == m->skvPerspectiveMatrix[SKV_VALUE_GAME_LOST][predVars[curPred].playerToMoveChanged ? PL_TO_MOVE_CHANGED : PL_TO_MOVE_UNCHANGED]) { + if (curStateValue == m->skvPerspectiveMatrix[SKV_VALUE_GAME_LOST][predVars[curPred].playerToMoveChanged ? PL_TO_MOVE_CHANGED : PL_TO_MOVE_UNCHANGED]) + { m->saveKnotValueInDatabase(predState.layerNumber, predState.stateNumber, SKV_VALUE_GAME_WON); - m->savePlyInfoInDatabase(predState.layerNumber, predState.stateNumber, numPliesTillCurState + 1); // (requirement: curNumPlies == numPliesTillCurState) - if (numPliesTillCurState + 1 < curNumPlies) { + m->savePlyInfoInDatabase(predState.layerNumber, predState.stateNumber, numPliesTillCurState + 1); // (requirement: curNumPlies == numPliesTillCurState) + if (numPliesTillCurState + 1 < curNumPlies) + { PRINT(0, m, "ERROR: Current number of plies is bigger than numPliesTillCurState + 1!"); return TM_RETURN_VALUE_TERMINATE_ALL_THREADS; } m->addStateToProcessQueue(*retroVars, *threadVars, numPliesTillCurState + 1, &predState); // if current state is a won game, then this state is not an option any more for all predecessors - } else { + } + else + { // reduce count value by one long *pCountValue = ((long *)retroVars->countArrays[curLayerId]) + predState.stateNumber / (sizeof(long) / sizeof(CountArrayVarType)); - long numBitsToShift = sizeof(CountArrayVarType) * 8 * (predState.stateNumber % (sizeof(long) / sizeof(CountArrayVarType))); // little-endian byte-order - long mask = 0x000000ff << numBitsToShift; - long curCountLong, newCountLong; + long numBitsToShift = sizeof(CountArrayVarType) * 8 * (predState.stateNumber % (sizeof(long) / sizeof(CountArrayVarType))); // little-endian byte-order + long mask = 0x000000ff << numBitsToShift; + long curCountLong, newCountLong; - do { + do + { curCountLong = *pCountValue; countValue = (CountArrayVarType)((curCountLong & mask) >> numBitsToShift); - if (countValue > 0) { + if (countValue > 0) + { countValue--; newCountLong = (curCountLong & (~mask)) + (countValue << numBitsToShift); - } else { + } + else + { PRINT(0, m, "ERROR: Count is already zero!"); return TM_RETURN_VALUE_TERMINATE_ALL_THREADS; } @@ -691,14 +799,17 @@ DWORD MiniMax::performRetroAnalysisThreadProc(void *pParameter) // ply info (requirement: curNumPlies == numPliesTillCurState) m->readPlyInfoFromDatabase(predState.layerNumber, predState.stateNumber, numPliesTillPredState); - if (numPliesTillPredState == PLYINFO_VALUE_UNCALCULATED || numPliesTillCurState + 1 > numPliesTillPredState) { + if (numPliesTillPredState == PLYINFO_VALUE_UNCALCULATED || numPliesTillCurState + 1 > numPliesTillPredState) + { m->savePlyInfoInDatabase(predState.layerNumber, predState.stateNumber, numPliesTillCurState + 1); } // when all successor are won states then this is a lost state (this should only be the case for one thread) - if (countValue == 0) { + if (countValue == 0) + { m->saveKnotValueInDatabase(predState.layerNumber, predState.stateNumber, SKV_VALUE_GAME_LOST); - if (numPliesTillCurState + 1 < curNumPlies) { + if (numPliesTillCurState + 1 < curNumPlies) + { PRINT(0, m, "ERROR: Current number of plies is bigger than numPliesTillCurState + 1!"); return TM_RETURN_VALUE_TERMINATE_ALL_THREADS; } @@ -720,20 +831,22 @@ DWORD MiniMax::performRetroAnalysisThreadProc(void *pParameter) //----------------------------------------------------------------------------- // Name: addStateToProcessQueue() -// Desc: +// Desc: //----------------------------------------------------------------------------- bool MiniMax::addStateToProcessQueue(retroAnalysisGlobalVars &retroVars, RetroAnalysisThreadVars &threadVars, unsigned int plyNumber, StateAdress *pState) { // resize vector if too small - if (plyNumber >= threadVars.statesToProcess.size()) { + if (plyNumber >= threadVars.statesToProcess.size()) + { threadVars.statesToProcess.resize(max(plyNumber + 1, 10 * threadVars.statesToProcess.size()), nullptr); PRINT(4, this, " statesToProcess resized to " << threadVars.statesToProcess.size()); } // initialize cyclic array if necessary - if (threadVars.statesToProcess[plyNumber] == nullptr) { - stringstream ssStatesToProcessFilePath; - stringstream ssStatesToProcessPath; + if (threadVars.statesToProcess[plyNumber] == nullptr) + { + stringstream ssStatesToProcessFilePath; + stringstream ssStatesToProcessPath; ssStatesToProcessPath << fileDirectory << (fileDirectory.size() ? "\\" : "") << "statesToProcess"; CreateDirectoryA(ssStatesToProcessPath.str().c_str(), nullptr); ssStatesToProcessFilePath.str(""); @@ -743,7 +856,8 @@ bool MiniMax::addStateToProcessQueue(retroAnalysisGlobalVars &retroVars, RetroAn } // add state - if (!threadVars.statesToProcess[plyNumber]->addBytes(sizeof(StateAdress), (unsigned char *)pState)) { + if (!threadVars.statesToProcess[plyNumber]->addBytes(sizeof(StateAdress), (unsigned char *)pState)) + { PRINT(0, this, "ERROR: Cyclic list to small! numStatesToProcess:" << threadVars.numStatesToProcess); return falseOrStop(); } diff --git a/src/perfect/miniMax_retroAnalysis.h b/src/perfect/miniMax_retroAnalysis.h index d029b1f8..d3bb60bb 100644 --- a/src/perfect/miniMax_retroAnalysis.h +++ b/src/perfect/miniMax_retroAnalysis.h @@ -8,64 +8,64 @@ struct RetroAnalysisQueueState { - StateNumberVarType stateNumber; // state stored in the retro analysis queue. the queue is a buffer containing states to be passed to 'RetroAnalysisThreadVars::statesToProcess' - PlyInfoVarType numPliesTillCurState; // ply number for the stored state + StateNumberVarType stateNumber; // state stored in the retro analysis queue. the queue is a buffer containing states to be passed to 'RetroAnalysisThreadVars::statesToProcess' + PlyInfoVarType numPliesTillCurState; // ply number for the stored state }; -struct RetroAnalysisThreadVars // thread specific variables for each thread in the retro analysis +struct RetroAnalysisThreadVars // thread specific variables for each thread in the retro analysis { - vector statesToProcess; // vector-queue containing the states, whose short knot value are known for sure. they have to be processed. if processed the state will be removed from list. indexing: [threadNo][plyNumber] - vector> stateQueue; // Queue containing states, whose 'count value' shall be increased by one. Before writing 'count value' to 'count array' the writing positions are sorted for faster processing. - long long numStatesToProcess; // Number of states in 'statesToProcess' which have to be processed - unsigned int threadNo; + vector statesToProcess; // vector-queue containing the states, whose short knot value are known for sure. they have to be processed. if processed the state will be removed from list. indexing: [threadNo][plyNumber] + vector> stateQueue; // Queue containing states, whose 'count value' shall be increased by one. Before writing 'count value' to 'count array' the writing positions are sorted for faster processing. + long long numStatesToProcess; // Number of states in 'statesToProcess' which have to be processed + unsigned int threadNo; }; -struct RetroAnalysisVars // constant during calculation +struct RetroAnalysisVars // constant during calculation { - vector countArrays; // One count array for each layer in 'layersToCalculate'. (For the nine men's morris game two layers have to considered at once.) - vector countArraysCompr; // '' but compressed - vector layerInitialized; // - vector layersToCalculate; // layers which shall be calculated - long long totalNumKnots; // total numbers of knots which have to be stored in memory - long long numKnotsToCalc; // number of knots of all layers to be calculated - vector thread; + vector countArrays; // One count array for each layer in 'layersToCalculate'. (For the nine men's morris game two layers have to considered at once.) + vector countArraysCompr; // '' but compressed + vector layerInitialized; // + vector layersToCalculate; // layers which shall be calculated + long long totalNumKnots; // total numbers of knots which have to be stored in memory + long long numKnotsToCalc; // number of knots of all layers to be calculated + vector thread; }; struct InitRetroAnalysisVars { MiniMax *pMiniMax; - unsigned int curThreadNo; - unsigned int layerNumber; - LONGLONG statesProcessed; - unsigned int statsValueCounter[SKV_NUM_VALUES]; + unsigned int curThreadNo; + unsigned int layerNumber; + LONGLONG statesProcessed; + unsigned int statsValueCounter[SKV_NUM_VALUES]; BufferedFile *bufferedFile; RetroAnalysisVars *retroVars; - bool initAlreadyDone; // true if the initialization information is already available in a file + bool initAlreadyDone; // true if the initialization information is already available in a file }; struct addSuccLayersVars { MiniMax *pMiniMax; - unsigned int curThreadNo; - unsigned int statsValueCounter[SKV_NUM_VALUES]; - unsigned int layerNumber; + unsigned int curThreadNo; + unsigned int statsValueCounter[SKV_NUM_VALUES]; + unsigned int layerNumber; RetroAnalysisVars *retroVars; }; struct RetroAnalysisPredVars { - unsigned int predStateNumbers; - unsigned int predLayerNumbers; - unsigned int predSymOperation; - bool playerToMoveChanged; + unsigned int predStateNumbers; + unsigned int predLayerNumbers; + unsigned int predSymOperation; + bool playerToMoveChanged; }; struct AddNumSuccedorsVars { MiniMax *pMiniMax; - unsigned int curThreadNo; - unsigned int layerNumber; - LONGLONG statesProcessed; + unsigned int curThreadNo; + unsigned int layerNumber; + LONGLONG statesProcessed; RetroAnalysisVars *retroVars; RetroAnalysisPredVars *predVars; }; \ No newline at end of file diff --git a/src/perfect/miniMax_test.cpp b/src/perfect/miniMax_test.cpp index 9a35f5d1..82bf9466 100644 --- a/src/perfect/miniMax_test.cpp +++ b/src/perfect/miniMax_test.cpp @@ -10,16 +10,17 @@ //----------------------------------------------------------------------------- // Name: testLayer() -// Desc: +// Desc: //----------------------------------------------------------------------------- bool MiniMax::testLayer(unsigned int layerNumber) { // Locals - unsigned int curThreadNo; - unsigned int returnValue; + unsigned int curThreadNo; + unsigned int returnValue; // database open? - if (hFileShortKnotValues == nullptr || hFilePlyInfo == nullptr) { + if (hFileShortKnotValues == nullptr || hFilePlyInfo == nullptr) + { PRINT(0, this, "ERROR: Database file not open!"); return falseOrStop(); } @@ -35,7 +36,8 @@ bool MiniMax::testLayer(unsigned int layerNumber) curCalculatedLayer = layerNumber; curCalculationActionId = MM_ACTION_TESTING_LAYER; TestLayersVars *tlVars = new TestLayersVars[threadManager.getNumThreads()]; - for (curThreadNo = 0; curThreadNo < threadManager.getNumThreads(); curThreadNo++) { + for (curThreadNo = 0; curThreadNo < threadManager.getNumThreads(); curThreadNo++) + { tlVars[curThreadNo].curThreadNo = curThreadNo; tlVars[curThreadNo].pMiniMax = this; tlVars[curThreadNo].layerNumber = layerNumber; @@ -47,21 +49,26 @@ bool MiniMax::testLayer(unsigned int layerNumber) // process each state in the current layer returnValue = threadManager.executeParallelLoop(testLayerThreadProc, (void *)tlVars, sizeof(TestLayersVars), TM_SCHEDULE_STATIC, 0, layerStats[layerNumber].knotsInLayer - 1, 1); - switch (returnValue) { + switch (returnValue) + { case TM_RETURN_VALUE_OK: case TM_RETURN_VALUE_EXECUTION_CANCELLED: // reduce and delete thread specific data - for (numStatesProcessed = 0, curThreadNo = 0; curThreadNo < threadManager.getNumThreads(); curThreadNo++) { + for (numStatesProcessed = 0, curThreadNo = 0; curThreadNo < threadManager.getNumThreads(); curThreadNo++) + { numStatesProcessed += tlVars[curThreadNo].statesProcessed; SAFE_DELETE_ARRAY(tlVars[curThreadNo].subValueInDatabase); SAFE_DELETE_ARRAY(tlVars[curThreadNo].hasCurPlayerChanged); SAFE_DELETE_ARRAY(tlVars[curThreadNo].subPlyInfos); } SAFE_DELETE_ARRAY(tlVars); - if (returnValue == TM_RETURN_VALUE_EXECUTION_CANCELLED) { + if (returnValue == TM_RETURN_VALUE_EXECUTION_CANCELLED) + { PRINT(0, this, "Main thread: Execution cancelled by user"); - return false; // ... better would be to return a cancel-specific value - } else { + return false; // ... better would be to return a cancel-specific value + } + else + { break; } default: @@ -71,49 +78,54 @@ bool MiniMax::testLayer(unsigned int layerNumber) } // layer is not ok - if (numStatesProcessed < layerStats[layerNumber].knotsInLayer) { + if (numStatesProcessed < layerStats[layerNumber].knotsInLayer) + { PRINT(0, this, "DATABASE ERROR IN LAYER " << layerNumber); return falseOrStop(); // layer is ok - } else { - PRINT(1, this, " TEST PASSED !" << endl << endl); + } + else + { + PRINT(1, this, " TEST PASSED !" << endl + << endl); return true; } } //----------------------------------------------------------------------------- // Name: testLayerThreadProc() -// Desc: +// Desc: //----------------------------------------------------------------------------- DWORD MiniMax::testLayerThreadProc(void *pParameter, int index) { // locals TestLayersVars *tlVars = (TestLayersVars *)pParameter; MiniMax *m = tlVars->pMiniMax; - unsigned int layerNumber = tlVars->layerNumber; - unsigned int stateNumber = index; - unsigned int threadNo = tlVars->curThreadNo; + unsigned int layerNumber = tlVars->layerNumber; + unsigned int stateNumber = index; + unsigned int threadNo = tlVars->curThreadNo; TwoBit *subValueInDatabase = tlVars->subValueInDatabase; PlyInfoVarType *subPlyInfos = tlVars->subPlyInfos; bool *hasCurPlayerChanged = tlVars->hasCurPlayerChanged; - TwoBit shortValueInDatabase; - PlyInfoVarType numPliesTillCurState; - TwoBit shortValueInGame; - float floatValueInGame; - PlyInfoVarType min, max; - unsigned int numPossibilities; - unsigned int i, j; - unsigned int tmpStateNumber, tmpLayerNumber; + TwoBit shortValueInDatabase; + PlyInfoVarType numPliesTillCurState; + TwoBit shortValueInGame; + float floatValueInGame; + PlyInfoVarType min, max; + unsigned int numPossibilities; + unsigned int i, j; + unsigned int tmpStateNumber, tmpLayerNumber; unsigned int *idPossibility; void *pPossibilities; void *pBackup; - bool isOpponentLevel; - bool invalidLayerOrStateNumber; - bool layerInDatabaseAndCompleted; + bool isOpponentLevel; + bool invalidLayerOrStateNumber; + bool layerInDatabaseAndCompleted; // output tlVars->statesProcessed++; - if (tlVars->statesProcessed % OUTPUT_EVERY_N_STATES == 0) { + if (tlVars->statesProcessed % OUTPUT_EVERY_N_STATES == 0) + { m->numStatesProcessed += OUTPUT_EVERY_N_STATES; PRINT(0, m, m->numStatesProcessed << " states of " << m->layerStats[layerNumber].knotsInLayer << " tested"); } @@ -123,19 +135,24 @@ DWORD MiniMax::testLayerThreadProc(void *pParameter, int index) m->readPlyInfoFromDatabase(layerNumber, stateNumber, numPliesTillCurState); // prepare the situation - if (!m->setSituation(threadNo, layerNumber, stateNumber)) { + if (!m->setSituation(threadNo, layerNumber, stateNumber)) + { // when situation cannot be constructed then state must be marked as invalid in database - if (shortValueInDatabase != SKV_VALUE_INVALID || numPliesTillCurState != PLYINFO_VALUE_INVALID) { + if (shortValueInDatabase != SKV_VALUE_INVALID || numPliesTillCurState != PLYINFO_VALUE_INVALID) + { PRINT(0, m, "ERROR: DATABASE ERROR IN LAYER " << layerNumber << " AND STATE " << stateNumber << ": Could not set situation, but value is not invalid."); goto errorInDatabase; - } else { + } + else + { return TM_RETURN_VALUE_OK; } } // debug information - if (m->verbosity > 5) { + if (m->verbosity > 5) + { PRINT(5, m, "layer: " << layerNumber << " state: " << stateNumber); m->printBoard(threadNo, shortValueInDatabase); } @@ -145,23 +162,30 @@ DWORD MiniMax::testLayerThreadProc(void *pParameter, int index) idPossibility = m->getPossibilities(threadNo, &numPossibilities, &isOpponentLevel, &pPossibilities); // unable to move - if (numPossibilities == 0) { + if (numPossibilities == 0) + { // get ingame value m->getValueOfSituation(threadNo, floatValueInGame, shortValueInGame); // compare database with game - if (shortValueInDatabase != shortValueInGame || numPliesTillCurState != 0) { - PRINT(0, m, "ERROR: DATABASE ERROR IN LAYER " << layerNumber << " AND STATE " << stateNumber << ": Number of possibilities is zero, but knot value is not invalid or ply info equal zero."); goto errorInDatabase; + if (shortValueInDatabase != shortValueInGame || numPliesTillCurState != 0) + { + PRINT(0, m, "ERROR: DATABASE ERROR IN LAYER " << layerNumber << " AND STATE " << stateNumber << ": Number of possibilities is zero, but knot value is not invalid or ply info equal zero."); + goto errorInDatabase; } - if (shortValueInDatabase == SKV_VALUE_INVALID) { - PRINT(0, m, "ERROR: DATABASE ERROR IN LAYER " << layerNumber << " AND STATE " << stateNumber << ": Number of possibilities is zero, but knot value is invalid."); goto errorInDatabase; + if (shortValueInDatabase == SKV_VALUE_INVALID) + { + PRINT(0, m, "ERROR: DATABASE ERROR IN LAYER " << layerNumber << " AND STATE " << stateNumber << ": Number of possibilities is zero, but knot value is invalid."); + goto errorInDatabase; } - - } else { + } + else + { // check each possible move - for (i = 0; i < numPossibilities; i++) { + for (i = 0; i < numPossibilities; i++) + { // move m->move(threadNo, idPossibility[i], isOpponentLevel, &pBackup, pPossibilities); @@ -172,14 +196,17 @@ DWORD MiniMax::testLayerThreadProc(void *pParameter, int index) hasCurPlayerChanged[i] = (m->getOpponentLevel(threadNo) == true); // debug information - if (m->verbosity > 5) { + if (m->verbosity > 5) + { PRINT(5, m, "layer: " << tmpLayerNumber << " state: " << tmpStateNumber << " value: " << (int)subValueInDatabase[i]); m->printBoard(threadNo, subValueInDatabase[i]); } // if layer or state number is invalid then value of testes state must be invalid - if (invalidLayerOrStateNumber && shortValueInDatabase != SKV_VALUE_INVALID) { - PRINT(0, m, "ERROR: DATABASE ERROR IN LAYER " << layerNumber << " AND STATE " << stateNumber << ": Succeding state has invalid layer (" << tmpLayerNumber << ")or state number (" << tmpStateNumber << "), but tested state is not marked as invalid."); goto errorInDatabase; + if (invalidLayerOrStateNumber && shortValueInDatabase != SKV_VALUE_INVALID) + { + PRINT(0, m, "ERROR: DATABASE ERROR IN LAYER " << layerNumber << " AND STATE " << stateNumber << ": Succeding state has invalid layer (" << tmpLayerNumber << ")or state number (" << tmpStateNumber << "), but tested state is not marked as invalid."); + goto errorInDatabase; } // BUG: Does not work because, layer 101 is calculated before 105, although removing a stone does need this jump. // if (!layerInDatabaseAndCompleted) { PRINT(0,m, "ERROR: DATABASE ERROR IN LAYER " << layerNumber << " AND STATE " << stateNumber << ": Succeding state " << tmpStateNumber << " in an uncalculated layer " << tmpLayerNumber << "! Calc layer first!"); goto errorInDatabase; } @@ -189,39 +216,50 @@ DWORD MiniMax::testLayerThreadProc(void *pParameter, int index) } // value possible? - switch (shortValueInDatabase) { + switch (shortValueInDatabase) + { case SKV_VALUE_GAME_LOST: // all possible moves must be lost for the current player or won for the opponent - for (i = 0; i < numPossibilities; i++) { - if (subValueInDatabase[i] != ((hasCurPlayerChanged[i]) ? SKV_VALUE_GAME_WON : SKV_VALUE_GAME_LOST) && subValueInDatabase[i] != SKV_VALUE_INVALID) { + for (i = 0; i < numPossibilities; i++) + { + if (subValueInDatabase[i] != ((hasCurPlayerChanged[i]) ? SKV_VALUE_GAME_WON : SKV_VALUE_GAME_LOST) && subValueInDatabase[i] != SKV_VALUE_INVALID) + { PRINT(0, m, "ERROR: DATABASE ERROR IN LAYER " << layerNumber << " AND STATE " << stateNumber << ": All possible moves must be lost for the current player or won for the opponent"); goto errorInDatabase; } } // not all options can be invalid - for (j = 0, i = 0; i < numPossibilities; i++) { - if (subValueInDatabase[i] == SKV_VALUE_INVALID) { + for (j = 0, i = 0; i < numPossibilities; i++) + { + if (subValueInDatabase[i] == SKV_VALUE_INVALID) + { j++; } } - if (j == numPossibilities) { + if (j == numPossibilities) + { PRINT(0, m, "DATABASE ERROR IN LAYER " << layerNumber << " AND STATE " << stateNumber << ". Not all options can be invalid"); } // ply info must be max(subPlyInfos[]+1) max = 0; - for (i = 0; i < numPossibilities; i++) { - if (subValueInDatabase[i] == ((hasCurPlayerChanged[i]) ? SKV_VALUE_GAME_WON : SKV_VALUE_GAME_LOST)) { - if (subPlyInfos[i] + 1 > max) { + for (i = 0; i < numPossibilities; i++) + { + if (subValueInDatabase[i] == ((hasCurPlayerChanged[i]) ? SKV_VALUE_GAME_WON : SKV_VALUE_GAME_LOST)) + { + if (subPlyInfos[i] + 1 > max) + { max = subPlyInfos[i] + 1; } } } - if (numPliesTillCurState > PLYINFO_VALUE_DRAWN) { + if (numPliesTillCurState > PLYINFO_VALUE_DRAWN) + { PRINT(0, m, "DATABASE ERROR IN LAYER " << layerNumber << " AND STATE " << stateNumber << ": Knot value is LOST, but numPliesTillCurState is bigger than PLYINFO_MAX_VALUE."); goto errorInDatabase; } - if (numPliesTillCurState != max) { + if (numPliesTillCurState != max) + { PRINT(0, m, "DATABASE ERROR IN LAYER " << layerNumber << " AND STATE " << stateNumber << ": Number of needed plies is not maximal for LOST state."); goto errorInDatabase; } @@ -230,29 +268,37 @@ DWORD MiniMax::testLayerThreadProc(void *pParameter, int index) case SKV_VALUE_GAME_WON: // at least one possible move must be lost for the opponent or won for the current player - for (i = 0; i < numPossibilities; i++) { + for (i = 0; i < numPossibilities; i++) + { // if (subValueInDatabase[i] == SKV_VALUE_INVALID) { PRINT(0,m, "DATABASE ERROR IN LAYER " << layerNumber << " AND STATE " << stateNumber << ": At least one possible move must be lost for the opponent or won for the current player. But subValueInDatabase[i] == SKV_VALUE_INVALID."); goto errorInDatabase; } - if (subValueInDatabase[i] == ((hasCurPlayerChanged[i]) ? SKV_VALUE_GAME_LOST : SKV_VALUE_GAME_WON)) i = numPossibilities; + if (subValueInDatabase[i] == ((hasCurPlayerChanged[i]) ? SKV_VALUE_GAME_LOST : SKV_VALUE_GAME_WON)) + i = numPossibilities; } - if (i == numPossibilities) { + if (i == numPossibilities) + { PRINT(0, m, "DATABASE ERROR IN LAYER " << layerNumber << " AND STATE " << stateNumber << ": At least one possible move must be lost for the opponent or won for the current player."); goto errorInDatabase; } // ply info must be min(subPlyInfos[]+1) min = PLYINFO_VALUE_DRAWN; - for (i = 0; i < numPossibilities; i++) { - if (subValueInDatabase[i] == ((hasCurPlayerChanged[i]) ? SKV_VALUE_GAME_LOST : SKV_VALUE_GAME_WON)) { - if (subPlyInfos[i] + 1 < min) { + for (i = 0; i < numPossibilities; i++) + { + if (subValueInDatabase[i] == ((hasCurPlayerChanged[i]) ? SKV_VALUE_GAME_LOST : SKV_VALUE_GAME_WON)) + { + if (subPlyInfos[i] + 1 < min) + { min = subPlyInfos[i] + 1; } } } - if (numPliesTillCurState > PLYINFO_VALUE_DRAWN) { + if (numPliesTillCurState > PLYINFO_VALUE_DRAWN) + { PRINT(0, m, "DATABASE ERROR IN LAYER " << layerNumber << " AND STATE " << stateNumber << ": Knot value is WON, but numPliesTillCurState is bigger than PLYINFO_MAX_VALUE."); goto errorInDatabase; } - if (numPliesTillCurState != min) { + if (numPliesTillCurState != min) + { PRINT(0, m, "DATABASE ERROR IN LAYER " << layerNumber << " AND STATE " << stateNumber << ": Number of needed plies is not minimal for WON state."); goto errorInDatabase; } @@ -261,38 +307,50 @@ DWORD MiniMax::testLayerThreadProc(void *pParameter, int index) case SKV_VALUE_GAME_DRAWN: // all possible moves must be won for the opponent, lost for the current player or drawn - for (j = 0, i = 0; i < numPossibilities; i++) { + for (j = 0, i = 0; i < numPossibilities; i++) + { // if (subValueInDatabase[i] == SKV_VALUE_INVALID) { PRINT(0,m, "DATABASE ERROR IN LAYER " << layerNumber << " AND STATE " << stateNumber << ": All possible moves must be won for the opponent, lost for the current player or drawn. But subValueInDatabase[i] == SKV_VALUE_INVALID."); goto errorInDatabase; } - if (subValueInDatabase[i] != ((hasCurPlayerChanged[i]) ? SKV_VALUE_GAME_WON : SKV_VALUE_GAME_LOST) - && subValueInDatabase[i] != SKV_VALUE_GAME_DRAWN - && subValueInDatabase[i] != SKV_VALUE_INVALID) { - PRINT(0, m, "DATABASE ERROR IN LAYER " << layerNumber << " AND STATE " << stateNumber << ": All possible moves must be won for the opponent, lost for the current player or drawn."); goto errorInDatabase; + if (subValueInDatabase[i] != ((hasCurPlayerChanged[i]) ? SKV_VALUE_GAME_WON : SKV_VALUE_GAME_LOST) && subValueInDatabase[i] != SKV_VALUE_GAME_DRAWN && subValueInDatabase[i] != SKV_VALUE_INVALID) + { + PRINT(0, m, "DATABASE ERROR IN LAYER " << layerNumber << " AND STATE " << stateNumber << ": All possible moves must be won for the opponent, lost for the current player or drawn."); + goto errorInDatabase; } - if (subValueInDatabase[i] == SKV_VALUE_GAME_DRAWN) j = 1; + if (subValueInDatabase[i] == SKV_VALUE_GAME_DRAWN) + j = 1; } // at least one succeding state must be drawn - if (j == 0) { - PRINT(0, m, "DATABASE ERROR IN LAYER " << layerNumber << " AND STATE " << stateNumber << ": At least one succeding state must be drawn."); goto errorInDatabase; + if (j == 0) + { + PRINT(0, m, "DATABASE ERROR IN LAYER " << layerNumber << " AND STATE " << stateNumber << ": At least one succeding state must be drawn."); + goto errorInDatabase; } // ply info must also be drawn - if (numPliesTillCurState != PLYINFO_VALUE_DRAWN) { - PRINT(0, m, "DATABASE ERROR IN LAYER " << layerNumber << " AND STATE " << stateNumber << ": Knot value is drawn but ply info is not!"); goto errorInDatabase; + if (numPliesTillCurState != PLYINFO_VALUE_DRAWN) + { + PRINT(0, m, "DATABASE ERROR IN LAYER " << layerNumber << " AND STATE " << stateNumber << ": Knot value is drawn but ply info is not!"); + goto errorInDatabase; } break; case SKV_VALUE_INVALID: // if setSituation() returned true but state value is invalid, then all following states must be invalid - for (i = 0; i < numPossibilities; i++) { - if (subValueInDatabase[i] != SKV_VALUE_INVALID) break; + for (i = 0; i < numPossibilities; i++) + { + if (subValueInDatabase[i] != SKV_VALUE_INVALID) + break; } - if (i != numPossibilities) { - PRINT(0, m, "DATABASE ERROR IN LAYER " << layerNumber << " AND STATE " << stateNumber << ": If setSituation() returned true but state value is invalid, then all following states must be invalid."); goto errorInDatabase; + if (i != numPossibilities) + { + PRINT(0, m, "DATABASE ERROR IN LAYER " << layerNumber << " AND STATE " << stateNumber << ": If setSituation() returned true but state value is invalid, then all following states must be invalid."); + goto errorInDatabase; } // ply info must also be invalid - if (numPliesTillCurState != PLYINFO_VALUE_INVALID) { - PRINT(0, m, "DATABASE ERROR IN LAYER " << layerNumber << " AND STATE " << stateNumber << ": Knot value is invalid but ply info is not!"); goto errorInDatabase; + if (numPliesTillCurState != PLYINFO_VALUE_INVALID) + { + PRINT(0, m, "DATABASE ERROR IN LAYER " << layerNumber << " AND STATE " << stateNumber << ": Knot value is invalid but ply info is not!"); + goto errorInDatabase; } break; } @@ -306,13 +364,13 @@ errorInDatabase: //----------------------------------------------------------------------------- // Name: testState() -// Desc: +// Desc: //----------------------------------------------------------------------------- bool MiniMax::testState(unsigned int layerNumber, unsigned int stateNumber) { // locals - TestLayersVars tlVars; - bool result; + TestLayersVars tlVars; + bool result; // prepare parameters for multithreading tlVars.curThreadNo = 0; @@ -323,7 +381,8 @@ bool MiniMax::testState(unsigned int layerNumber, unsigned int stateNumber) tlVars.subPlyInfos = new PlyInfoVarType[maxNumBranches]; tlVars.hasCurPlayerChanged = new bool[maxNumBranches]; - if (testLayerThreadProc(&tlVars, stateNumber) != TM_RETURN_VALUE_OK) result = false; + if (testLayerThreadProc(&tlVars, stateNumber) != TM_RETURN_VALUE_OK) + result = false; delete[] tlVars.subValueInDatabase; delete[] tlVars.subPlyInfos; @@ -334,13 +393,13 @@ bool MiniMax::testState(unsigned int layerNumber, unsigned int stateNumber) //----------------------------------------------------------------------------- // Name: testSetSituationAndGetPoss() -// Desc: +// Desc: //----------------------------------------------------------------------------- bool MiniMax::testSetSituationAndGetPoss(unsigned int layerNumber) { // Locals - unsigned int curThreadNo; - unsigned int returnValue; + unsigned int curThreadNo; + unsigned int returnValue; // output PRINT(1, this, endl << "*** Test each state in layer: " << layerNumber << " ***"); @@ -350,7 +409,8 @@ bool MiniMax::testSetSituationAndGetPoss(unsigned int layerNumber) numStatesProcessed = 0; curCalculationActionId = MM_ACTION_TESTING_LAYER; TestLayersVars *tlVars = new TestLayersVars[threadManager.getNumThreads()]; - for (curThreadNo = 0; curThreadNo < threadManager.getNumThreads(); curThreadNo++) { + for (curThreadNo = 0; curThreadNo < threadManager.getNumThreads(); curThreadNo++) + { tlVars[curThreadNo].curThreadNo = curThreadNo; tlVars[curThreadNo].pMiniMax = this; tlVars[curThreadNo].layerNumber = layerNumber; @@ -362,21 +422,26 @@ bool MiniMax::testSetSituationAndGetPoss(unsigned int layerNumber) // process each state in the current layer returnValue = threadManager.executeParallelLoop(testSetSituationThreadProc, (void *)tlVars, sizeof(TestLayersVars), TM_SCHEDULE_STATIC, 0, layerStats[layerNumber].knotsInLayer - 1, 1); - switch (returnValue) { + switch (returnValue) + { case TM_RETURN_VALUE_OK: case TM_RETURN_VALUE_EXECUTION_CANCELLED: // reduce and delete thread specific data - for (numStatesProcessed = 0, curThreadNo = 0; curThreadNo < threadManager.getNumThreads(); curThreadNo++) { + for (numStatesProcessed = 0, curThreadNo = 0; curThreadNo < threadManager.getNumThreads(); curThreadNo++) + { numStatesProcessed += tlVars[curThreadNo].statesProcessed; SAFE_DELETE_ARRAY(tlVars[curThreadNo].subValueInDatabase); SAFE_DELETE_ARRAY(tlVars[curThreadNo].hasCurPlayerChanged); SAFE_DELETE_ARRAY(tlVars[curThreadNo].subPlyInfos); } SAFE_DELETE_ARRAY(tlVars); - if (returnValue == TM_RETURN_VALUE_EXECUTION_CANCELLED) { + if (returnValue == TM_RETURN_VALUE_EXECUTION_CANCELLED) + { PRINT(0, this, "Main thread: Execution cancelled by user"); - return false; // ... better would be to return a cancel-specific value - } else { + return false; // ... better would be to return a cancel-specific value + } + else + { break; } default: @@ -386,19 +451,23 @@ bool MiniMax::testSetSituationAndGetPoss(unsigned int layerNumber) } // layer is not ok - if (numStatesProcessed < layerStats[layerNumber].knotsInLayer) { + if (numStatesProcessed < layerStats[layerNumber].knotsInLayer) + { PRINT(0, this, "DATABASE ERROR IN LAYER " << layerNumber); return falseOrStop(); // layer is ok - } else { - PRINT(1, this, " TEST PASSED !" << endl << endl); + } + else + { + PRINT(1, this, " TEST PASSED !" << endl + << endl); return true; } } //----------------------------------------------------------------------------- // Name: testSetSituationThreadProc() -// Desc: +// Desc: //----------------------------------------------------------------------------- DWORD MiniMax::testSetSituationThreadProc(void *pParameter, int index) { @@ -408,26 +477,30 @@ DWORD MiniMax::testSetSituationThreadProc(void *pParameter, int index) unsigned int *idPossibility; void *pPossibilities; void *pBackup; - unsigned int curPoss; - float floatValue; - StateAdress curState; - StateAdress subState; - Node knot; - TwoBit shortKnotValue = SKV_VALUE_GAME_DRAWN; + unsigned int curPoss; + float floatValue; + StateAdress curState; + StateAdress subState; + Node knot; + TwoBit shortKnotValue = SKV_VALUE_GAME_DRAWN; curState.layerNumber = tlVars->layerNumber; curState.stateNumber = index; // output tlVars->statesProcessed++; - if (tlVars->statesProcessed % OUTPUT_EVERY_N_STATES == 0) { + if (tlVars->statesProcessed % OUTPUT_EVERY_N_STATES == 0) + { m->numStatesProcessed += OUTPUT_EVERY_N_STATES; PRINT(0, m, m->numStatesProcessed << " states of " << m->layerStats[curState.layerNumber].knotsInLayer << " tested"); } // set state - if (m->setSituation(tlVars->curThreadNo, curState.layerNumber, curState.stateNumber)) { + if (m->setSituation(tlVars->curThreadNo, curState.layerNumber, curState.stateNumber)) + { m->getValueOfSituation(tlVars->curThreadNo, floatValue, shortKnotValue); - } else { + } + else + { shortKnotValue = SKV_VALUE_INVALID; } @@ -435,20 +508,26 @@ DWORD MiniMax::testSetSituationThreadProc(void *pParameter, int index) idPossibility = m->getPossibilities(tlVars->curThreadNo, &knot.numPossibilities, &knot.isOpponentLevel, &pPossibilities); // unable to move - if (knot.numPossibilities == 0) { - if (shortKnotValue == SKV_VALUE_GAME_DRAWN) { + if (knot.numPossibilities == 0) + { + if (shortKnotValue == SKV_VALUE_GAME_DRAWN) + { PRINT(0, m, "ERROR: Layer " << curState.layerNumber << " and state " << curState.stateNumber << ". setSituation() returned true, although getPossibilities() yields no possible moves."); return m->falseOrStop(); } // moving is possible - } else { - if (shortKnotValue == SKV_VALUE_INVALID) { + } + else + { + if (shortKnotValue == SKV_VALUE_INVALID) + { PRINT(0, m, "ERROR: Moved from layer " << curState.layerNumber << " and state " << curState.stateNumber << " setSituation() returned false, although getPossibilities() yields some possible moves."); return m->falseOrStop(); } // check each possibility - for (curPoss = 0; curPoss < knot.numPossibilities; curPoss++) { + for (curPoss = 0; curPoss < knot.numPossibilities; curPoss++) + { // move m->move(tlVars->curThreadNo, idPossibility[curPoss], knot.isOpponentLevel, &pBackup, pPossibilities); @@ -462,7 +541,8 @@ DWORD MiniMax::testSetSituationThreadProc(void *pParameter, int index) m->undo(tlVars->curThreadNo, idPossibility[curPoss], knot.isOpponentLevel, pBackup, pPossibilities); // state reached by move() must not be invalid - if (!m->setSituation(tlVars->curThreadNo, subState.layerNumber, subState.stateNumber)) { + if (!m->setSituation(tlVars->curThreadNo, subState.layerNumber, subState.stateNumber)) + { PRINT(0, m, "ERROR: Moved from layer " << curState.layerNumber << " and state " << curState.stateNumber << " to invalid situation layer " << curState.layerNumber << " and state " << curState.stateNumber); return m->falseOrStop(); } @@ -473,36 +553,38 @@ DWORD MiniMax::testSetSituationThreadProc(void *pParameter, int index) return TM_RETURN_VALUE_OK; //errorInDatabase: - // terminate all threads + // terminate all threads return TM_RETURN_VALUE_TERMINATE_ALL_THREADS; } //----------------------------------------------------------------------------- // Name: testIfSymStatesHaveSameValue() -// Desc: +// Desc: //----------------------------------------------------------------------------- bool MiniMax::testIfSymStatesHaveSameValue(unsigned int layerNumber) { // Locals - unsigned int threadNo = 0; - TwoBit shortValueInDatabase; - TwoBit shortValueOfSymState; - PlyInfoVarType numPliesTillCurState; - PlyInfoVarType numPliesTillSymState; - unsigned int stateNumber = 0; + unsigned int threadNo = 0; + TwoBit shortValueInDatabase; + TwoBit shortValueOfSymState; + PlyInfoVarType numPliesTillCurState; + PlyInfoVarType numPliesTillSymState; + unsigned int stateNumber = 0; unsigned int *symStateNumbers = nullptr; - unsigned int numSymmetricStates; - unsigned int i; + unsigned int numSymmetricStates; + unsigned int i; // database open? - if (hFileShortKnotValues == nullptr || hFilePlyInfo == nullptr) { + if (hFileShortKnotValues == nullptr || hFilePlyInfo == nullptr) + { PRINT(0, this, "ERROR: Database files not open!"); layerNumber = 0; goto errorInDatabase; } // layer completed ? - if (!layerStats[layerNumber].layerIsCompletedAndInFile) { + if (!layerStats[layerNumber].layerIsCompletedAndInFile) + { PRINT(0, this, "ERROR: Layer not in file!"); layerNumber = 0; goto errorInDatabase; @@ -513,33 +595,40 @@ bool MiniMax::testIfSymStatesHaveSameValue(unsigned int layerNumber) PRINT(1, this, (getOutputInformation(layerNumber))); skvfHeader.completed = false; - for (layerInDatabase = false, stateNumber = 0; stateNumber < layerStats[layerNumber].knotsInLayer; stateNumber++) { + for (layerInDatabase = false, stateNumber = 0; stateNumber < layerStats[layerNumber].knotsInLayer; stateNumber++) + { // output - if (stateNumber % OUTPUT_EVERY_N_STATES == 0) PRINT(1, this, stateNumber << " states of " << layerStats[layerNumber].knotsInLayer << " tested"); + if (stateNumber % OUTPUT_EVERY_N_STATES == 0) + PRINT(1, this, stateNumber << " states of " << layerStats[layerNumber].knotsInLayer << " tested"); // situation already existend in database ? readKnotValueFromDatabase(layerNumber, stateNumber, shortValueInDatabase); readPlyInfoFromDatabase(layerNumber, stateNumber, numPliesTillCurState); // prepare the situation - if (!setSituation(threadNo, layerNumber, stateNumber)) { + if (!setSituation(threadNo, layerNumber, stateNumber)) + { // when situation cannot be constructed then state must be marked as invalid in database - if (shortValueInDatabase != SKV_VALUE_INVALID || numPliesTillCurState != PLYINFO_VALUE_INVALID) goto errorInDatabase; - else continue; + if (shortValueInDatabase != SKV_VALUE_INVALID || numPliesTillCurState != PLYINFO_VALUE_INVALID) + goto errorInDatabase; + else + continue; } // get numbers of symmetric states getSymStateNumWithDoubles(threadNo, &numSymmetricStates, &symStateNumbers); // save value for all symmetric states - for (i = 0; i < numSymmetricStates; i++) { + for (i = 0; i < numSymmetricStates; i++) + { readKnotValueFromDatabase(layerNumber, symStateNumbers[i], shortValueOfSymState); readPlyInfoFromDatabase(layerNumber, symStateNumbers[i], numPliesTillSymState); - if (shortValueOfSymState != shortValueInDatabase || numPliesTillCurState != numPliesTillSymState) { + if (shortValueOfSymState != shortValueInDatabase || numPliesTillCurState != numPliesTillSymState) + { PRINT(2, this, "current tested state " << stateNumber << " has value " << (int)shortValueInDatabase); setSituation(threadNo, layerNumber, stateNumber); @@ -562,6 +651,7 @@ bool MiniMax::testIfSymStatesHaveSameValue(unsigned int layerNumber) errorInDatabase: // layer is not ok - if (layerNumber) PRINT(0, this, "DATABASE ERROR IN LAYER " << layerNumber << " AND STATE " << stateNumber); + if (layerNumber) + PRINT(0, this, "DATABASE ERROR IN LAYER " << layerNumber << " AND STATE " << stateNumber); return falseOrStop(); } diff --git a/src/perfect/perfectAI.cpp b/src/perfect/perfectAI.cpp index 7bae687e..331da580 100644 --- a/src/perfect/perfectAI.cpp +++ b/src/perfect/perfectAI.cpp @@ -9,178 +9,162 @@ #include "perfectAI.h" unsigned int soTableTurnLeft[] = { - 2, 14, 23, - 5, 13, 20, - 8,12,17, - 1, 4, 7, 16,19,22, - 6,11,15, - 3, 10, 18, - 0, 9, 21 -}; + 2, 14, 23, + 5, 13, 20, + 8, 12, 17, + 1, 4, 7, 16, 19, 22, + 6, 11, 15, + 3, 10, 18, + 0, 9, 21}; unsigned int soTableDoNothing[] = { - 0, 1, 2, - 3, 4, 5, - 6, 7, 8, - 9,10,11, 12,13,14, - 15,16,17, - 18, 19, 20, -21, 22, 23 -}; + 0, 1, 2, + 3, 4, 5, + 6, 7, 8, + 9, 10, 11, 12, 13, 14, + 15, 16, 17, + 18, 19, 20, + 21, 22, 23}; unsigned int soTableMirrorHori[] = { -21, 22, 23, - 18, 19, 20, - 15,16,17, - 9,10,11, 12,13,14, - 6, 7, 8, - 3, 4, 5, - 0, 1, 2 -}; + 21, 22, 23, + 18, 19, 20, + 15, 16, 17, + 9, 10, 11, 12, 13, 14, + 6, 7, 8, + 3, 4, 5, + 0, 1, 2}; unsigned int soTableTurn180[] = { - 23, 22, 21, - 20, 19, 18, - 17,16,15, - 14,13,12, 11,10, 9, - 8, 7, 6, - 5, 4, 3, - 2, 1, 0 -}; + 23, 22, 21, + 20, 19, 18, + 17, 16, 15, + 14, 13, 12, 11, 10, 9, + 8, 7, 6, + 5, 4, 3, + 2, 1, 0}; unsigned int soTableInvert[] = { - 6, 7, 8, - 3, 4, 5, - 0, 1, 2, - 11,10, 9, 14,13,12, - 21,22,23, - 18, 19, 20, - 15, 16, 17 -}; + 6, 7, 8, + 3, 4, 5, + 0, 1, 2, + 11, 10, 9, 14, 13, 12, + 21, 22, 23, + 18, 19, 20, + 15, 16, 17}; unsigned int soTableInvMirHori[] = { - 15, 16, 17, - 18, 19, 20, - 21,22,23, - 11,10, 9, 14,13,12, - 0, 1, 2, - 3, 4, 5, - 6, 7, 8 -}; + 15, 16, 17, + 18, 19, 20, + 21, 22, 23, + 11, 10, 9, 14, 13, 12, + 0, 1, 2, + 3, 4, 5, + 6, 7, 8}; unsigned int soTableInvMirVert[] = { - 8, 7, 6, - 5, 4, 3, - 2, 1, 0, - 12,13,14, 9,10,11, - 23,22,21, - 20, 19, 18, - 17, 16, 15 -}; + 8, 7, 6, + 5, 4, 3, + 2, 1, 0, + 12, 13, 14, 9, 10, 11, + 23, 22, 21, + 20, 19, 18, + 17, 16, 15}; unsigned int soTableInvMirDiag1[] = { - 17, 12, 8, - 20, 13, 5, - 23,14, 2, - 16,19,22, 1, 4, 7, - 21, 9, 0, - 18, 10, 3, - 15, 11, 6 -}; + 17, 12, 8, + 20, 13, 5, + 23, 14, 2, + 16, 19, 22, 1, 4, 7, + 21, 9, 0, + 18, 10, 3, + 15, 11, 6}; unsigned int soTableInvMirDiag2[] = { - 6, 11, 15, - 3, 10, 18, - 0, 9,21, - 7, 4, 1, 22,19,16, - 2,14,23, - 5, 13, 20, - 8, 12, 17 -}; + 6, 11, 15, + 3, 10, 18, + 0, 9, 21, + 7, 4, 1, 22, 19, 16, + 2, 14, 23, + 5, 13, 20, + 8, 12, 17}; unsigned int soTableInvLeft[] = { - 8, 12, 17, - 5, 13, 20, - 2,14,23, - 7, 4, 1, 22,19,16, - 0, 9,21, - 3, 10, 18, - 6, 11, 15 -}; + 8, 12, 17, + 5, 13, 20, + 2, 14, 23, + 7, 4, 1, 22, 19, 16, + 0, 9, 21, + 3, 10, 18, + 6, 11, 15}; unsigned int soTableInvRight[] = { - 15, 11, 6, - 18, 10, 3, - 21, 9, 0, - 16,19,22, 1, 4, 7, - 23,14, 2, - 20, 13, 5, - 17, 12, 8 -}; + 15, 11, 6, + 18, 10, 3, + 21, 9, 0, + 16, 19, 22, 1, 4, 7, + 23, 14, 2, + 20, 13, 5, + 17, 12, 8}; unsigned int soTableInv180[] = { - 17, 16, 15, - 20, 19, 18, - 23,22,21, - 12,13,14, 9,10,11, - 2, 1, 0, - 5, 4, 3, - 8, 7, 6 -}; + 17, 16, 15, + 20, 19, 18, + 23, 22, 21, + 12, 13, 14, 9, 10, 11, + 2, 1, 0, + 5, 4, 3, + 8, 7, 6}; unsigned int soTableMirrorDiag1[] = { - 0, 9, 21, - 3, 10, 18, - 6,11,15, - 1, 4, 7, 16,19,22, - 8,12,17, - 5, 13, 20, - 2, 14, 23 -}; + 0, 9, 21, + 3, 10, 18, + 6, 11, 15, + 1, 4, 7, 16, 19, 22, + 8, 12, 17, + 5, 13, 20, + 2, 14, 23}; unsigned int soTableTurnRight[] = { - 21, 9, 0, - 18, 10, 3, - 15,11, 6, - 22,19,16, 7, 4, 1, - 17,12, 8, - 20, 13, 5, - 23, 14, 2 -}; + 21, 9, 0, + 18, 10, 3, + 15, 11, 6, + 22, 19, 16, 7, 4, 1, + 17, 12, 8, + 20, 13, 5, + 23, 14, 2}; unsigned int soTableMirrorVert[] = { - 2, 1, 0, - 5, 4, 3, - 8, 7, 6, - 14,13,12, 11,10, 9, - 17,16,15, - 20, 19, 18, - 23, 22, 21 -}; + 2, 1, 0, + 5, 4, 3, + 8, 7, 6, + 14, 13, 12, 11, 10, 9, + 17, 16, 15, + 20, 19, 18, + 23, 22, 21}; unsigned int soTableMirrorDiag2[] = { - 23, 14, 2, - 20, 13, 5, - 17,12, 8, - 22,19,16, 7, 4, 1, - 15,11, 6, - 18, 10, 3, - 21, 9, 0 -}; + 23, 14, 2, + 20, 13, 5, + 17, 12, 8, + 22, 19, 16, 7, 4, 1, + 15, 11, 6, + 18, 10, 3, + 21, 9, 0}; // define the four groups -unsigned int squareIndexGroupA[] = { 3, 5, 20, 18 }; -unsigned int squareIndexGroupB[] = { 4, 13, 19, 10 }; -unsigned int squareIndexGroupC[] = { 0, 2, 23, 21, 6, 8, 17, 15 }; -unsigned int squareIndexGroupD[] = { 1, 7, 14, 12, 22, 16, 9, 11 }; +unsigned int squareIndexGroupA[] = {3, 5, 20, 18}; +unsigned int squareIndexGroupB[] = {4, 13, 19, 10}; +unsigned int squareIndexGroupC[] = {0, 2, 23, 21, 6, 8, 17, 15}; +unsigned int squareIndexGroupD[] = {1, 7, 14, 12, 22, 16, 9, 11}; -unsigned int fieldPosIsOfGroup[] = { GROUP_C, GROUP_D, GROUP_C, - GROUP_A, GROUP_B, GROUP_A, - GROUP_C,GROUP_D,GROUP_C, - GROUP_D,GROUP_B,GROUP_D, GROUP_D,GROUP_B,GROUP_D, - GROUP_C,GROUP_D,GROUP_C, - GROUP_A, GROUP_B, GROUP_A, - GROUP_C, GROUP_D, GROUP_C }; +unsigned int fieldPosIsOfGroup[] = {GROUP_C, GROUP_D, GROUP_C, + GROUP_A, GROUP_B, GROUP_A, + GROUP_C, GROUP_D, GROUP_C, + GROUP_D, GROUP_B, GROUP_D, GROUP_D, GROUP_B, GROUP_D, + GROUP_C, GROUP_D, GROUP_C, + GROUP_A, GROUP_B, GROUP_A, + GROUP_C, GROUP_D, GROUP_C}; //----------------------------------------------------------------------------- // Name: PerfectAI() @@ -189,21 +173,22 @@ unsigned int fieldPosIsOfGroup[] = { GROUP_C, GROUP_D, PerfectAI::PerfectAI(const char *directory) { // loacls - unsigned int i, a, b, c, totalNumStones; - unsigned int wCD, bCD, wAB, bAB; - unsigned int stateAB, stateCD, symStateCD, layerNum; - unsigned int myField[fieldStruct::size]; - unsigned int symField[fieldStruct::size]; + unsigned int i, a, b, c, totalNumStones; + unsigned int wCD, bCD, wAB, bAB; + unsigned int stateAB, stateCD, symStateCD, layerNum; + unsigned int myField[fieldStruct::size]; + unsigned int symField[fieldStruct::size]; unsigned int *originalStateCD_tmp[10][10]; - DWORD dwBytesRead = 0; - DWORD dwBytesWritten = 0; - HANDLE hFilePreCalcVars; - stringstream ssPreCalcVarsFilePath; - PreCalcedVarsFileHeader preCalcVarsHeader; + DWORD dwBytesRead = 0; + DWORD dwBytesWritten = 0; + HANDLE hFilePreCalcVars; + stringstream ssPreCalcVarsFilePath; + PreCalcedVarsFileHeader preCalcVarsHeader; - // + // threadVars = new ThreadVars[getNumThreads()]; - for (unsigned int curThread = 0; curThread < getNumThreads(); curThread++) { + for (unsigned int curThread = 0; curThread < getNumThreads(); curThread++) + { threadVars[curThread].parent = this; threadVars[curThread].field = &dummyField; threadVars[curThread].possibilities = new Possibility[MAX_DEPTH_OF_TREE + 1]; @@ -212,14 +197,17 @@ PerfectAI::PerfectAI(const char *directory) } // Open File, which contains the precalculated vars - if (strlen(directory) && PathFileExistsA(directory)) { + if (strlen(directory) && PathFileExistsA(directory)) + { ssPreCalcVarsFilePath << directory << "\\"; - } ssPreCalcVarsFilePath << "preCalculatedVars.dat"; + } + ssPreCalcVarsFilePath << "preCalculatedVars.dat"; hFilePreCalcVars = CreateFileA(ssPreCalcVarsFilePath.str().c_str(), GENERIC_READ /*| GENERIC_WRITE*/, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); ReadFile(hFilePreCalcVars, &preCalcVarsHeader, sizeof(PreCalcedVarsFileHeader), &dwBytesRead, nullptr); // vars already stored in file? - if (dwBytesRead) { + if (dwBytesRead) + { // Read from file ReadFile(hFilePreCalcVars, layer, sizeof(Layer) * NUM_LAYERS, &dwBytesRead, nullptr); @@ -239,35 +227,46 @@ PerfectAI::PerfectAI(const char *directory) ReadFile(hFilePreCalcVars, incidencesValuesSubMoves, sizeof(unsigned int) * 4 * fieldStruct::size * fieldStruct::size, &dwBytesRead, nullptr); // process originalStateAB[][] - for (a = 0; a <= NUM_STONES_PER_PLAYER; a++) { - for (b = 0; b <= NUM_STONES_PER_PLAYER; b++) { - if (a + b > numSquaresGroupA + numSquaresGroupB) continue; + for (a = 0; a <= NUM_STONES_PER_PLAYER; a++) + { + for (b = 0; b <= NUM_STONES_PER_PLAYER; b++) + { + if (a + b > numSquaresGroupA + numSquaresGroupB) + continue; originalStateAB[a][b] = new unsigned int[anzahlStellungenAB[a][b]]; ReadFile(hFilePreCalcVars, originalStateAB[a][b], sizeof(unsigned int) * anzahlStellungenAB[a][b], &dwBytesRead, nullptr); } } // process originalStateCD[][] - for (a = 0; a <= NUM_STONES_PER_PLAYER; a++) { - for (b = 0; b <= NUM_STONES_PER_PLAYER; b++) { - if (a + b > numSquaresGroupC + numSquaresGroupD) continue; + for (a = 0; a <= NUM_STONES_PER_PLAYER; a++) + { + for (b = 0; b <= NUM_STONES_PER_PLAYER; b++) + { + if (a + b > numSquaresGroupC + numSquaresGroupD) + continue; originalStateCD[a][b] = new unsigned int[anzahlStellungenCD[a][b]]; ReadFile(hFilePreCalcVars, originalStateCD[a][b], sizeof(unsigned int) * anzahlStellungenCD[a][b], &dwBytesRead, nullptr); } } // calculate vars and save into file - } else { + } + else + { // calc mOverN - for (a = 0; a <= fieldStruct::size; a++) { - for (b = 0; b <= fieldStruct::size; b++) { + for (a = 0; a <= fieldStruct::size; a++) + { + for (b = 0; b <= fieldStruct::size; b++) + { mOverN[a][b] = (unsigned int)mOverN_Function(a, b); } } // reset - for (i = 0; i < fieldStruct::size * fieldStruct::size; i++) { + for (i = 0; i < fieldStruct::size * fieldStruct::size; i++) + { plyInfoForOutput[i] = PLYINFO_VALUE_INVALID; valueOfMove[i] = SKV_VALUE_INVALID; incidencesValuesSubMoves[i][SKV_VALUE_INVALID] = 0; @@ -277,10 +276,12 @@ PerfectAI::PerfectAI(const char *directory) } // power of three - for (powerOfThree[0] = 1, i = 1; i < numSquaresGroupC + numSquaresGroupD; i++) powerOfThree[i] = 3 * powerOfThree[i - 1]; + for (powerOfThree[0] = 1, i = 1; i < numSquaresGroupC + numSquaresGroupD; i++) + powerOfThree[i] = 3 * powerOfThree[i - 1]; // symmetry operation table - for (i = 0; i < fieldStruct::size; i++) { + for (i = 0; i < fieldStruct::size; i++) + { symmetryOperationTable[SO_TURN_LEFT][i] = soTableTurnLeft[i]; symmetryOperationTable[SO_TURN_180][i] = soTableTurn180[i]; symmetryOperationTable[SO_TURN_RIGHT][i] = soTableTurnRight[i]; @@ -318,27 +319,35 @@ PerfectAI::PerfectAI(const char *directory) reverseSymOperation[SO_INV_MIR_DIAG_2] = SO_INV_MIR_DIAG_2; // concatenated symmetry operations - for (a = 0; a < NUM_SYM_OPERATIONS; a++) { - for (b = 0; b < NUM_SYM_OPERATIONS; b++) { + for (a = 0; a < NUM_SYM_OPERATIONS; a++) + { + for (b = 0; b < NUM_SYM_OPERATIONS; b++) + { // test each symmetry operation - for (c = 0; c < NUM_SYM_OPERATIONS; c++) { + for (c = 0; c < NUM_SYM_OPERATIONS; c++) + { // look if b(a(state)) == c(state) - for (i = 0; i < fieldStruct::size; i++) { - if (symmetryOperationTable[c][i] != symmetryOperationTable[a][symmetryOperationTable[b][i]]) break; + for (i = 0; i < fieldStruct::size; i++) + { + if (symmetryOperationTable[c][i] != symmetryOperationTable[a][symmetryOperationTable[b][i]]) + break; } // match found? - if (i == fieldStruct::size) { + if (i == fieldStruct::size) + { concSymOperation[a][b] = c; break; } } // no match found - if (c == NUM_SYM_OPERATIONS) { - cout << endl << "ERROR IN SYMMETRY-OPERATIONS!" << endl; + if (c == NUM_SYM_OPERATIONS) + { + cout << endl + << "ERROR IN SYMMETRY-OPERATIONS!" << endl; } } } @@ -346,10 +355,13 @@ PerfectAI::PerfectAI(const char *directory) // group A&B // // reserve memory - for (a = 0; a <= NUM_STONES_PER_PLAYER; a++) { - for (b = 0; b <= NUM_STONES_PER_PLAYER; b++) { + for (a = 0; a <= NUM_STONES_PER_PLAYER; a++) + { + for (b = 0; b <= NUM_STONES_PER_PLAYER; b++) + { - if (a + b > numSquaresGroupA + numSquaresGroupB) continue; + if (a + b > numSquaresGroupA + numSquaresGroupB) + continue; anzahlStellungenAB[a][b] = mOverN[numSquaresGroupA + numSquaresGroupB][a] * mOverN[numSquaresGroupA + numSquaresGroupB - a][b]; originalStateAB[a][b] = new unsigned int[anzahlStellungenAB[a][b]]; @@ -358,15 +370,19 @@ PerfectAI::PerfectAI(const char *directory) } // mark all indexCD as not indexed - for (stateAB = 0; stateAB < MAX_ANZ_STELLUNGEN_A * MAX_ANZ_STELLUNGEN_B; stateAB++) indexAB[stateAB] = NOT_INDEXED; + for (stateAB = 0; stateAB < MAX_ANZ_STELLUNGEN_A * MAX_ANZ_STELLUNGEN_B; stateAB++) + indexAB[stateAB] = NOT_INDEXED; - for (stateAB = 0; stateAB < MAX_ANZ_STELLUNGEN_A * MAX_ANZ_STELLUNGEN_B; stateAB++) { + for (stateAB = 0; stateAB < MAX_ANZ_STELLUNGEN_A * MAX_ANZ_STELLUNGEN_B; stateAB++) + { // new state ? - if (indexAB[stateAB] == NOT_INDEXED) { + if (indexAB[stateAB] == NOT_INDEXED) + { // zero board - for (i = 0; i < fieldStruct::size; i++) myField[i] = FREE_SQUARE; + for (i = 0; i < fieldStruct::size; i++) + myField[i] = FREE_SQUARE; // make board myField[squareIndexGroupA[0]] = (stateAB / powerOfThree[7]) % 3; @@ -379,11 +395,16 @@ PerfectAI::PerfectAI(const char *directory) myField[squareIndexGroupB[7]] = (stateAB / powerOfThree[0]) % 3; // count black and white stones - for (a = 0, i = 0; i < fieldStruct::size; i++) if (myField[i] == WHITE_STONE) a++; - for (b = 0, i = 0; i < fieldStruct::size; i++) if (myField[i] == BLACK_STONE) b++; + for (a = 0, i = 0; i < fieldStruct::size; i++) + if (myField[i] == WHITE_STONE) + a++; + for (b = 0, i = 0; i < fieldStruct::size; i++) + if (myField[i] == BLACK_STONE) + b++; // condition - if (a + b > numSquaresGroupA + numSquaresGroupB) continue; + if (a + b > numSquaresGroupA + numSquaresGroupB) + continue; // mark original state indexAB[stateAB] = anzahlStellungenAB[a][b]; @@ -397,9 +418,12 @@ PerfectAI::PerfectAI(const char *directory) // group C&D // // reserve memory - for (a = 0; a <= NUM_STONES_PER_PLAYER; a++) { - for (b = 0; b <= NUM_STONES_PER_PLAYER; b++) { - if (a + b > numSquaresGroupC + numSquaresGroupD) continue; + for (a = 0; a <= NUM_STONES_PER_PLAYER; a++) + { + for (b = 0; b <= NUM_STONES_PER_PLAYER; b++) + { + if (a + b > numSquaresGroupC + numSquaresGroupD) + continue; originalStateCD_tmp[a][b] = new unsigned int[mOverN[numSquaresGroupC + numSquaresGroupD][a] * mOverN[numSquaresGroupC + numSquaresGroupD - a][b]]; anzahlStellungenCD[a][b] = 0; } @@ -408,13 +432,16 @@ PerfectAI::PerfectAI(const char *directory) // mark all indexCD as not indexed memset(indexCD, NOT_INDEXED, 4 * MAX_ANZ_STELLUNGEN_C * MAX_ANZ_STELLUNGEN_D); - for (stateCD = 0; stateCD < MAX_ANZ_STELLUNGEN_C * MAX_ANZ_STELLUNGEN_D; stateCD++) { + for (stateCD = 0; stateCD < MAX_ANZ_STELLUNGEN_C * MAX_ANZ_STELLUNGEN_D; stateCD++) + { // new state ? - if (indexCD[stateCD] == NOT_INDEXED) { + if (indexCD[stateCD] == NOT_INDEXED) + { // zero board - for (i = 0; i < fieldStruct::size; i++) myField[i] = FREE_SQUARE; + for (i = 0; i < fieldStruct::size; i++) + myField[i] = FREE_SQUARE; // make board myField[squareIndexGroupC[0]] = (stateCD / powerOfThree[15]) % 3; @@ -435,13 +462,20 @@ PerfectAI::PerfectAI(const char *directory) myField[squareIndexGroupD[7]] = (stateCD / powerOfThree[0]) % 3; // count black and white stones - for (a = 0, i = 0; i < fieldStruct::size; i++) if (myField[i] == WHITE_STONE) a++; - for (b = 0, i = 0; i < fieldStruct::size; i++) if (myField[i] == BLACK_STONE) b++; + for (a = 0, i = 0; i < fieldStruct::size; i++) + if (myField[i] == WHITE_STONE) + a++; + for (b = 0, i = 0; i < fieldStruct::size; i++) + if (myField[i] == BLACK_STONE) + b++; // condition - if (a + b > numSquaresGroupC + numSquaresGroupD) continue; - if (a > NUM_STONES_PER_PLAYER) continue; - if (b > NUM_STONES_PER_PLAYER) continue; + if (a + b > numSquaresGroupC + numSquaresGroupD) + continue; + if (a > NUM_STONES_PER_PLAYER) + continue; + if (b > NUM_STONES_PER_PLAYER) + continue; // mark original state indexCD[stateCD] = anzahlStellungenCD[a][b]; @@ -449,28 +483,15 @@ PerfectAI::PerfectAI(const char *directory) originalStateCD_tmp[a][b][anzahlStellungenCD[a][b]] = stateCD; // mark all symmetric states - for (i = 0; i < NUM_SYM_OPERATIONS; i++) { + for (i = 0; i < NUM_SYM_OPERATIONS; i++) + { applySymmetrieOperationOnField(i, myField, symField); - symStateCD = symField[squareIndexGroupC[0]] * powerOfThree[15] - + symField[squareIndexGroupC[1]] * powerOfThree[14] - + symField[squareIndexGroupC[2]] * powerOfThree[13] - + symField[squareIndexGroupC[3]] * powerOfThree[12] - + symField[squareIndexGroupC[4]] * powerOfThree[11] - + symField[squareIndexGroupC[5]] * powerOfThree[10] - + symField[squareIndexGroupC[6]] * powerOfThree[9] - + symField[squareIndexGroupC[7]] * powerOfThree[8] - + symField[squareIndexGroupD[0]] * powerOfThree[7] - + symField[squareIndexGroupD[1]] * powerOfThree[6] - + symField[squareIndexGroupD[2]] * powerOfThree[5] - + symField[squareIndexGroupD[3]] * powerOfThree[4] - + symField[squareIndexGroupD[4]] * powerOfThree[3] - + symField[squareIndexGroupD[5]] * powerOfThree[2] - + symField[squareIndexGroupD[6]] * powerOfThree[1] - + symField[squareIndexGroupD[7]] * powerOfThree[0]; + symStateCD = symField[squareIndexGroupC[0]] * powerOfThree[15] + symField[squareIndexGroupC[1]] * powerOfThree[14] + symField[squareIndexGroupC[2]] * powerOfThree[13] + symField[squareIndexGroupC[3]] * powerOfThree[12] + symField[squareIndexGroupC[4]] * powerOfThree[11] + symField[squareIndexGroupC[5]] * powerOfThree[10] + symField[squareIndexGroupC[6]] * powerOfThree[9] + symField[squareIndexGroupC[7]] * powerOfThree[8] + symField[squareIndexGroupD[0]] * powerOfThree[7] + symField[squareIndexGroupD[1]] * powerOfThree[6] + symField[squareIndexGroupD[2]] * powerOfThree[5] + symField[squareIndexGroupD[3]] * powerOfThree[4] + symField[squareIndexGroupD[4]] * powerOfThree[3] + symField[squareIndexGroupD[5]] * powerOfThree[2] + symField[squareIndexGroupD[6]] * powerOfThree[1] + symField[squareIndexGroupD[7]] * powerOfThree[0]; - if (stateCD != symStateCD) { + if (stateCD != symStateCD) + { indexCD[symStateCD] = anzahlStellungenCD[a][b]; symmetryOperationCD[symStateCD] = reverseSymOperation[i]; } @@ -482,45 +503,64 @@ PerfectAI::PerfectAI(const char *directory) } // copy from originalStateCD_tmp to originalStateCD - for (a = 0; a <= NUM_STONES_PER_PLAYER; a++) { - for (b = 0; b <= NUM_STONES_PER_PLAYER; b++) { - if (a + b > numSquaresGroupC + numSquaresGroupD) continue; + for (a = 0; a <= NUM_STONES_PER_PLAYER; a++) + { + for (b = 0; b <= NUM_STONES_PER_PLAYER; b++) + { + if (a + b > numSquaresGroupC + numSquaresGroupD) + continue; originalStateCD[a][b] = new unsigned int[anzahlStellungenCD[a][b]]; - for (i = 0; i < anzahlStellungenCD[a][b]; i++) originalStateCD[a][b][i] = originalStateCD_tmp[a][b][i]; + for (i = 0; i < anzahlStellungenCD[a][b]; i++) + originalStateCD[a][b][i] = originalStateCD_tmp[a][b][i]; SAFE_DELETE_ARRAY(originalStateCD_tmp[a][b]); } } // moving phase - for (totalNumStones = 0, layerNum = 0; totalNumStones <= 18; totalNumStones++) { - for (a = 0; a <= totalNumStones; a++) { - for (b = 0; b <= totalNumStones - a; b++) { - if (a > NUM_STONES_PER_PLAYER) continue; - if (b > NUM_STONES_PER_PLAYER) continue; - if (a + b != totalNumStones) continue; + for (totalNumStones = 0, layerNum = 0; totalNumStones <= 18; totalNumStones++) + { + for (a = 0; a <= totalNumStones; a++) + { + for (b = 0; b <= totalNumStones - a; b++) + { + if (a > NUM_STONES_PER_PLAYER) + continue; + if (b > NUM_STONES_PER_PLAYER) + continue; + if (a + b != totalNumStones) + continue; layerIndex[LAYER_INDEX_MOVING_PHASE][a][b] = layerNum; layer[layerNum].numWhiteStones = a; layer[layerNum].numBlackStones = b; layer[layerNum].numSubLayers = 0; - for (wCD = 0; wCD <= layer[layerNum].numWhiteStones; wCD++) { - for (bCD = 0; bCD <= layer[layerNum].numBlackStones; bCD++) { + for (wCD = 0; wCD <= layer[layerNum].numWhiteStones; wCD++) + { + for (bCD = 0; bCD <= layer[layerNum].numBlackStones; bCD++) + { // calc number of white and black stones for group A&B wAB = layer[layerNum].numWhiteStones - wCD; bAB = layer[layerNum].numBlackStones - bCD; // conditions - if (wCD + wAB != layer[layerNum].numWhiteStones) continue; - if (bCD + bAB != layer[layerNum].numBlackStones) continue; - if (wAB + bAB > numSquaresGroupA + numSquaresGroupB) continue; - if (wCD + bCD > numSquaresGroupC + numSquaresGroupD) continue; + if (wCD + wAB != layer[layerNum].numWhiteStones) + continue; + if (bCD + bAB != layer[layerNum].numBlackStones) + continue; + if (wAB + bAB > numSquaresGroupA + numSquaresGroupB) + continue; + if (wCD + bCD > numSquaresGroupC + numSquaresGroupD) + continue; - if (layer[layerNum].numSubLayers > 0) { + if (layer[layerNum].numSubLayers > 0) + { layer[layerNum].subLayer[layer[layerNum].numSubLayers].maxIndex = layer[layerNum].subLayer[layer[layerNum].numSubLayers - 1].maxIndex + anzahlStellungenAB[wAB][bAB] * anzahlStellungenCD[wCD][bCD]; layer[layerNum].subLayer[layer[layerNum].numSubLayers].minIndex = layer[layerNum].subLayer[layer[layerNum].numSubLayers - 1].maxIndex + 1; - } else { + } + else + { layer[layerNum].subLayer[layer[layerNum].numSubLayers].maxIndex = anzahlStellungenAB[wAB][bAB] * anzahlStellungenCD[wCD][bCD] - 1; layer[layerNum].subLayer[layer[layerNum].numSubLayers].minIndex = 0; } @@ -539,34 +579,49 @@ PerfectAI::PerfectAI(const char *directory) } // setting phase - for (totalNumStones = 0, layerNum = NUM_LAYERS - 1; totalNumStones <= 2 * NUM_STONES_PER_PLAYER; totalNumStones++) { - for (a = 0; a <= totalNumStones; a++) { - for (b = 0; b <= totalNumStones - a; b++) { - if (a > NUM_STONES_PER_PLAYER) continue; - if (b > NUM_STONES_PER_PLAYER) continue; - if (a + b != totalNumStones) continue; + for (totalNumStones = 0, layerNum = NUM_LAYERS - 1; totalNumStones <= 2 * NUM_STONES_PER_PLAYER; totalNumStones++) + { + for (a = 0; a <= totalNumStones; a++) + { + for (b = 0; b <= totalNumStones - a; b++) + { + if (a > NUM_STONES_PER_PLAYER) + continue; + if (b > NUM_STONES_PER_PLAYER) + continue; + if (a + b != totalNumStones) + continue; layer[layerNum].numWhiteStones = a; layer[layerNum].numBlackStones = b; layerIndex[LAYER_INDEX_SETTING_PHASE][a][b] = layerNum; layer[layerNum].numSubLayers = 0; - for (wCD = 0; wCD <= layer[layerNum].numWhiteStones; wCD++) { - for (bCD = 0; bCD <= layer[layerNum].numBlackStones; bCD++) { + for (wCD = 0; wCD <= layer[layerNum].numWhiteStones; wCD++) + { + for (bCD = 0; bCD <= layer[layerNum].numBlackStones; bCD++) + { // calc number of white and black stones for group A&B wAB = layer[layerNum].numWhiteStones - wCD; bAB = layer[layerNum].numBlackStones - bCD; // conditions - if (wCD + wAB != layer[layerNum].numWhiteStones) continue; - if (bCD + bAB != layer[layerNum].numBlackStones) continue; - if (wAB + bAB > numSquaresGroupA + numSquaresGroupB) continue; - if (wCD + bCD > numSquaresGroupC + numSquaresGroupD) continue; + if (wCD + wAB != layer[layerNum].numWhiteStones) + continue; + if (bCD + bAB != layer[layerNum].numBlackStones) + continue; + if (wAB + bAB > numSquaresGroupA + numSquaresGroupB) + continue; + if (wCD + bCD > numSquaresGroupC + numSquaresGroupD) + continue; - if (layer[layerNum].numSubLayers > 0) { + if (layer[layerNum].numSubLayers > 0) + { layer[layerNum].subLayer[layer[layerNum].numSubLayers].maxIndex = layer[layerNum].subLayer[layer[layerNum].numSubLayers - 1].maxIndex + anzahlStellungenAB[wAB][bAB] * anzahlStellungenCD[wCD][bCD]; layer[layerNum].subLayer[layer[layerNum].numSubLayers].minIndex = layer[layerNum].subLayer[layer[layerNum].numSubLayers - 1].maxIndex + 1; - } else { + } + else + { layer[layerNum].subLayer[layer[layerNum].numSubLayers].maxIndex = anzahlStellungenAB[wAB][bAB] * anzahlStellungenCD[wCD][bCD] - 1; layer[layerNum].subLayer[layer[layerNum].numSubLayers].minIndex = 0; } @@ -605,17 +660,23 @@ PerfectAI::PerfectAI(const char *directory) WriteFile(hFilePreCalcVars, incidencesValuesSubMoves, sizeof(unsigned int) * 4 * fieldStruct::size * fieldStruct::size, &dwBytesWritten, nullptr); // process originalStateAB[][] - for (a = 0; a <= NUM_STONES_PER_PLAYER; a++) { - for (b = 0; b <= NUM_STONES_PER_PLAYER; b++) { - if (a + b > numSquaresGroupA + numSquaresGroupB) continue; + for (a = 0; a <= NUM_STONES_PER_PLAYER; a++) + { + for (b = 0; b <= NUM_STONES_PER_PLAYER; b++) + { + if (a + b > numSquaresGroupA + numSquaresGroupB) + continue; WriteFile(hFilePreCalcVars, originalStateAB[a][b], sizeof(unsigned int) * anzahlStellungenAB[a][b], &dwBytesWritten, nullptr); } } // process originalStateCD[][] - for (a = 0; a <= NUM_STONES_PER_PLAYER; a++) { - for (b = 0; b <= NUM_STONES_PER_PLAYER; b++) { - if (a + b > numSquaresGroupC + numSquaresGroupD) continue; + for (a = 0; a <= NUM_STONES_PER_PLAYER; a++) + { + for (b = 0; b <= NUM_STONES_PER_PLAYER; b++) + { + if (a + b > numSquaresGroupC + numSquaresGroupD) + continue; WriteFile(hFilePreCalcVars, originalStateCD[a][b], sizeof(unsigned int) * anzahlStellungenCD[a][b], &dwBytesWritten, nullptr); } } @@ -635,7 +696,8 @@ PerfectAI::~PerfectAI() unsigned int curThread; // release memory - for (curThread = 0; curThread < getNumThreads(); curThread++) { + for (curThread = 0; curThread < getNumThreads(); curThread++) + { SAFE_DELETE_ARRAY(threadVars[curThread].oldStates); SAFE_DELETE_ARRAY(threadVars[curThread].idPossibilities); SAFE_DELETE_ARRAY(threadVars[curThread].possibilities); @@ -646,7 +708,7 @@ PerfectAI::~PerfectAI() //----------------------------------------------------------------------------- // Name: play() -// Desc: +// Desc: //----------------------------------------------------------------------------- void PerfectAI::play(fieldStruct *theField, unsigned int *pushFrom, unsigned int *pushTo) { @@ -656,10 +718,11 @@ void PerfectAI::play(fieldStruct *theField, unsigned int *pushFrom, unsigned int // locals threadVars[0].field = theField; threadVars[0].ownId = threadVars[0].field->curPlayer->id; - unsigned int bestChoice, i; + unsigned int bestChoice, i; // reset - for (i = 0; i < fieldStruct::size * fieldStruct::size; i++) { + for (i = 0; i < fieldStruct::size * fieldStruct::size; i++) + { valueOfMove[i] = SKV_VALUE_INVALID; plyInfoForOutput[i] = PLYINFO_VALUE_INVALID; incidencesValuesSubMoves[i][SKV_VALUE_INVALID] = 0; @@ -671,14 +734,19 @@ void PerfectAI::play(fieldStruct *theField, unsigned int *pushFrom, unsigned int // open database file openDatabase(databaseDirectory.c_str(), MAX_NUM_POS_MOVES); - if (theField->settingPhase) threadVars[0].depthOfFullTree = 2; - else threadVars[0].depthOfFullTree = 2; + if (theField->settingPhase) + threadVars[0].depthOfFullTree = 2; + else + threadVars[0].depthOfFullTree = 2; // current state already calculated? - if (isCurrentStateInDatabase(0)) { + if (isCurrentStateInDatabase(0)) + { cout << "PerfectAI is using database!\n\n\n"; threadVars[0].depthOfFullTree = 3; - } else { + } + else + { cout << "PerfectAI is thinking thinking with a depth of " << threadVars[0].depthOfFullTree << " steps!\n\n\n"; } @@ -686,11 +754,18 @@ void PerfectAI::play(fieldStruct *theField, unsigned int *pushFrom, unsigned int Possibility *rootPossibilities = (Possibility *)getBestChoice(threadVars[0].depthOfFullTree, &bestChoice, MAX_NUM_POS_MOVES); // decode the best choice - if (threadVars[0].field->stoneMustBeRemoved) { - *pushFrom = bestChoice; *pushTo = 0; - } else if (threadVars[0].field->settingPhase) { - *pushFrom = 0; *pushTo = bestChoice; - } else { + if (threadVars[0].field->stoneMustBeRemoved) + { + *pushFrom = bestChoice; + *pushTo = 0; + } + else if (threadVars[0].field->settingPhase) + { + *pushFrom = 0; + *pushTo = bestChoice; + } + else + { *pushFrom = rootPossibilities->from[bestChoice]; *pushTo = rootPossibilities->to[bestChoice]; } @@ -701,15 +776,16 @@ void PerfectAI::play(fieldStruct *theField, unsigned int *pushFrom, unsigned int //----------------------------------------------------------------------------- // Name: prepareDatabaseCalculation() -// Desc: +// Desc: //----------------------------------------------------------------------------- void PerfectAI::prepareDatabaseCalculation() { // only prepare layers? - unsigned int curThread; + unsigned int curThread; // create a temporary board - for (curThread = 0; curThread < getNumThreads(); curThread++) { + for (curThread = 0; curThread < getNumThreads(); curThread++) + { threadVars[curThread].field = new fieldStruct(); threadVars[curThread].field->createBoard(); setOpponentLevel(curThread, false); @@ -721,7 +797,7 @@ void PerfectAI::prepareDatabaseCalculation() //----------------------------------------------------------------------------- // Name: wrapUpDatabaseCalculation() -// Desc: +// Desc: //----------------------------------------------------------------------------- void PerfectAI::wrapUpDatabaseCalculation(bool calculationAborted) { @@ -729,7 +805,8 @@ void PerfectAI::wrapUpDatabaseCalculation(bool calculationAborted) unsigned int curThread; // release memory - for (curThread = 0; curThread < getNumThreads(); curThread++) { + for (curThread = 0; curThread < getNumThreads(); curThread++) + { threadVars[curThread].field->deleteBoard(); SAFE_DELETE(threadVars[curThread].field); threadVars[curThread].field = &dummyField; @@ -738,19 +815,23 @@ void PerfectAI::wrapUpDatabaseCalculation(bool calculationAborted) //----------------------------------------------------------------------------- // Name: testLayers() -// Desc: +// Desc: //----------------------------------------------------------------------------- bool PerfectAI::testLayers(unsigned int startTestFromLayer, unsigned int endTestAtLayer) { // locals unsigned int curLayer; - bool result = true; + bool result = true; - for (curLayer = startTestFromLayer; curLayer <= endTestAtLayer; curLayer++) { + for (curLayer = startTestFromLayer; curLayer <= endTestAtLayer; curLayer++) + { closeDatabase(); - if (!openDatabase(databaseDirectory.c_str(), MAX_NUM_POS_MOVES)) result = false; - if (!testIfSymStatesHaveSameValue(curLayer)) result = false; - if (!testLayer(curLayer)) result = false; + if (!openDatabase(databaseDirectory.c_str(), MAX_NUM_POS_MOVES)) + result = false; + if (!testIfSymStatesHaveSameValue(curLayer)) + result = false; + if (!testLayer(curLayer)) + result = false; unloadAllLayers(); unloadAllPlyInfos(); closeDatabase(); @@ -760,13 +841,16 @@ bool PerfectAI::testLayers(unsigned int startTestFromLayer, unsigned int endTest //----------------------------------------------------------------------------- // Name: setDatabasePath() -// Desc: +// Desc: //----------------------------------------------------------------------------- bool PerfectAI::setDatabasePath(const char *directory) { - if (directory == nullptr) { + if (directory == nullptr) + { return false; - } else { + } + else + { cout << "Path to database set to: " << directory << endl; databaseDirectory.assign(directory); return true; @@ -775,11 +859,12 @@ bool PerfectAI::setDatabasePath(const char *directory) //----------------------------------------------------------------------------- // Name: prepareBestChoiceCalculation() -// Desc: +// Desc: //----------------------------------------------------------------------------- void PerfectAI::prepareBestChoiceCalculation() { - for (unsigned int curThread = 0; curThread < getNumThreads(); curThread++) { + for (unsigned int curThread = 0; curThread < getNumThreads(); curThread++) + { threadVars[curThread].floatValue = 0.0f; threadVars[curThread].shortValue = SKV_VALUE_INVALID; threadVars[curThread].gameHasFinished = false; @@ -789,7 +874,7 @@ void PerfectAI::prepareBestChoiceCalculation() //----------------------------------------------------------------------------- // Name: ThreadVars() -// Desc: +// Desc: //----------------------------------------------------------------------------- PerfectAI::ThreadVars::ThreadVars() { @@ -804,78 +889,88 @@ PerfectAI::ThreadVars::ThreadVars() oldStates = nullptr; possibilities = nullptr; parent = nullptr; - } //----------------------------------------------------------------------------- // Name: getPossSettingPhase() -// Desc: +// Desc: //----------------------------------------------------------------------------- unsigned int *PerfectAI::ThreadVars::getPossSettingPhase(unsigned int *numPossibilities, void **pPossibilities) { // locals unsigned int i; unsigned int *idPossibility = &idPossibilities[curSearchDepth * MAX_NUM_POS_MOVES]; - bool stoneCanBeRemoved; + bool stoneCanBeRemoved; unsigned int numberOfMillsBeeingClosed; // check if an opponent stone can be removed - for (stoneCanBeRemoved = false, i = 0; i < field->size; i++) { - if (field->board[i] == field->oppPlayer->id && field->stonePartOfMill[i] == 0) { + for (stoneCanBeRemoved = false, i = 0; i < field->size; i++) + { + if (field->board[i] == field->oppPlayer->id && field->stonePartOfMill[i] == 0) + { stoneCanBeRemoved = true; break; } } // possibilities with cut off - for ((*numPossibilities) = 0, i = 0; i < field->size; i++) { + for ((*numPossibilities) = 0, i = 0; i < field->size; i++) + { // move possible ? - if (field->board[i] == field->squareIsFree) { + if (field->board[i] == field->squareIsFree) + { // check if a mill is beeing closed numberOfMillsBeeingClosed = 0; - if (field->curPlayer->id == field->board[field->neighbour[i][0][0]] && field->curPlayer->id == field->board[field->neighbour[i][0][1]]) numberOfMillsBeeingClosed++; - if (field->curPlayer->id == field->board[field->neighbour[i][1][0]] && field->curPlayer->id == field->board[field->neighbour[i][1][1]]) numberOfMillsBeeingClosed++; + if (field->curPlayer->id == field->board[field->neighbour[i][0][0]] && field->curPlayer->id == field->board[field->neighbour[i][0][1]]) + numberOfMillsBeeingClosed++; + if (field->curPlayer->id == field->board[field->neighbour[i][1][0]] && field->curPlayer->id == field->board[field->neighbour[i][1][1]]) + numberOfMillsBeeingClosed++; // Version 15: don't allow to close two mills at once // Version 25: don't allow to close a mill, although no stone can be removed from the opponent - if ((numberOfMillsBeeingClosed < 2) && (numberOfMillsBeeingClosed == 0 || stoneCanBeRemoved)) { + if ((numberOfMillsBeeingClosed < 2) && (numberOfMillsBeeingClosed == 0 || stoneCanBeRemoved)) + { idPossibility[*numPossibilities] = i; (*numPossibilities)++; } - } } // possibility code is simple - if (pPossibilities != nullptr) *pPossibilities = nullptr; + if (pPossibilities != nullptr) + *pPossibilities = nullptr; return idPossibility; } //----------------------------------------------------------------------------- // Name: getPossNormalMove() -// Desc: +// Desc: //----------------------------------------------------------------------------- unsigned int *PerfectAI::ThreadVars::getPossNormalMove(unsigned int *numPossibilities, void **pPossibilities) { // locals - unsigned int from, to, dir; + unsigned int from, to, dir; unsigned int *idPossibility = &idPossibilities[curSearchDepth * MAX_NUM_POS_MOVES]; Possibility *possibility = &possibilities[curSearchDepth]; // if he is not allowed to spring - if (field->curPlayer->numStones > 3) { + if (field->curPlayer->numStones > 3) + { - for ((*numPossibilities) = 0, from = 0; from < field->size; from++) { - for (dir = 0; dir < 4; dir++) { + for ((*numPossibilities) = 0, from = 0; from < field->size; from++) + { + for (dir = 0; dir < 4; dir++) + { - // destination + // destination to = field->connectedSquare[from][dir]; // move possible ? - if (to < field->size && field->board[from] == field->curPlayer->id && field->board[to] == field->squareIsFree) { + if (to < field->size && field->board[from] == field->curPlayer->id && field->board[to] == field->squareIsFree) + { // stone is moveable idPossibility[*numPossibilities] = *numPossibilities; @@ -887,13 +982,18 @@ unsigned int *PerfectAI::ThreadVars::getPossNormalMove(unsigned int *numPossibil } } } - } else if (field->curPlayer->numStones == 3) { + } + else if (field->curPlayer->numStones == 3) + { - for ((*numPossibilities) = 0, from = 0; from < field->size; from++) { - for (to = 0; to < field->size; to++) { + for ((*numPossibilities) = 0, from = 0; from < field->size; from++) + { + for (to = 0; to < field->size; to++) + { // move possible ? - if (field->board[from] == field->curPlayer->id && field->board[to] == field->squareIsFree && *numPossibilities < MAX_NUM_POS_MOVES) { + if (field->board[from] == field->curPlayer->id && field->board[to] == field->squareIsFree && *numPossibilities < MAX_NUM_POS_MOVES) + { // stone is moveable idPossibility[*numPossibilities] = *numPossibilities; @@ -903,19 +1003,22 @@ unsigned int *PerfectAI::ThreadVars::getPossNormalMove(unsigned int *numPossibil } } } - } else { + } + else + { *numPossibilities = 0; } // pass possibilities - if (pPossibilities != nullptr) *pPossibilities = (void *)possibility; + if (pPossibilities != nullptr) + *pPossibilities = (void *)possibility; return idPossibility; } //----------------------------------------------------------------------------- // Name: getPossStoneRemove() -// Desc: +// Desc: //----------------------------------------------------------------------------- unsigned int *PerfectAI::ThreadVars::getPossStoneRemove(unsigned int *numPossibilities, void **pPossibilities) { @@ -924,10 +1027,12 @@ unsigned int *PerfectAI::ThreadVars::getPossStoneRemove(unsigned int *numPossibi unsigned int *idPossibility = &idPossibilities[curSearchDepth * MAX_NUM_POS_MOVES]; // possibilities with cut off - for ((*numPossibilities) = 0, i = 0; i < field->size; i++) { + for ((*numPossibilities) = 0, i = 0; i < field->size; i++) + { // move possible ? - if (field->board[i] == field->oppPlayer->id && !field->stonePartOfMill[i]) { + if (field->board[i] == field->oppPlayer->id && !field->stonePartOfMill[i]) + { idPossibility[*numPossibilities] = i; (*numPossibilities)++; @@ -935,19 +1040,20 @@ unsigned int *PerfectAI::ThreadVars::getPossStoneRemove(unsigned int *numPossibi } // possibility code is simple - if (pPossibilities != nullptr) *pPossibilities = nullptr; + if (pPossibilities != nullptr) + *pPossibilities = nullptr; return idPossibility; } //----------------------------------------------------------------------------- // Name: getPossibilities() -// Desc: +// Desc: //----------------------------------------------------------------------------- unsigned int *PerfectAI::getPossibilities(unsigned int threadNo, unsigned int *numPossibilities, bool *opponentsMove, void **pPossibilities) { // locals - bool aStoneCanBeRemovedFromCurPlayer = 0; + bool aStoneCanBeRemovedFromCurPlayer = 0; unsigned int numberOfMillsCurrentPlayer = 0; unsigned int numberOfMillsOpponentPlayer = 0; unsigned int i; @@ -957,29 +1063,39 @@ unsigned int *PerfectAI::getPossibilities(unsigned int threadNo, unsigned int *n *opponentsMove = (tv->field->curPlayer->id == tv->ownId) ? false : true; // count completed mills - for (i = 0; i < fieldStruct::size; i++) { - if (tv->field->board[i] == tv->field->curPlayer->id) numberOfMillsCurrentPlayer += tv->field->stonePartOfMill[i]; - else numberOfMillsOpponentPlayer += tv->field->stonePartOfMill[i]; - if (tv->field->stonePartOfMill[i] == 0 && tv->field->board[i] == tv->field->curPlayer->id) aStoneCanBeRemovedFromCurPlayer = true; + for (i = 0; i < fieldStruct::size; i++) + { + if (tv->field->board[i] == tv->field->curPlayer->id) + numberOfMillsCurrentPlayer += tv->field->stonePartOfMill[i]; + else + numberOfMillsOpponentPlayer += tv->field->stonePartOfMill[i]; + if (tv->field->stonePartOfMill[i] == 0 && tv->field->board[i] == tv->field->curPlayer->id) + aStoneCanBeRemovedFromCurPlayer = true; } numberOfMillsCurrentPlayer /= 3; numberOfMillsOpponentPlayer /= 3; // When game has ended of course nothing happens any more - if (tv->gameHasFinished || !tv->fieldIntegrityOK(numberOfMillsCurrentPlayer, numberOfMillsOpponentPlayer, aStoneCanBeRemovedFromCurPlayer)) { + if (tv->gameHasFinished || !tv->fieldIntegrityOK(numberOfMillsCurrentPlayer, numberOfMillsOpponentPlayer, aStoneCanBeRemovedFromCurPlayer)) + { *numPossibilities = 0; return 0; // look what is to do - } else { - if (tv->field->stoneMustBeRemoved) return tv->getPossStoneRemove(numPossibilities, pPossibilities); - else if (tv->field->settingPhase) return tv->getPossSettingPhase(numPossibilities, pPossibilities); - else return tv->getPossNormalMove(numPossibilities, pPossibilities); + } + else + { + if (tv->field->stoneMustBeRemoved) + return tv->getPossStoneRemove(numPossibilities, pPossibilities); + else if (tv->field->settingPhase) + return tv->getPossSettingPhase(numPossibilities, pPossibilities); + else + return tv->getPossNormalMove(numPossibilities, pPossibilities); } } //----------------------------------------------------------------------------- // Name: getValueOfSituation() -// Desc: +// Desc: //----------------------------------------------------------------------------- void PerfectAI::getValueOfSituation(unsigned int threadNo, float &floatValue, TwoBit &shortValue) { @@ -990,7 +1106,7 @@ void PerfectAI::getValueOfSituation(unsigned int threadNo, float &floatValue, Tw //----------------------------------------------------------------------------- // Name: deletePossibilities() -// Desc: +// Desc: //----------------------------------------------------------------------------- void PerfectAI::deletePossibilities(unsigned int threadNo, void *pPossibilities) { @@ -998,7 +1114,7 @@ void PerfectAI::deletePossibilities(unsigned int threadNo, void *pPossibilities) //----------------------------------------------------------------------------- // Name: undo() -// Desc: +// Desc: //----------------------------------------------------------------------------- void PerfectAI::undo(unsigned int threadNo, unsigned int idPossibility, bool opponentsMove, void *pBackup, void *pPossibilities) { @@ -1027,19 +1143,21 @@ void PerfectAI::undo(unsigned int threadNo, unsigned int idPossibility, bool opp tv->field->board[oldState->to] = oldState->fieldTo; // very expensive - for (int i = 0; i < tv->field->size; i++) { + for (int i = 0; i < tv->field->size; i++) + { tv->field->stonePartOfMill[i] = oldState->stonePartOfMill[i]; } } //----------------------------------------------------------------------------- // Name: setWarning() -// Desc: +// Desc: //----------------------------------------------------------------------------- inline void PerfectAI::ThreadVars::setWarning(unsigned int stoneOne, unsigned int stoneTwo, unsigned int stoneThree) { // if all 3 fields are occupied by current player than he closed a mill - if (field->board[stoneOne] == field->curPlayer->id && field->board[stoneTwo] == field->curPlayer->id && field->board[stoneThree] == field->curPlayer->id) { + if (field->board[stoneOne] == field->curPlayer->id && field->board[stoneTwo] == field->curPlayer->id && field->board[stoneThree] == field->curPlayer->id) + { field->stonePartOfMill[stoneOne]++; field->stonePartOfMill[stoneTwo]++; field->stonePartOfMill[stoneThree]++; @@ -1047,7 +1165,8 @@ inline void PerfectAI::ThreadVars::setWarning(unsigned int stoneOne, unsigned in } // is a mill destroyed ? - if (field->board[stoneOne] == field->squareIsFree && field->stonePartOfMill[stoneOne] && field->stonePartOfMill[stoneTwo] && field->stonePartOfMill[stoneThree]) { + if (field->board[stoneOne] == field->squareIsFree && field->stonePartOfMill[stoneOne] && field->stonePartOfMill[stoneTwo] && field->stonePartOfMill[stoneThree]) + { field->stonePartOfMill[stoneOne]--; field->stonePartOfMill[stoneTwo]--; field->stonePartOfMill[stoneThree]--; @@ -1056,76 +1175,100 @@ inline void PerfectAI::ThreadVars::setWarning(unsigned int stoneOne, unsigned in //----------------------------------------------------------------------------- // Name: updateWarning() -// Desc: +// Desc: //----------------------------------------------------------------------------- inline void PerfectAI::ThreadVars::updateWarning(unsigned int firstStone, unsigned int secondStone) { // set warnings - if (firstStone < field->size) this->setWarning(firstStone, field->neighbour[firstStone][0][0], field->neighbour[firstStone][0][1]); - if (firstStone < field->size) this->setWarning(firstStone, field->neighbour[firstStone][1][0], field->neighbour[firstStone][1][1]); + if (firstStone < field->size) + this->setWarning(firstStone, field->neighbour[firstStone][0][0], field->neighbour[firstStone][0][1]); + if (firstStone < field->size) + this->setWarning(firstStone, field->neighbour[firstStone][1][0], field->neighbour[firstStone][1][1]); - if (secondStone < field->size) this->setWarning(secondStone, field->neighbour[secondStone][0][0], field->neighbour[secondStone][0][1]); - if (secondStone < field->size) this->setWarning(secondStone, field->neighbour[secondStone][1][0], field->neighbour[secondStone][1][1]); + if (secondStone < field->size) + this->setWarning(secondStone, field->neighbour[secondStone][0][0], field->neighbour[secondStone][0][1]); + if (secondStone < field->size) + this->setWarning(secondStone, field->neighbour[secondStone][1][0], field->neighbour[secondStone][1][1]); // no stone must be removed if each belongs to a mill - unsigned int i; - bool atLeastOneStoneRemoveAble = false; - if (field->stoneMustBeRemoved) for (i = 0; i < field->size; i++) if (field->stonePartOfMill[i] == 0 && field->board[i] == field->oppPlayer->id) { - atLeastOneStoneRemoveAble = true; break; - } - if (!atLeastOneStoneRemoveAble) field->stoneMustBeRemoved = 0; + unsigned int i; + bool atLeastOneStoneRemoveAble = false; + if (field->stoneMustBeRemoved) + for (i = 0; i < field->size; i++) + if (field->stonePartOfMill[i] == 0 && field->board[i] == field->oppPlayer->id) + { + atLeastOneStoneRemoveAble = true; + break; + } + if (!atLeastOneStoneRemoveAble) + field->stoneMustBeRemoved = 0; } //----------------------------------------------------------------------------- // Name: updatePossibleMoves() -// Desc: +// Desc: //----------------------------------------------------------------------------- inline void PerfectAI::ThreadVars::updatePossibleMoves(unsigned int stone, Player *stoneOwner, bool stoneRemoved, unsigned int ignoreStone) { // locals - unsigned int neighbor, direction; + unsigned int neighbor, direction; // look into every direction - for (direction = 0; direction < 4; direction++) { + for (direction = 0; direction < 4; direction++) + { neighbor = field->connectedSquare[stone][direction]; // neighbor must exist - if (neighbor < field->size) { + if (neighbor < field->size) + { // relevant when moving from one square to another connected square - if (ignoreStone == neighbor) continue; + if (ignoreStone == neighbor) + continue; // if there is no neighbour stone than it only affects the actual stone - if (field->board[neighbor] == field->squareIsFree) { + if (field->board[neighbor] == field->squareIsFree) + { - if (stoneRemoved) stoneOwner->numPossibleMoves--; - else stoneOwner->numPossibleMoves++; + if (stoneRemoved) + stoneOwner->numPossibleMoves--; + else + stoneOwner->numPossibleMoves++; // if there is a neighbour stone than it effects only this one - } else if (field->board[neighbor] == field->curPlayer->id) { + } + else if (field->board[neighbor] == field->curPlayer->id) + { - if (stoneRemoved) field->curPlayer->numPossibleMoves++; - else field->curPlayer->numPossibleMoves--; + if (stoneRemoved) + field->curPlayer->numPossibleMoves++; + else + field->curPlayer->numPossibleMoves--; + } + else + { - } else { - - if (stoneRemoved) field->oppPlayer->numPossibleMoves++; - else field->oppPlayer->numPossibleMoves--; + if (stoneRemoved) + field->oppPlayer->numPossibleMoves++; + else + field->oppPlayer->numPossibleMoves--; } } } // only 3 stones resting - if (field->curPlayer->numStones <= 3 && !field->settingPhase) field->curPlayer->numPossibleMoves = field->curPlayer->numStones * (field->size - field->curPlayer->numStones - field->oppPlayer->numStones); - if (field->oppPlayer->numStones <= 3 && !field->settingPhase) field->oppPlayer->numPossibleMoves = field->oppPlayer->numStones * (field->size - field->curPlayer->numStones - field->oppPlayer->numStones); + if (field->curPlayer->numStones <= 3 && !field->settingPhase) + field->curPlayer->numPossibleMoves = field->curPlayer->numStones * (field->size - field->curPlayer->numStones - field->oppPlayer->numStones); + if (field->oppPlayer->numStones <= 3 && !field->settingPhase) + field->oppPlayer->numPossibleMoves = field->oppPlayer->numStones * (field->size - field->curPlayer->numStones - field->oppPlayer->numStones); } //----------------------------------------------------------------------------- // Name: setStone() -// Desc: +// Desc: //----------------------------------------------------------------------------- -inline void PerfectAI::ThreadVars::setStone(unsigned int to, Backup *backup) +inline void PerfectAI::ThreadVars::setStone(unsigned int to, Backup *backup) { // backup backup->from = field->size; @@ -1139,7 +1282,8 @@ inline void PerfectAI::ThreadVars::setStone(unsigned int to, Backup *backup) field->stonesSet++; // setting phase finished ? - if (field->stonesSet == 18) field->settingPhase = false; + if (field->stonesSet == 18) + field->settingPhase = false; // update possible moves updatePossibleMoves(to, field->curPlayer, false, field->size); @@ -1150,9 +1294,9 @@ inline void PerfectAI::ThreadVars::setStone(unsigned int to, Backup *backup) //----------------------------------------------------------------------------- // Name: normalMove() -// Desc: +// Desc: //----------------------------------------------------------------------------- -inline void PerfectAI::ThreadVars::normalMove(unsigned int from, unsigned int to, Backup *backup) +inline void PerfectAI::ThreadVars::normalMove(unsigned int from, unsigned int to, Backup *backup) { // backup backup->from = from; @@ -1174,7 +1318,7 @@ inline void PerfectAI::ThreadVars::normalMove(unsigned int from, unsigned int to //----------------------------------------------------------------------------- // Name: removeStone() -// Desc: +// Desc: //----------------------------------------------------------------------------- inline void PerfectAI::ThreadVars::removeStone(unsigned int from, Backup *backup) { @@ -1197,12 +1341,13 @@ inline void PerfectAI::ThreadVars::removeStone(unsigned int from, Backup *backup updateWarning(from, field->size); // end of game ? - if ((field->oppPlayer->numStones < 3) && (!field->settingPhase)) gameHasFinished = true; + if ((field->oppPlayer->numStones < 3) && (!field->settingPhase)) + gameHasFinished = true; } //----------------------------------------------------------------------------- // Name: move() -// Desc: +// Desc: //----------------------------------------------------------------------------- void PerfectAI::move(unsigned int threadNo, unsigned int idPossibility, bool opponentsMove, void **pBackup, void *pPossibilities) { @@ -1211,7 +1356,7 @@ void PerfectAI::move(unsigned int threadNo, unsigned int idPossibility, bool opp Backup *oldState = &tv->oldStates[tv->curSearchDepth]; Possibility *tmpPossibility = (Possibility *)pPossibilities; Player *tmpPlayer; - unsigned int i; + unsigned int i; // calculate place of stone *pBackup = (void *)oldState; @@ -1232,38 +1377,52 @@ void PerfectAI::move(unsigned int threadNo, unsigned int idPossibility, bool opp tv->curSearchDepth++; // very expensive - for (i = 0; i < tv->field->size; i++) { + for (i = 0; i < tv->field->size; i++) + { oldState->stonePartOfMill[i] = tv->field->stonePartOfMill[i]; } // move - if (tv->field->stoneMustBeRemoved) { + if (tv->field->stoneMustBeRemoved) + { tv->removeStone(idPossibility, oldState); - } else if (tv->field->settingPhase) { + } + else if (tv->field->settingPhase) + { tv->setStone(idPossibility, oldState); - } else { + } + else + { tv->normalMove(tmpPossibility->from[idPossibility], tmpPossibility->to[idPossibility], oldState); } // when opponent is unable to move than current player has won - if ((!tv->field->oppPlayer->numPossibleMoves) && (!tv->field->settingPhase) && (!tv->field->stoneMustBeRemoved) && (tv->field->oppPlayer->numStones > 3)) tv->gameHasFinished = true; + if ((!tv->field->oppPlayer->numPossibleMoves) && (!tv->field->settingPhase) && (!tv->field->stoneMustBeRemoved) && (tv->field->oppPlayer->numStones > 3)) + tv->gameHasFinished = true; // when game has finished - perfect for the current player - if (tv->gameHasFinished && !opponentsMove) tv->shortValue = SKV_VALUE_GAME_WON; - if (tv->gameHasFinished && opponentsMove) tv->shortValue = SKV_VALUE_GAME_LOST; + if (tv->gameHasFinished && !opponentsMove) + tv->shortValue = SKV_VALUE_GAME_WON; + if (tv->gameHasFinished && opponentsMove) + tv->shortValue = SKV_VALUE_GAME_LOST; tv->floatValue = tv->shortValue; // calc value - if (!opponentsMove) tv->floatValue = (float)tv->field->oppPlayer->numStonesMissing - tv->field->curPlayer->numStonesMissing + tv->field->stoneMustBeRemoved + tv->field->curPlayer->numPossibleMoves * 0.1f - tv->field->oppPlayer->numPossibleMoves * 0.1f; - else tv->floatValue = (float)tv->field->curPlayer->numStonesMissing - tv->field->oppPlayer->numStonesMissing - tv->field->stoneMustBeRemoved + tv->field->oppPlayer->numPossibleMoves * 0.1f - tv->field->curPlayer->numPossibleMoves * 0.1f; + if (!opponentsMove) + tv->floatValue = (float)tv->field->oppPlayer->numStonesMissing - tv->field->curPlayer->numStonesMissing + tv->field->stoneMustBeRemoved + tv->field->curPlayer->numPossibleMoves * 0.1f - tv->field->oppPlayer->numPossibleMoves * 0.1f; + else + tv->floatValue = (float)tv->field->curPlayer->numStonesMissing - tv->field->oppPlayer->numStonesMissing - tv->field->stoneMustBeRemoved + tv->field->oppPlayer->numPossibleMoves * 0.1f - tv->field->curPlayer->numPossibleMoves * 0.1f; // when game has finished - perfect for the current player - if (tv->gameHasFinished && !opponentsMove) tv->floatValue = VALUE_GAME_WON - tv->curSearchDepth; - if (tv->gameHasFinished && opponentsMove) tv->floatValue = VALUE_GAME_LOST + tv->curSearchDepth; + if (tv->gameHasFinished && !opponentsMove) + tv->floatValue = VALUE_GAME_WON - tv->curSearchDepth; + if (tv->gameHasFinished && opponentsMove) + tv->floatValue = VALUE_GAME_LOST + tv->curSearchDepth; // set next player - if (!tv->field->stoneMustBeRemoved) { + if (!tv->field->stoneMustBeRemoved) + { tmpPlayer = tv->field->curPlayer; tv->field->curPlayer = tv->field->oppPlayer; tv->field->oppPlayer = tmpPlayer; @@ -1272,18 +1431,21 @@ void PerfectAI::move(unsigned int threadNo, unsigned int idPossibility, bool opp //----------------------------------------------------------------------------- // Name: storeValueOfMove() -// Desc: +// Desc: //----------------------------------------------------------------------------- void PerfectAI::storeValueOfMove(unsigned int threadNo, unsigned int idPossibility, void *pPossibilities, unsigned char value, unsigned int *freqValuesSubMoves, PlyInfoVarType plyInfo) { // locals ThreadVars *tv = &threadVars[threadNo]; - unsigned int index; + unsigned int index; Possibility *tmpPossibility = (Possibility *)pPossibilities; - if (tv->field->stoneMustBeRemoved) index = idPossibility; - else if (tv->field->settingPhase) index = idPossibility; - else index = tmpPossibility->from[idPossibility] * fieldStruct::size + tmpPossibility->to[idPossibility]; + if (tv->field->stoneMustBeRemoved) + index = idPossibility; + else if (tv->field->settingPhase) + index = idPossibility; + else + index = tmpPossibility->from[idPossibility] * fieldStruct::size + tmpPossibility->to[idPossibility]; plyInfoForOutput[index] = plyInfo; valueOfMove[index] = value; @@ -1295,65 +1457,88 @@ void PerfectAI::storeValueOfMove(unsigned int threadNo, unsigned int idPossibili //----------------------------------------------------------------------------- // Name: getValueOfMoves() -// Desc: +// Desc: //----------------------------------------------------------------------------- void PerfectAI::getValueOfMoves(unsigned char *moveValue, unsigned int *freqValuesSubMoves, PlyInfoVarType *plyInfo, unsigned int *moveQuality, unsigned char &knotValue, PlyInfoVarType &bestAmountOfPlies) { // locals - unsigned int moveQualities[fieldStruct::size * fieldStruct::size]; // 0 is bad, 1 is good - unsigned int i, j; + unsigned int moveQualities[fieldStruct::size * fieldStruct::size]; // 0 is bad, 1 is good + unsigned int i, j; // set an invalid default value knotValue = SKV_NUM_VALUES; // calc knotValue - for (i = 0; i < fieldStruct::size; i++) { - for (j = 0; j < fieldStruct::size; j++) { - if (valueOfMove[i * fieldStruct::size + j] == SKV_VALUE_GAME_WON) { + for (i = 0; i < fieldStruct::size; i++) + { + for (j = 0; j < fieldStruct::size; j++) + { + if (valueOfMove[i * fieldStruct::size + j] == SKV_VALUE_GAME_WON) + { knotValue = SKV_VALUE_GAME_WON; i = fieldStruct::size; j = fieldStruct::size; - } else if (valueOfMove[i * fieldStruct::size + j] == SKV_VALUE_GAME_DRAWN) { + } + else if (valueOfMove[i * fieldStruct::size + j] == SKV_VALUE_GAME_DRAWN) + { knotValue = SKV_VALUE_GAME_DRAWN; - } else if (valueOfMove[i * fieldStruct::size + j] == SKV_VALUE_GAME_LOST && knotValue != SKV_VALUE_GAME_DRAWN) { + } + else if (valueOfMove[i * fieldStruct::size + j] == SKV_VALUE_GAME_LOST && knotValue != SKV_VALUE_GAME_DRAWN) + { knotValue = SKV_VALUE_GAME_LOST; } } } - // calc move bestAmountOfPlies - if (knotValue == SKV_VALUE_GAME_WON) { + // calc move bestAmountOfPlies + if (knotValue == SKV_VALUE_GAME_WON) + { bestAmountOfPlies = PLYINFO_VALUE_INVALID; - for (i = 0; i < fieldStruct::size; i++) { - for (j = 0; j < fieldStruct::size; j++) { - if (valueOfMove[i * fieldStruct::size + j] == SKV_VALUE_GAME_WON) { - if (bestAmountOfPlies >= plyInfoForOutput[i * fieldStruct::size + j]) { + for (i = 0; i < fieldStruct::size; i++) + { + for (j = 0; j < fieldStruct::size; j++) + { + if (valueOfMove[i * fieldStruct::size + j] == SKV_VALUE_GAME_WON) + { + if (bestAmountOfPlies >= plyInfoForOutput[i * fieldStruct::size + j]) + { bestAmountOfPlies = plyInfoForOutput[i * fieldStruct::size + j]; } } } } - - } else if (knotValue == SKV_VALUE_GAME_LOST) { + } + else if (knotValue == SKV_VALUE_GAME_LOST) + { bestAmountOfPlies = 0; - for (i = 0; i < fieldStruct::size; i++) { - for (j = 0; j < fieldStruct::size; j++) { - if (valueOfMove[i * fieldStruct::size + j] == SKV_VALUE_GAME_LOST) { - if (bestAmountOfPlies <= plyInfoForOutput[i * fieldStruct::size + j]) { + for (i = 0; i < fieldStruct::size; i++) + { + for (j = 0; j < fieldStruct::size; j++) + { + if (valueOfMove[i * fieldStruct::size + j] == SKV_VALUE_GAME_LOST) + { + if (bestAmountOfPlies <= plyInfoForOutput[i * fieldStruct::size + j]) + { bestAmountOfPlies = plyInfoForOutput[i * fieldStruct::size + j]; } } } } - } else if (knotValue == SKV_VALUE_GAME_DRAWN) { + } + else if (knotValue == SKV_VALUE_GAME_DRAWN) + { bestAmountOfPlies = 0; - for (i = 0; i < fieldStruct::size; i++) { - for (j = 0; j < fieldStruct::size; j++) { - if (valueOfMove[i * fieldStruct::size + j] == SKV_VALUE_GAME_DRAWN) { - if (bestAmountOfPlies <= incidencesValuesSubMoves[i * fieldStruct::size + j][SKV_VALUE_GAME_WON]) { + for (i = 0; i < fieldStruct::size; i++) + { + for (j = 0; j < fieldStruct::size; j++) + { + if (valueOfMove[i * fieldStruct::size + j] == SKV_VALUE_GAME_DRAWN) + { + if (bestAmountOfPlies <= incidencesValuesSubMoves[i * fieldStruct::size + j][SKV_VALUE_GAME_WON]) + { bestAmountOfPlies = incidencesValuesSubMoves[i * fieldStruct::size + j][SKV_VALUE_GAME_WON]; } } @@ -1362,12 +1547,16 @@ void PerfectAI::getValueOfMoves(unsigned char *moveValue, unsigned int *freqValu } // zero move qualities - for (i = 0; i < fieldStruct::size; i++) { - for (j = 0; j < fieldStruct::size; j++) { - if ((valueOfMove[i * fieldStruct::size + j] == knotValue && bestAmountOfPlies == plyInfoForOutput[i * fieldStruct::size + j] && knotValue != SKV_VALUE_GAME_DRAWN) - || (valueOfMove[i * fieldStruct::size + j] == knotValue && bestAmountOfPlies == incidencesValuesSubMoves[i * fieldStruct::size + j][SKV_VALUE_GAME_WON] && knotValue == SKV_VALUE_GAME_DRAWN)) { + for (i = 0; i < fieldStruct::size; i++) + { + for (j = 0; j < fieldStruct::size; j++) + { + if ((valueOfMove[i * fieldStruct::size + j] == knotValue && bestAmountOfPlies == plyInfoForOutput[i * fieldStruct::size + j] && knotValue != SKV_VALUE_GAME_DRAWN) || (valueOfMove[i * fieldStruct::size + j] == knotValue && bestAmountOfPlies == incidencesValuesSubMoves[i * fieldStruct::size + j][SKV_VALUE_GAME_WON] && knotValue == SKV_VALUE_GAME_DRAWN)) + { moveQualities[i * fieldStruct::size + j] = 1; - } else { + } + else + { moveQualities[i * fieldStruct::size + j] = 0; } } @@ -1382,7 +1571,7 @@ void PerfectAI::getValueOfMoves(unsigned char *moveValue, unsigned int *freqValu //----------------------------------------------------------------------------- // Name: printMoveInformation() -// Desc: +// Desc: //----------------------------------------------------------------------------- void PerfectAI::printMoveInformation(unsigned int threadNo, unsigned int idPossibility, void *pPossibilities) { @@ -1391,9 +1580,12 @@ void PerfectAI::printMoveInformation(unsigned int threadNo, unsigned int idPossi Possibility *tmpPossibility = (Possibility *)pPossibilities; // move - if (tv->field->stoneMustBeRemoved) cout << "remove stone from " << (char)(idPossibility + 97); - else if (tv->field->settingPhase) cout << "set stone to " << (char)(idPossibility + 97); - else cout << "move from " << (char)(tmpPossibility->from[idPossibility] + 97) << " to " << (char)(tmpPossibility->to[idPossibility] + 97); + if (tv->field->stoneMustBeRemoved) + cout << "remove stone from " << (char)(idPossibility + 97); + else if (tv->field->settingPhase) + cout << "set stone to " << (char)(idPossibility + 97); + else + cout << "move from " << (char)(tmpPossibility->from[idPossibility] + 97) << " to " << (char)(tmpPossibility->to[idPossibility] + 97); } //----------------------------------------------------------------------------- @@ -1430,9 +1622,8 @@ unsigned int PerfectAI::getNumberOfKnotsInLayer(unsigned int layerNum) numberOfKnots *= MAX_NUM_STONES_REMOVED_MINUS_1; // return zero if layer is not reachable - if (((layer[layerNum].numBlackStones < 2 || layer[layerNum].numWhiteStones < 2) && layerNum < 100) // moving phase - || (layer[layerNum].numBlackStones == 2 && layer[layerNum].numWhiteStones == 2 && layerNum < 100) - || (layerNum == 100)) + if (((layer[layerNum].numBlackStones < 2 || layer[layerNum].numWhiteStones < 2) && layerNum < 100) // moving phase + || (layer[layerNum].numBlackStones == 2 && layer[layerNum].numWhiteStones == 2 && layerNum < 100) || (layerNum == 100)) return 0; // another way @@ -1451,16 +1642,20 @@ long long PerfectAI::mOverN_Function(unsigned int m, unsigned int n) unsigned int i; // invalid parameters ? - if (n > m) return 0; + if (n > m) + return 0; // flip, since then the result value won't get so high - if (n > m / 2) n = m - n; + if (n > m / 2) + n = m - n; // calc number of possibilities one can put n different stones in m holes - for (i = m - n + 1; i <= m; i++) result *= i; + for (i = m - n + 1; i <= m; i++) + result *= i; // calc number of possibilities one can sort n different stones - for (i = 1; i <= n; i++) fakN *= i; + for (i = 1; i <= n; i++) + fakN *= i; // divide result /= fakN; @@ -1474,14 +1669,15 @@ long long PerfectAI::mOverN_Function(unsigned int m, unsigned int n) //----------------------------------------------------------------------------- void PerfectAI::applySymmetrieOperationOnField(unsigned char symmetryOperationNumber, unsigned int *sourceField, unsigned int *destField) { - for (unsigned int i = 0; i < fieldStruct::size; i++) { + for (unsigned int i = 0; i < fieldStruct::size; i++) + { destField[i] = sourceField[symmetryOperationTable[symmetryOperationNumber][i]]; } } //----------------------------------------------------------------------------- // Name: getLayerNumber() -// Desc: +// Desc: //----------------------------------------------------------------------------- unsigned int PerfectAI::getLayerNumber(unsigned int threadNo) { @@ -1494,7 +1690,7 @@ unsigned int PerfectAI::getLayerNumber(unsigned int threadNo) //----------------------------------------------------------------------------- // Name: getLayerAndStateNumber() -// Desc: +// Desc: //----------------------------------------------------------------------------- unsigned int PerfectAI::getLayerAndStateNumber(unsigned int threadNo, unsigned int &layerNum, unsigned int &stateNumber) { @@ -1522,56 +1718,41 @@ unsigned int PerfectAI::ThreadVars::getLayerAndStateNumber(unsigned int &layerNu layerNum = parent->layerIndex[phaseIndex][numWhiteStones][numBlackStones]; // make white and black fields - for (i = 0; i < fieldStruct::size; i++) { - if (field->board[i] == fieldStruct::squareIsFree) { + for (i = 0; i < fieldStruct::size; i++) + { + if (field->board[i] == fieldStruct::squareIsFree) + { myField[i] = FREE_SQUARE; - } else if (field->board[i] == field->curPlayer->id) { + } + else if (field->board[i] == field->curPlayer->id) + { myField[i] = WHITE_STONE; - if (fieldPosIsOfGroup[i] == GROUP_C) wCD++; - if (fieldPosIsOfGroup[i] == GROUP_D) wCD++; - } else { + if (fieldPosIsOfGroup[i] == GROUP_C) + wCD++; + if (fieldPosIsOfGroup[i] == GROUP_D) + wCD++; + } + else + { myField[i] = BLACK_STONE; - if (fieldPosIsOfGroup[i] == GROUP_C) bCD++; - if (fieldPosIsOfGroup[i] == GROUP_D) bCD++; + if (fieldPosIsOfGroup[i] == GROUP_C) + bCD++; + if (fieldPosIsOfGroup[i] == GROUP_D) + bCD++; } } // calc stateCD - stateCD = myField[squareIndexGroupC[0]] * parent->powerOfThree[15] - + myField[squareIndexGroupC[1]] * parent->powerOfThree[14] - + myField[squareIndexGroupC[2]] * parent->powerOfThree[13] - + myField[squareIndexGroupC[3]] * parent->powerOfThree[12] - + myField[squareIndexGroupC[4]] * parent->powerOfThree[11] - + myField[squareIndexGroupC[5]] * parent->powerOfThree[10] - + myField[squareIndexGroupC[6]] * parent->powerOfThree[9] - + myField[squareIndexGroupC[7]] * parent->powerOfThree[8] - + myField[squareIndexGroupD[0]] * parent->powerOfThree[7] - + myField[squareIndexGroupD[1]] * parent->powerOfThree[6] - + myField[squareIndexGroupD[2]] * parent->powerOfThree[5] - + myField[squareIndexGroupD[3]] * parent->powerOfThree[4] - + myField[squareIndexGroupD[4]] * parent->powerOfThree[3] - + myField[squareIndexGroupD[5]] * parent->powerOfThree[2] - + myField[squareIndexGroupD[6]] * parent->powerOfThree[1] - + myField[squareIndexGroupD[7]] * parent->powerOfThree[0]; + stateCD = myField[squareIndexGroupC[0]] * parent->powerOfThree[15] + myField[squareIndexGroupC[1]] * parent->powerOfThree[14] + myField[squareIndexGroupC[2]] * parent->powerOfThree[13] + myField[squareIndexGroupC[3]] * parent->powerOfThree[12] + myField[squareIndexGroupC[4]] * parent->powerOfThree[11] + myField[squareIndexGroupC[5]] * parent->powerOfThree[10] + myField[squareIndexGroupC[6]] * parent->powerOfThree[9] + myField[squareIndexGroupC[7]] * parent->powerOfThree[8] + myField[squareIndexGroupD[0]] * parent->powerOfThree[7] + myField[squareIndexGroupD[1]] * parent->powerOfThree[6] + myField[squareIndexGroupD[2]] * parent->powerOfThree[5] + myField[squareIndexGroupD[3]] * parent->powerOfThree[4] + myField[squareIndexGroupD[4]] * parent->powerOfThree[3] + myField[squareIndexGroupD[5]] * parent->powerOfThree[2] + myField[squareIndexGroupD[6]] * parent->powerOfThree[1] + myField[squareIndexGroupD[7]] * parent->powerOfThree[0]; // apply symmetry operation on group A&B parent->applySymmetrieOperationOnField(parent->symmetryOperationCD[stateCD], myField, symField); // calc stateAB - stateAB = symField[squareIndexGroupA[0]] * parent->powerOfThree[7] - + symField[squareIndexGroupA[1]] * parent->powerOfThree[6] - + symField[squareIndexGroupA[2]] * parent->powerOfThree[5] - + symField[squareIndexGroupA[3]] * parent->powerOfThree[4] - + symField[squareIndexGroupB[0]] * parent->powerOfThree[3] - + symField[squareIndexGroupB[1]] * parent->powerOfThree[2] - + symField[squareIndexGroupB[2]] * parent->powerOfThree[1] - + symField[squareIndexGroupB[3]] * parent->powerOfThree[0]; + stateAB = symField[squareIndexGroupA[0]] * parent->powerOfThree[7] + symField[squareIndexGroupA[1]] * parent->powerOfThree[6] + symField[squareIndexGroupA[2]] * parent->powerOfThree[5] + symField[squareIndexGroupA[3]] * parent->powerOfThree[4] + symField[squareIndexGroupB[0]] * parent->powerOfThree[3] + symField[squareIndexGroupB[1]] * parent->powerOfThree[2] + symField[squareIndexGroupB[2]] * parent->powerOfThree[1] + symField[squareIndexGroupB[3]] * parent->powerOfThree[0]; // calc index - stateNumber = parent->layer[layerNum].subLayer[parent->layer[layerNum].subLayerIndexCD[wCD][bCD]].minIndex * MAX_NUM_STONES_REMOVED_MINUS_1 - + parent->indexAB[stateAB] * parent->anzahlStellungenCD[wCD][bCD] * MAX_NUM_STONES_REMOVED_MINUS_1 - + parent->indexCD[stateCD] * MAX_NUM_STONES_REMOVED_MINUS_1 - + field->stoneMustBeRemoved; + stateNumber = parent->layer[layerNum].subLayer[parent->layer[layerNum].subLayerIndexCD[wCD][bCD]].minIndex * MAX_NUM_STONES_REMOVED_MINUS_1 + parent->indexAB[stateAB] * parent->anzahlStellungenCD[wCD][bCD] * MAX_NUM_STONES_REMOVED_MINUS_1 + parent->indexCD[stateCD] * MAX_NUM_STONES_REMOVED_MINUS_1 + field->stoneMustBeRemoved; return parent->symmetryOperationCD[stateCD]; } @@ -1584,8 +1765,10 @@ unsigned int PerfectAI::ThreadVars::getLayerAndStateNumber(unsigned int &layerNu bool PerfectAI::setSituation(unsigned int threadNo, unsigned int layerNum, unsigned int stateNumber) { // parameters ok ? - if (getNumberOfLayers() <= layerNum) return false; - if (getNumberOfKnotsInLayer(layerNum) <= stateNumber) return false; + if (getNumberOfLayers() <= layerNum) + return false; + if (getNumberOfKnotsInLayer(layerNum) <= stateNumber) + return false; // locals ThreadVars *tv = &threadVars[threadNo]; @@ -1601,12 +1784,13 @@ bool PerfectAI::setSituation(unsigned int threadNo, unsigned int layerNum, unsig unsigned int numberOfMillsOpponentPlayer = 0; unsigned int wCD, bCD, wAB, bAB; unsigned int i; - bool aStoneCanBeRemovedFromCurPlayer; + bool aStoneCanBeRemovedFromCurPlayer; // get wCD, bCD, wAB, bAB - for (i = 0; i <= layer[layerNum].numSubLayers; i++) { - if (layer[layerNum].subLayer[i].minIndex <= stateNumber / MAX_NUM_STONES_REMOVED_MINUS_1 - && layer[layerNum].subLayer[i].maxIndex >= stateNumber / MAX_NUM_STONES_REMOVED_MINUS_1) { + for (i = 0; i <= layer[layerNum].numSubLayers; i++) + { + if (layer[layerNum].subLayer[i].minIndex <= stateNumber / MAX_NUM_STONES_REMOVED_MINUS_1 && layer[layerNum].subLayer[i].maxIndex >= stateNumber / MAX_NUM_STONES_REMOVED_MINUS_1) + { wCD = layer[layerNum].subLayer[i].numWhiteStonesGroupCD; bCD = layer[layerNum].subLayer[i].numBlackStonesGroupCD; wAB = layer[layerNum].subLayer[i].numWhiteStonesGroupAB; @@ -1666,10 +1850,14 @@ bool PerfectAI::setSituation(unsigned int threadNo, unsigned int layerNum, unsig applySymmetrieOperationOnField(reverseSymOperation[symmetryOperationCD[stateCD]], myField, symField); // translate symField[] to board->board[] - for (i = 0; i < fieldStruct::size; i++) { - if (symField[i] == FREE_SQUARE) tv->field->board[i] = fieldStruct::squareIsFree; - else if (symField[i] == WHITE_STONE) tv->field->board[i] = tv->field->curPlayer->id; - else tv->field->board[i] = tv->field->oppPlayer->id; + for (i = 0; i < fieldStruct::size; i++) + { + if (symField[i] == FREE_SQUARE) + tv->field->board[i] = fieldStruct::squareIsFree; + else if (symField[i] == WHITE_STONE) + tv->field->board[i] = tv->field->curPlayer->id; + else + tv->field->board[i] = tv->field->oppPlayer->id; } // calc possible moves @@ -1677,56 +1865,73 @@ bool PerfectAI::setSituation(unsigned int threadNo, unsigned int layerNum, unsig tv->calcPossibleMoves(tv->field->oppPlayer); // zero - for (i = 0; i < fieldStruct::size; i++) { + for (i = 0; i < fieldStruct::size; i++) + { tv->field->stonePartOfMill[i] = 0; } // go in every direction - for (i = 0; i < fieldStruct::size; i++) { + for (i = 0; i < fieldStruct::size; i++) + { tv->setWarningAndMill(i, tv->field->neighbour[i][0][0], tv->field->neighbour[i][0][1]); tv->setWarningAndMill(i, tv->field->neighbour[i][1][0], tv->field->neighbour[i][1][1]); } // since every mill was detected 3 times - for (i = 0; i < fieldStruct::size; i++) tv->field->stonePartOfMill[i] /= 3; + for (i = 0; i < fieldStruct::size; i++) + tv->field->stonePartOfMill[i] /= 3; // count completed mills - for (i = 0; i < fieldStruct::size; i++) { - if (tv->field->board[i] == tv->field->curPlayer->id) numberOfMillsCurrentPlayer += tv->field->stonePartOfMill[i]; - else numberOfMillsOpponentPlayer += tv->field->stonePartOfMill[i]; + for (i = 0; i < fieldStruct::size; i++) + { + if (tv->field->board[i] == tv->field->curPlayer->id) + numberOfMillsCurrentPlayer += tv->field->stonePartOfMill[i]; + else + numberOfMillsOpponentPlayer += tv->field->stonePartOfMill[i]; } numberOfMillsCurrentPlayer /= 3; numberOfMillsOpponentPlayer /= 3; // stonesSet & numStonesMissing - if (tv->field->settingPhase) { + if (tv->field->settingPhase) + { // BUG: ... This calculation is not correct! It is possible that some mills did not cause a stone removal. tv->field->curPlayer->numStonesMissing = numberOfMillsOpponentPlayer; tv->field->oppPlayer->numStonesMissing = numberOfMillsCurrentPlayer - tv->field->stoneMustBeRemoved; tv->field->stonesSet = tv->field->curPlayer->numStones + tv->field->oppPlayer->numStones + tv->field->curPlayer->numStonesMissing + tv->field->oppPlayer->numStonesMissing; - } else { + } + else + { tv->field->stonesSet = 18; tv->field->curPlayer->numStonesMissing = 9 - tv->field->curPlayer->numStones; tv->field->oppPlayer->numStonesMissing = 9 - tv->field->oppPlayer->numStones; } // when opponent is unable to move than current player has won - if ((!tv->field->curPlayer->numPossibleMoves) && (!tv->field->settingPhase) && (!tv->field->stoneMustBeRemoved) && (tv->field->curPlayer->numStones > 3)) { - tv->gameHasFinished = true; tv->shortValue = SKV_VALUE_GAME_LOST; + if ((!tv->field->curPlayer->numPossibleMoves) && (!tv->field->settingPhase) && (!tv->field->stoneMustBeRemoved) && (tv->field->curPlayer->numStones > 3)) + { + tv->gameHasFinished = true; + tv->shortValue = SKV_VALUE_GAME_LOST; } - if ((tv->field->curPlayer->numStones < 3) && (!tv->field->settingPhase)) { - tv->gameHasFinished = true; tv->shortValue = SKV_VALUE_GAME_LOST; + if ((tv->field->curPlayer->numStones < 3) && (!tv->field->settingPhase)) + { + tv->gameHasFinished = true; + tv->shortValue = SKV_VALUE_GAME_LOST; } - if ((tv->field->oppPlayer->numStones < 3) && (!tv->field->settingPhase)) { - tv->gameHasFinished = true; tv->shortValue = SKV_VALUE_GAME_WON; + if ((tv->field->oppPlayer->numStones < 3) && (!tv->field->settingPhase)) + { + tv->gameHasFinished = true; + tv->shortValue = SKV_VALUE_GAME_WON; } tv->floatValue = tv->shortValue; // precalc aStoneCanBeRemovedFromCurPlayer - for (aStoneCanBeRemovedFromCurPlayer = false, i = 0; i < tv->field->size; i++) { - if (tv->field->stonePartOfMill[i] == 0 && tv->field->board[i] == tv->field->curPlayer->id) { + for (aStoneCanBeRemovedFromCurPlayer = false, i = 0; i < tv->field->size; i++) + { + if (tv->field->stonePartOfMill[i] == 0 && tv->field->board[i] == tv->field->curPlayer->id) + { aStoneCanBeRemovedFromCurPlayer = true; break; } @@ -1738,30 +1943,38 @@ bool PerfectAI::setSituation(unsigned int threadNo, unsigned int layerNum, unsig //----------------------------------------------------------------------------- // Name: calcPossibleMoves() -// Desc: +// Desc: //----------------------------------------------------------------------------- void PerfectAI::ThreadVars::calcPossibleMoves(Player *player) { // locals unsigned int i, j, k, movingDirection; - for (player->numPossibleMoves = 0, i = 0; i < fieldStruct::size; i++) { - for (j = 0; j < fieldStruct::size; j++) { + for (player->numPossibleMoves = 0, i = 0; i < fieldStruct::size; i++) + { + for (j = 0; j < fieldStruct::size; j++) + { // is stone from player ? - if (field->board[i] != player->id) continue; + if (field->board[i] != player->id) + continue; // is destination free ? - if (field->board[j] != field->squareIsFree) continue; + if (field->board[j] != field->squareIsFree) + continue; // when current player has only 3 stones he is allowed to spring his stone - if (player->numStones > 3 || field->settingPhase) { + if (player->numStones > 3 || field->settingPhase) + { // determine moving direction - for (k = 0, movingDirection = 4; k < 4; k++) if (field->connectedSquare[i][k] == j) movingDirection = k; + for (k = 0, movingDirection = 4; k < 4; k++) + if (field->connectedSquare[i][k] == j) + movingDirection = k; // are both squares connected ? - if (movingDirection == 4) continue; + if (movingDirection == 4) + continue; } // everything is ok @@ -1772,15 +1985,16 @@ void PerfectAI::ThreadVars::calcPossibleMoves(Player *player) //----------------------------------------------------------------------------- // Name: setWarningAndMill() -// Desc: +// Desc: //----------------------------------------------------------------------------- void PerfectAI::ThreadVars::setWarningAndMill(unsigned int stone, unsigned int firstNeighbour, unsigned int secondNeighbour) { // locals - int rowOwner = field->board[stone]; + int rowOwner = field->board[stone]; // mill closed ? - if (rowOwner != field->squareIsFree && field->board[firstNeighbour] == rowOwner && field->board[secondNeighbour] == rowOwner) { + if (rowOwner != field->squareIsFree && field->board[firstNeighbour] == rowOwner && field->board[secondNeighbour] == rowOwner) + { field->stonePartOfMill[stone]++; field->stonePartOfMill[firstNeighbour]++; @@ -1790,7 +2004,7 @@ void PerfectAI::ThreadVars::setWarningAndMill(unsigned int stone, unsigned int f //----------------------------------------------------------------------------- // Name: getOutputInformation() -// Desc: +// Desc: //----------------------------------------------------------------------------- string PerfectAI::getOutputInformation(unsigned int layerNum) { @@ -1801,16 +2015,16 @@ string PerfectAI::getOutputInformation(unsigned int layerNum) //----------------------------------------------------------------------------- // Name: printBoard() -// Desc: +// Desc: //----------------------------------------------------------------------------- void PerfectAI::printBoard(unsigned int threadNo, unsigned char value) { ThreadVars *tv = &threadVars[threadNo]; - char wonStr[] = "WON"; - char lostStr[] = "LOST"; - char drawStr[] = "DRAW"; - char invStr[] = "INVALID"; - char *table[4] = { invStr, lostStr, drawStr, wonStr }; + char wonStr[] = "WON"; + char lostStr[] = "LOST"; + char drawStr[] = "DRAW"; + char invStr[] = "INVALID"; + char *table[4] = {invStr, lostStr, drawStr, wonStr}; cout << "\nstate value : " << table[value]; cout << "\nstones set : " << tv->field->stonesSet << "\n"; @@ -1819,7 +2033,7 @@ void PerfectAI::printBoard(unsigned int threadNo, unsigned char value) //----------------------------------------------------------------------------- // Name: getField() -// Desc: +// Desc: //----------------------------------------------------------------------------- void PerfectAI::getField(unsigned int layerNum, unsigned int stateNumber, fieldStruct *field, bool *gameHasFinished) { @@ -1828,22 +2042,22 @@ void PerfectAI::getField(unsigned int layerNum, unsigned int stateNumber, fieldS // copy content of fieldStruct threadVars[0].field->copyBoard(field); - if (gameHasFinished != nullptr) *gameHasFinished = threadVars[0].gameHasFinished; + if (gameHasFinished != nullptr) + *gameHasFinished = threadVars[0].gameHasFinished; } - //----------------------------------------------------------------------------- // Name: getLayerAndStateNumber() -// Desc: +// Desc: //----------------------------------------------------------------------------- -void PerfectAI::getLayerAndStateNumber(unsigned int &layerNum, unsigned int &stateNumber/*, unsigned int& symmetryOperation*/) +void PerfectAI::getLayerAndStateNumber(unsigned int &layerNum, unsigned int &stateNumber /*, unsigned int& symmetryOperation*/) { - /*symmetryOperation = */threadVars[0].getLayerAndStateNumber(layerNum, stateNumber); + /*symmetryOperation = */ threadVars[0].getLayerAndStateNumber(layerNum, stateNumber); } //----------------------------------------------------------------------------- // Name: setOpponentLevel() -// Desc: +// Desc: //----------------------------------------------------------------------------- void PerfectAI::setOpponentLevel(unsigned int threadNo, bool isOpponentLevel) { @@ -1853,7 +2067,7 @@ void PerfectAI::setOpponentLevel(unsigned int threadNo, bool isOpponentLevel) //----------------------------------------------------------------------------- // Name: getOpponentLevel() -// Desc: +// Desc: //----------------------------------------------------------------------------- bool PerfectAI::getOpponentLevel(unsigned int threadNo) { @@ -1863,14 +2077,15 @@ bool PerfectAI::getOpponentLevel(unsigned int threadNo) //----------------------------------------------------------------------------- // Name: getPartnerLayer() -// Desc: +// Desc: //----------------------------------------------------------------------------- unsigned int PerfectAI::getPartnerLayer(unsigned int layerNum) { if (layerNum < 100) - for (int i = 0; i < 100; i++) { - if (layer[layerNum].numBlackStones == layer[i].numWhiteStones - && layer[layerNum].numWhiteStones == layer[i].numBlackStones) { + for (int i = 0; i < 100; i++) + { + if (layer[layerNum].numBlackStones == layer[i].numWhiteStones && layer[layerNum].numWhiteStones == layer[i].numBlackStones) + { return i; } } @@ -1879,7 +2094,7 @@ unsigned int PerfectAI::getPartnerLayer(unsigned int layerNum) //----------------------------------------------------------------------------- // Name: getSuccLayers() -// Desc: +// Desc: //----------------------------------------------------------------------------- void PerfectAI::getSuccLayers(unsigned int layerNum, unsigned int *amountOfSuccLayers, unsigned int *succLayers) { @@ -1889,9 +2104,10 @@ void PerfectAI::getSuccLayers(unsigned int layerNum, unsigned int *amountOfSuccL int diff = (layerNum >= 100) ? 1 : -1; // search layer with one white stone less - for (*amountOfSuccLayers = 0, i = 0 + shift; i < 100 + shift; i++) { - if (layer[i].numWhiteStones == layer[layerNum].numBlackStones + diff - && layer[i].numBlackStones == layer[layerNum].numWhiteStones) { + for (*amountOfSuccLayers = 0, i = 0 + shift; i < 100 + shift; i++) + { + if (layer[i].numWhiteStones == layer[layerNum].numBlackStones + diff && layer[i].numBlackStones == layer[layerNum].numWhiteStones) + { succLayers[*amountOfSuccLayers] = i; *amountOfSuccLayers = *amountOfSuccLayers + 1; break; @@ -1899,9 +2115,10 @@ void PerfectAI::getSuccLayers(unsigned int layerNum, unsigned int *amountOfSuccL } // search layer with one black stone less - for (i = 0 + shift; i < 100 + shift; i++) { - if (layer[i].numWhiteStones == layer[layerNum].numBlackStones - && layer[i].numBlackStones == layer[layerNum].numWhiteStones + diff) { + for (i = 0 + shift; i < 100 + shift; i++) + { + if (layer[i].numWhiteStones == layer[layerNum].numBlackStones && layer[i].numBlackStones == layer[layerNum].numWhiteStones + diff) + { succLayers[*amountOfSuccLayers] = i; *amountOfSuccLayers = *amountOfSuccLayers + 1; break; @@ -1911,13 +2128,13 @@ void PerfectAI::getSuccLayers(unsigned int layerNum, unsigned int *amountOfSuccL //----------------------------------------------------------------------------- // Name: getSymStateNumWithDoubles() -// Desc: +// Desc: //----------------------------------------------------------------------------- void PerfectAI::getSymStateNumWithDoubles(unsigned int threadNo, unsigned int *numSymmetricStates, unsigned int **symStateNumbers) { // locals ThreadVars *tv = &threadVars[threadNo]; - int originalField[fieldStruct::size]; + int originalField[fieldStruct::size]; unsigned int originalPartOfMill[fieldStruct::size]; unsigned int i, symmetryOperation; unsigned int layerNum, stateNum; @@ -1926,13 +2143,15 @@ void PerfectAI::getSymStateNumWithDoubles(unsigned int threadNo, unsigned int *n *symStateNumbers = symmetricStateNumberArray; // save current board - for (i = 0; i < fieldStruct::size; i++) { + for (i = 0; i < fieldStruct::size; i++) + { originalField[i] = tv->field->board[i]; originalPartOfMill[i] = tv->field->stonePartOfMill[i]; } // add all symmetric states - for (symmetryOperation = 0; symmetryOperation < NUM_SYM_OPERATIONS; symmetryOperation++) { + for (symmetryOperation = 0; symmetryOperation < NUM_SYM_OPERATIONS; symmetryOperation++) + { // appy symmetry operation applySymmetrieOperationOnField(symmetryOperation, (unsigned int *)originalField, (unsigned int *)tv->field->board); @@ -1944,7 +2163,8 @@ void PerfectAI::getSymStateNumWithDoubles(unsigned int threadNo, unsigned int *n } // restore original board - for (i = 0; i < fieldStruct::size; i++) { + for (i = 0; i < fieldStruct::size; i++) + { tv->field->board[i] = originalField[i]; tv->field->stonePartOfMill[i] = originalPartOfMill[i]; } @@ -1952,43 +2172,57 @@ void PerfectAI::getSymStateNumWithDoubles(unsigned int threadNo, unsigned int *n //----------------------------------------------------------------------------- // Name: fieldIntegrityOK() -// Desc: +// Desc: //----------------------------------------------------------------------------- bool PerfectAI::ThreadVars::fieldIntegrityOK(unsigned int numberOfMillsCurrentPlayer, unsigned int numberOfMillsOpponentPlayer, bool aStoneCanBeRemovedFromCurPlayer) { // locals - int i, j; + int i, j; bool noneFullFilled; // when stone is going to be removed than at least one opponent stone mustn't be part of a mill - if (numberOfMillsOpponentPlayer > 0 && field->stoneMustBeRemoved) { - for (i = 0; i < field->size; i++) if (field->stonePartOfMill[i] == 0 && field->oppPlayer->id == field->board[i]) break; - if (i == field->size) return false; + if (numberOfMillsOpponentPlayer > 0 && field->stoneMustBeRemoved) + { + for (i = 0; i < field->size; i++) + if (field->stonePartOfMill[i] == 0 && field->oppPlayer->id == field->board[i]) + break; + if (i == field->size) + return false; } // when no mill is closed than no stone can be removed - if (field->stoneMustBeRemoved && numberOfMillsCurrentPlayer == 0) { + if (field->stoneMustBeRemoved && numberOfMillsCurrentPlayer == 0) + { return false; // when in setting phase and difference in number of stones between the two players is not - } else if (field->settingPhase) { + } + else if (field->settingPhase) + { // Version 8: added for-loop noneFullFilled = true; - for (i = 0; noneFullFilled && i <= (int)numberOfMillsOpponentPlayer && i <= (int)numberOfMillsCurrentPlayer; i++) { - for (j = 0; noneFullFilled && j <= (int)numberOfMillsOpponentPlayer && j <= (int)numberOfMillsCurrentPlayer - (int)field->stoneMustBeRemoved; j++) { - if (field->curPlayer->numStones + numberOfMillsOpponentPlayer + 0 - field->stoneMustBeRemoved - j == field->oppPlayer->numStones + numberOfMillsCurrentPlayer - field->stoneMustBeRemoved - i) noneFullFilled = false; - if (field->curPlayer->numStones + numberOfMillsOpponentPlayer + 1 - field->stoneMustBeRemoved - j == field->oppPlayer->numStones + numberOfMillsCurrentPlayer - field->stoneMustBeRemoved - i) noneFullFilled = false; + for (i = 0; noneFullFilled && i <= (int)numberOfMillsOpponentPlayer && i <= (int)numberOfMillsCurrentPlayer; i++) + { + for (j = 0; noneFullFilled && j <= (int)numberOfMillsOpponentPlayer && j <= (int)numberOfMillsCurrentPlayer - (int)field->stoneMustBeRemoved; j++) + { + if (field->curPlayer->numStones + numberOfMillsOpponentPlayer + 0 - field->stoneMustBeRemoved - j == field->oppPlayer->numStones + numberOfMillsCurrentPlayer - field->stoneMustBeRemoved - i) + noneFullFilled = false; + if (field->curPlayer->numStones + numberOfMillsOpponentPlayer + 1 - field->stoneMustBeRemoved - j == field->oppPlayer->numStones + numberOfMillsCurrentPlayer - field->stoneMustBeRemoved - i) + noneFullFilled = false; } } - if (noneFullFilled || field->stonesSet >= 18) { + if (noneFullFilled || field->stonesSet >= 18) + { return false; } // moving phase - } else if (!field->settingPhase && (field->curPlayer->numStones < 2 || field->oppPlayer->numStones < 2)) { + } + else if (!field->settingPhase && (field->curPlayer->numStones < 2 || field->oppPlayer->numStones < 2)) + { return false; } @@ -1997,56 +2231,92 @@ bool PerfectAI::ThreadVars::fieldIntegrityOK(unsigned int numberOfMillsCurrentPl //----------------------------------------------------------------------------- // Name: isSymOperationInvariantOnGroupCD() -// Desc: +// Desc: //----------------------------------------------------------------------------- bool PerfectAI::isSymOperationInvariantOnGroupCD(unsigned int symmetryOperation, int *theField) { // locals unsigned int i; - i = squareIndexGroupC[0]; if (theField[i] != theField[symmetryOperationTable[symmetryOperation][i]]) return false; - i = squareIndexGroupC[1]; if (theField[i] != theField[symmetryOperationTable[symmetryOperation][i]]) return false; - i = squareIndexGroupC[2]; if (theField[i] != theField[symmetryOperationTable[symmetryOperation][i]]) return false; - i = squareIndexGroupC[3]; if (theField[i] != theField[symmetryOperationTable[symmetryOperation][i]]) return false; - i = squareIndexGroupC[4]; if (theField[i] != theField[symmetryOperationTable[symmetryOperation][i]]) return false; - i = squareIndexGroupC[5]; if (theField[i] != theField[symmetryOperationTable[symmetryOperation][i]]) return false; - i = squareIndexGroupC[6]; if (theField[i] != theField[symmetryOperationTable[symmetryOperation][i]]) return false; - i = squareIndexGroupC[7]; if (theField[i] != theField[symmetryOperationTable[symmetryOperation][i]]) return false; - i = squareIndexGroupD[0]; if (theField[i] != theField[symmetryOperationTable[symmetryOperation][i]]) return false; - i = squareIndexGroupD[1]; if (theField[i] != theField[symmetryOperationTable[symmetryOperation][i]]) return false; - i = squareIndexGroupD[2]; if (theField[i] != theField[symmetryOperationTable[symmetryOperation][i]]) return false; - i = squareIndexGroupD[3]; if (theField[i] != theField[symmetryOperationTable[symmetryOperation][i]]) return false; - i = squareIndexGroupD[4]; if (theField[i] != theField[symmetryOperationTable[symmetryOperation][i]]) return false; - i = squareIndexGroupD[5]; if (theField[i] != theField[symmetryOperationTable[symmetryOperation][i]]) return false; - i = squareIndexGroupD[6]; if (theField[i] != theField[symmetryOperationTable[symmetryOperation][i]]) return false; - i = squareIndexGroupD[7]; if (theField[i] != theField[symmetryOperationTable[symmetryOperation][i]]) return false; + i = squareIndexGroupC[0]; + if (theField[i] != theField[symmetryOperationTable[symmetryOperation][i]]) + return false; + i = squareIndexGroupC[1]; + if (theField[i] != theField[symmetryOperationTable[symmetryOperation][i]]) + return false; + i = squareIndexGroupC[2]; + if (theField[i] != theField[symmetryOperationTable[symmetryOperation][i]]) + return false; + i = squareIndexGroupC[3]; + if (theField[i] != theField[symmetryOperationTable[symmetryOperation][i]]) + return false; + i = squareIndexGroupC[4]; + if (theField[i] != theField[symmetryOperationTable[symmetryOperation][i]]) + return false; + i = squareIndexGroupC[5]; + if (theField[i] != theField[symmetryOperationTable[symmetryOperation][i]]) + return false; + i = squareIndexGroupC[6]; + if (theField[i] != theField[symmetryOperationTable[symmetryOperation][i]]) + return false; + i = squareIndexGroupC[7]; + if (theField[i] != theField[symmetryOperationTable[symmetryOperation][i]]) + return false; + i = squareIndexGroupD[0]; + if (theField[i] != theField[symmetryOperationTable[symmetryOperation][i]]) + return false; + i = squareIndexGroupD[1]; + if (theField[i] != theField[symmetryOperationTable[symmetryOperation][i]]) + return false; + i = squareIndexGroupD[2]; + if (theField[i] != theField[symmetryOperationTable[symmetryOperation][i]]) + return false; + i = squareIndexGroupD[3]; + if (theField[i] != theField[symmetryOperationTable[symmetryOperation][i]]) + return false; + i = squareIndexGroupD[4]; + if (theField[i] != theField[symmetryOperationTable[symmetryOperation][i]]) + return false; + i = squareIndexGroupD[5]; + if (theField[i] != theField[symmetryOperationTable[symmetryOperation][i]]) + return false; + i = squareIndexGroupD[6]; + if (theField[i] != theField[symmetryOperationTable[symmetryOperation][i]]) + return false; + i = squareIndexGroupD[7]; + if (theField[i] != theField[symmetryOperationTable[symmetryOperation][i]]) + return false; return true; } //----------------------------------------------------------------------------- // Name: storePredecessor() -// Desc: +// Desc: //----------------------------------------------------------------------------- void PerfectAI::ThreadVars::storePredecessor(unsigned int numberOfMillsCurrentPlayer, unsigned int numberOfMillsOpponentPlayer, unsigned int *amountOfPred, RetroAnalysisPredVars *predVars) { // locals - int originalField[fieldStruct::size]; + int originalField[fieldStruct::size]; unsigned int i, symmetryOperation, symOpApplied; unsigned int predLayerNum, predStateNum; unsigned int originalAmountOfPred = *amountOfPred; // store only if state is valid - if (fieldIntegrityOK(numberOfMillsCurrentPlayer, numberOfMillsOpponentPlayer, false)) { + if (fieldIntegrityOK(numberOfMillsCurrentPlayer, numberOfMillsOpponentPlayer, false)) + { // save current board - for (i = 0; i < fieldStruct::size; i++) originalField[i] = field->board[i]; + for (i = 0; i < fieldStruct::size; i++) + originalField[i] = field->board[i]; // add all symmetric states - for (symmetryOperation = 0; symmetryOperation < NUM_SYM_OPERATIONS; symmetryOperation++) { + for (symmetryOperation = 0; symmetryOperation < NUM_SYM_OPERATIONS; symmetryOperation++) + { // ... - if (symmetryOperation == SO_DO_NOTHING || parent->isSymOperationInvariantOnGroupCD(symmetryOperation, originalField)) { + if (symmetryOperation == SO_DO_NOTHING || parent->isSymOperationInvariantOnGroupCD(symmetryOperation, originalField)) + { // appy symmetry operation parent->applySymmetrieOperationOnField(symmetryOperation, (unsigned int *)originalField, (unsigned int *)field->board); @@ -2058,13 +2328,17 @@ void PerfectAI::ThreadVars::storePredecessor(unsigned int numberOfMillsCurrentPl predVars[*amountOfPred].playerToMoveChanged = predVars[originalAmountOfPred].playerToMoveChanged; // add only if not already in list - for (i = 0; i < (*amountOfPred); i++) if (predVars[i].predLayerNumbers == predLayerNum && predVars[i].predStateNumbers == predStateNum) break; - if (i == *amountOfPred) (*amountOfPred)++; + for (i = 0; i < (*amountOfPred); i++) + if (predVars[i].predLayerNumbers == predLayerNum && predVars[i].predStateNumbers == predStateNum) + break; + if (i == *amountOfPred) + (*amountOfPred)++; } } // restore original board - for (i = 0; i < fieldStruct::size; i++) field->board[i] = originalField[i]; + for (i = 0; i < fieldStruct::size; i++) + field->board[i] = originalField[i]; } } @@ -2086,8 +2360,8 @@ void PerfectAI::getPredecessors(unsigned int threadNo, unsigned int *amountOfPre // locals ThreadVars *tv = &threadVars[threadNo]; - bool aStoneCanBeRemovedFromCurPlayer; - bool millWasClosed; + bool aStoneCanBeRemovedFromCurPlayer; + bool millWasClosed; unsigned int from, to, dir, i; Player *tmpPlayer; unsigned int numberOfMillsCurrentPlayer = 0; @@ -2097,62 +2371,80 @@ void PerfectAI::getPredecessors(unsigned int threadNo, unsigned int *amountOfPre *amountOfPred = 0; // count completed mills - for (i = 0; i < fieldStruct::size; i++) { - if (tv->field->board[i] == tv->field->curPlayer->id) numberOfMillsCurrentPlayer += tv->field->stonePartOfMill[i]; - else numberOfMillsOpponentPlayer += tv->field->stonePartOfMill[i]; + for (i = 0; i < fieldStruct::size; i++) + { + if (tv->field->board[i] == tv->field->curPlayer->id) + numberOfMillsCurrentPlayer += tv->field->stonePartOfMill[i]; + else + numberOfMillsOpponentPlayer += tv->field->stonePartOfMill[i]; } numberOfMillsCurrentPlayer /= 3; numberOfMillsOpponentPlayer /= 3; // precalc aStoneCanBeRemovedFromCurPlayer - for (aStoneCanBeRemovedFromCurPlayer = false, i = 0; i < tv->field->size; i++) { - if (tv->field->stonePartOfMill[i] == 0 && tv->field->board[i] == tv->field->curPlayer->id) { + for (aStoneCanBeRemovedFromCurPlayer = false, i = 0; i < tv->field->size; i++) + { + if (tv->field->stonePartOfMill[i] == 0 && tv->field->board[i] == tv->field->curPlayer->id) + { aStoneCanBeRemovedFromCurPlayer = true; break; } } // was a mill closed? - if (tv->field->stoneMustBeRemoved) millWasClosed = true; - else millWasClosed = false; + if (tv->field->stoneMustBeRemoved) + millWasClosed = true; + else + millWasClosed = false; // in moving phase - if (!tv->field->settingPhase && tv->field->curPlayer->numStones >= 3 && tv->field->oppPlayer->numStones >= 3) { + if (!tv->field->settingPhase && tv->field->curPlayer->numStones >= 3 && tv->field->oppPlayer->numStones >= 3) + { // normal move - if ((tv->field->stoneMustBeRemoved && tv->field->curPlayer->numStones > 3) - || (!tv->field->stoneMustBeRemoved && tv->field->oppPlayer->numStones > 3)) { + if ((tv->field->stoneMustBeRemoved && tv->field->curPlayer->numStones > 3) || (!tv->field->stoneMustBeRemoved && tv->field->oppPlayer->numStones > 3)) + { // when game has finished then because current player can't move anymore or has less then 3 stones - if (!tv->gameHasFinished || (tv->gameHasFinished && tv->field->curPlayer->numPossibleMoves == 0)) { + if (!tv->gameHasFinished || (tv->gameHasFinished && tv->field->curPlayer->numPossibleMoves == 0)) + { // test each destination - for (to = 0; to < tv->field->size; to++) { + for (to = 0; to < tv->field->size; to++) + { // was opponent player stone owner? - if (tv->field->board[to] != (tv->field->stoneMustBeRemoved ? tv->field->curPlayer->id : tv->field->oppPlayer->id)) continue; + if (tv->field->board[to] != (tv->field->stoneMustBeRemoved ? tv->field->curPlayer->id : tv->field->oppPlayer->id)) + continue; // when stone is going to be removed than a mill must be closed - if (tv->field->stoneMustBeRemoved && tv->field->stonePartOfMill[to] == 0) continue; + if (tv->field->stoneMustBeRemoved && tv->field->stonePartOfMill[to] == 0) + continue; // when stone is part of a mill then a stone must be removed - if (aStoneCanBeRemovedFromCurPlayer && tv->field->stoneMustBeRemoved == 0 && tv->field->stonePartOfMill[to]) continue; + if (aStoneCanBeRemovedFromCurPlayer && tv->field->stoneMustBeRemoved == 0 && tv->field->stonePartOfMill[to]) + continue; // test each direction - for (dir = 0; dir < 4; dir++) { + for (dir = 0; dir < 4; dir++) + { - // origin + // origin from = tv->field->connectedSquare[to][dir]; // move possible ? - if (from < tv->field->size && tv->field->board[from] == tv->field->squareIsFree) { + if (from < tv->field->size && tv->field->board[from] == tv->field->squareIsFree) + { - if (millWasClosed) { + if (millWasClosed) + { numberOfMillsCurrentPlayer -= tv->field->stonePartOfMill[to]; tv->field->stoneMustBeRemoved = 0; predVars[*amountOfPred].playerToMoveChanged = false; - } else { + } + else + { predVars[*amountOfPred].playerToMoveChanged = true; tmpPlayer = tv->field->curPlayer; tv->field->curPlayer = tv->field->oppPlayer; @@ -2174,10 +2466,13 @@ void PerfectAI::getPredecessors(unsigned int threadNo, unsigned int *amountOfPre tv->field->board[to] = tv->field->board[from]; tv->field->board[from] = tv->field->squareIsFree; - if (millWasClosed) { + if (millWasClosed) + { numberOfMillsCurrentPlayer += tv->field->stonePartOfMill[to]; tv->field->stoneMustBeRemoved = 1; - } else { + } + else + { tmpPlayer = tv->field->curPlayer; tv->field->curPlayer = tv->field->oppPlayer; tv->field->oppPlayer = tmpPlayer; @@ -2192,32 +2487,43 @@ void PerfectAI::getPredecessors(unsigned int threadNo, unsigned int *amountOfPre } } } - } else if (!tv->gameHasFinished) { + } + else if (!tv->gameHasFinished) + { // test each destination - for (to = 0; to < tv->field->size; to++) { + for (to = 0; to < tv->field->size; to++) + { // when stone must be removed than current player closed a mill, otherwise the opponent did a common spring move - if (tv->field->board[to] != (tv->field->stoneMustBeRemoved ? tv->field->curPlayer->id : tv->field->oppPlayer->id)) continue; + if (tv->field->board[to] != (tv->field->stoneMustBeRemoved ? tv->field->curPlayer->id : tv->field->oppPlayer->id)) + continue; // when stone is going to be removed than a mill must be closed - if (tv->field->stoneMustBeRemoved && tv->field->stonePartOfMill[to] == 0) continue; + if (tv->field->stoneMustBeRemoved && tv->field->stonePartOfMill[to] == 0) + continue; // when stone is part of a mill then a stone must be removed - if (aStoneCanBeRemovedFromCurPlayer && tv->field->stoneMustBeRemoved == 0 && tv->field->stonePartOfMill[to]) continue; + if (aStoneCanBeRemovedFromCurPlayer && tv->field->stoneMustBeRemoved == 0 && tv->field->stonePartOfMill[to]) + continue; // test each direction - for (from = 0; from < tv->field->size; from++) { + for (from = 0; from < tv->field->size; from++) + { // move possible ? - if (tv->field->board[from] == tv->field->squareIsFree) { + if (tv->field->board[from] == tv->field->squareIsFree) + { // was a mill closed? - if (millWasClosed) { + if (millWasClosed) + { numberOfMillsCurrentPlayer -= tv->field->stonePartOfMill[to]; tv->field->stoneMustBeRemoved = 0; predVars[*amountOfPred].playerToMoveChanged = false; - } else { + } + else + { predVars[*amountOfPred].playerToMoveChanged = true; tmpPlayer = tv->field->curPlayer; tv->field->curPlayer = tv->field->oppPlayer; @@ -2239,10 +2545,13 @@ void PerfectAI::getPredecessors(unsigned int threadNo, unsigned int *amountOfPre tv->field->board[to] = tv->field->board[from]; tv->field->board[from] = tv->field->squareIsFree; - if (millWasClosed) { + if (millWasClosed) + { numberOfMillsCurrentPlayer += tv->field->stonePartOfMill[to]; tv->field->stoneMustBeRemoved = 1; - } else { + } + else + { tmpPlayer = tv->field->curPlayer; tv->field->curPlayer = tv->field->oppPlayer; tv->field->oppPlayer = tmpPlayer; @@ -2258,20 +2567,24 @@ void PerfectAI::getPredecessors(unsigned int threadNo, unsigned int *amountOfPre } // was a stone removed ? - if (tv->field->curPlayer->numStones < 9 && tv->field->curPlayer->numStonesMissing > 0 && tv->field->stoneMustBeRemoved == 0) { + if (tv->field->curPlayer->numStones < 9 && tv->field->curPlayer->numStonesMissing > 0 && tv->field->stoneMustBeRemoved == 0) + { // has opponent player a closed mill ? - if (numberOfMillsOpponentPlayer) { + if (numberOfMillsOpponentPlayer) + { // from each free position the opponent could have removed a stone from the current player - for (from = 0; from < tv->field->size; from++) { + for (from = 0; from < tv->field->size; from++) + { // square free? - if (tv->field->board[from] == tv->field->squareIsFree) { + if (tv->field->board[from] == tv->field->squareIsFree) + { // stone mustn't be part of mill - if ((!(tv->field->board[tv->field->neighbour[from][0][0]] == tv->field->curPlayer->id && tv->field->board[tv->field->neighbour[from][0][1]] == tv->field->curPlayer->id)) - && (!(tv->field->board[tv->field->neighbour[from][1][0]] == tv->field->curPlayer->id && tv->field->board[tv->field->neighbour[from][1][1]] == tv->field->curPlayer->id))) { + if ((!(tv->field->board[tv->field->neighbour[from][0][0]] == tv->field->curPlayer->id && tv->field->board[tv->field->neighbour[from][0][1]] == tv->field->curPlayer->id)) && (!(tv->field->board[tv->field->neighbour[from][1][0]] == tv->field->curPlayer->id && tv->field->board[tv->field->neighbour[from][1][1]] == tv->field->curPlayer->id))) + { // put back stone tv->field->stoneMustBeRemoved = 1; @@ -2306,44 +2619,53 @@ void PerfectAI::getPredecessors(unsigned int threadNo, unsigned int *amountOfPre //----------------------------------------------------------------------------- // Name: checkMoveAndSetSituation() -// Desc: +// Desc: //----------------------------------------------------------------------------- bool PerfectAI::checkMoveAndSetSituation() { // locals - bool aStoneCanBeRemovedFromCurPlayer; - unsigned int numberOfMillsCurrentPlayer, numberOfMillsOpponentPlayer; - unsigned int stateNum, layerNum, curMove, i; + bool aStoneCanBeRemovedFromCurPlayer; + unsigned int numberOfMillsCurrentPlayer, numberOfMillsOpponentPlayer; + unsigned int stateNum, layerNum, curMove, i; unsigned int *idPossibility; - unsigned int numPossibilities; - bool isOpponentLevel; + unsigned int numPossibilities; + bool isOpponentLevel; void *pPossibilities; void *pBackup; - unsigned int threadNo = 0; + unsigned int threadNo = 0; ThreadVars *tv = &threadVars[threadNo]; - // output - cout << endl << "checkMoveAndSetSituation()" << endl; + // output + cout << endl + << "checkMoveAndSetSituation()" << endl; // test if each successor from getPossibilities() leads to the original state using getPredecessors() - for (layerNum = 0; layerNum < NUM_LAYERS; layerNum++) { + for (layerNum = 0; layerNum < NUM_LAYERS; layerNum++) + { // generate random state - cout << endl << "TESTING LAYER: " << layerNum; - if (layer[layerNum].subLayer[layer[layerNum].numSubLayers - 1].maxIndex == 0) continue; + cout << endl + << "TESTING LAYER: " << layerNum; + if (layer[layerNum].subLayer[layer[layerNum].numSubLayers - 1].maxIndex == 0) + continue; - // test each state of layer - for (stateNum = 0; stateNum < (layer[layerNum].subLayer[layer[layerNum].numSubLayers - 1].maxIndex + 1) * MAX_NUM_STONES_REMOVED_MINUS_1; stateNum++) { + // test each state of layer + for (stateNum = 0; stateNum < (layer[layerNum].subLayer[layer[layerNum].numSubLayers - 1].maxIndex + 1) * MAX_NUM_STONES_REMOVED_MINUS_1; stateNum++) + { // set situation - if (stateNum % OUTPUT_EVERY_N_STATES == 0) cout << endl << "TESTING STATE " << stateNum << " OF " << (layer[layerNum].subLayer[layer[layerNum].numSubLayers - 1].maxIndex + 1) * MAX_NUM_STONES_REMOVED_MINUS_1; - if (!setSituation(threadNo, layerNum, stateNum)) continue; + if (stateNum % OUTPUT_EVERY_N_STATES == 0) + cout << endl + << "TESTING STATE " << stateNum << " OF " << (layer[layerNum].subLayer[layer[layerNum].numSubLayers - 1].maxIndex + 1) * MAX_NUM_STONES_REMOVED_MINUS_1; + if (!setSituation(threadNo, layerNum, stateNum)) + continue; // get all possible moves idPossibility = getPossibilities(threadNo, &numPossibilities, &isOpponentLevel, &pPossibilities); // go to each successor state - for (curMove = 0; curMove < numPossibilities; curMove++) { + for (curMove = 0; curMove < numPossibilities; curMove++) + { // move move(threadNo, idPossibility[curMove], isOpponentLevel, &pBackup, pPossibilities); @@ -2351,24 +2673,31 @@ bool PerfectAI::checkMoveAndSetSituation() // count completed mills numberOfMillsCurrentPlayer = 0; numberOfMillsOpponentPlayer = 0; - for (i = 0; i < fieldStruct::size; i++) { - if (tv->field->board[i] == tv->field->curPlayer->id) numberOfMillsCurrentPlayer += tv->field->stonePartOfMill[i]; - else numberOfMillsOpponentPlayer += tv->field->stonePartOfMill[i]; + for (i = 0; i < fieldStruct::size; i++) + { + if (tv->field->board[i] == tv->field->curPlayer->id) + numberOfMillsCurrentPlayer += tv->field->stonePartOfMill[i]; + else + numberOfMillsOpponentPlayer += tv->field->stonePartOfMill[i]; } numberOfMillsCurrentPlayer /= 3; numberOfMillsOpponentPlayer /= 3; // precalc aStoneCanBeRemovedFromCurPlayer - for (aStoneCanBeRemovedFromCurPlayer = false, i = 0; i < tv->field->size; i++) { - if (tv->field->stonePartOfMill[i] == 0 && tv->field->board[i] == tv->field->curPlayer->id) { + for (aStoneCanBeRemovedFromCurPlayer = false, i = 0; i < tv->field->size; i++) + { + if (tv->field->stonePartOfMill[i] == 0 && tv->field->board[i] == tv->field->curPlayer->id) + { aStoneCanBeRemovedFromCurPlayer = true; break; } } - // - if (tv->fieldIntegrityOK(numberOfMillsCurrentPlayer, numberOfMillsOpponentPlayer, aStoneCanBeRemovedFromCurPlayer) == false) { - cout << endl << "ERROR: STATE " << stateNum << " REACHED WITH move(), BUT IS INVALID!"; + // + if (tv->fieldIntegrityOK(numberOfMillsCurrentPlayer, numberOfMillsOpponentPlayer, aStoneCanBeRemovedFromCurPlayer) == false) + { + cout << endl + << "ERROR: STATE " << stateNum << " REACHED WITH move(), BUT IS INVALID!"; //return false; } @@ -2376,7 +2705,8 @@ bool PerfectAI::checkMoveAndSetSituation() undo(threadNo, idPossibility[curMove], isOpponentLevel, pBackup, pPossibilities); } } - cout << endl << "LAYER OK: " << layerNum << endl; + cout << endl + << "LAYER OK: " << layerNum << endl; } // free mem @@ -2385,41 +2715,49 @@ bool PerfectAI::checkMoveAndSetSituation() //----------------------------------------------------------------------------- // Name: checkGetPossThanGetPred() -// Desc: +// Desc: //----------------------------------------------------------------------------- bool PerfectAI::checkGetPossThanGetPred() { // locals - unsigned int stateNum, layerNum, i, j; + unsigned int stateNum, layerNum, i, j; unsigned int *idPossibility; - unsigned int numPossibilities; - unsigned int amountOfPred; - bool isOpponentLevel; + unsigned int numPossibilities; + unsigned int amountOfPred; + bool isOpponentLevel; void *pPossibilities; void *pBackup; - RetroAnalysisPredVars predVars[MAX_NUM_PREDECESSORS]; - unsigned int threadNo = 0; + RetroAnalysisPredVars predVars[MAX_NUM_PREDECESSORS]; + unsigned int threadNo = 0; ThreadVars *tv = &threadVars[threadNo]; // test if each successor from getPossibilities() leads to the original state using getPredecessors() - for (layerNum = 0; layerNum < NUM_LAYERS; layerNum++) { + for (layerNum = 0; layerNum < NUM_LAYERS; layerNum++) + { // generate random state - cout << endl << "TESTING LAYER: " << layerNum; - if (layer[layerNum].subLayer[layer[layerNum].numSubLayers - 1].maxIndex == 0) continue; + cout << endl + << "TESTING LAYER: " << layerNum; + if (layer[layerNum].subLayer[layer[layerNum].numSubLayers - 1].maxIndex == 0) + continue; - // test each state of layer - for (stateNum = 0; stateNum < (layer[layerNum].subLayer[layer[layerNum].numSubLayers - 1].maxIndex + 1) * MAX_NUM_STONES_REMOVED_MINUS_1; stateNum++) { + // test each state of layer + for (stateNum = 0; stateNum < (layer[layerNum].subLayer[layer[layerNum].numSubLayers - 1].maxIndex + 1) * MAX_NUM_STONES_REMOVED_MINUS_1; stateNum++) + { // set situation - if (stateNum % 10000 == 0) cout << endl << "TESTING STATE " << stateNum << " OF " << (layer[layerNum].subLayer[layer[layerNum].numSubLayers - 1].maxIndex + 1) * MAX_NUM_STONES_REMOVED_MINUS_1; - if (!setSituation(threadNo, layerNum, stateNum)) continue; + if (stateNum % 10000 == 0) + cout << endl + << "TESTING STATE " << stateNum << " OF " << (layer[layerNum].subLayer[layer[layerNum].numSubLayers - 1].maxIndex + 1) * MAX_NUM_STONES_REMOVED_MINUS_1; + if (!setSituation(threadNo, layerNum, stateNum)) + continue; // get all possible moves idPossibility = getPossibilities(threadNo, &numPossibilities, &isOpponentLevel, &pPossibilities); // go to each successor state - for (i = 0; i < numPossibilities; i++) { + for (i = 0; i < numPossibilities; i++) + { // move move(threadNo, idPossibility[i], isOpponentLevel, &pBackup, pPossibilities); @@ -2428,14 +2766,18 @@ bool PerfectAI::checkGetPossThanGetPred() getPredecessors(threadNo, &amountOfPred, predVars); // does it match ? - for (j = 0; j < amountOfPred; j++) { - if (predVars[j].predStateNumbers == stateNum && predVars[j].predLayerNumbers == layerNum) break; + for (j = 0; j < amountOfPred; j++) + { + if (predVars[j].predStateNumbers == stateNum && predVars[j].predLayerNumbers == layerNum) + break; } // error? - if (j == amountOfPred) { + if (j == amountOfPred) + { - cout << endl << "ERROR: STATE " << stateNum << " NOT FOUND IN PREDECESSOR LIST"; + cout << endl + << "ERROR: STATE " << stateNum << " NOT FOUND IN PREDECESSOR LIST"; return false; // perform several commands to see in debug mode where the error occurs @@ -2455,7 +2797,8 @@ bool PerfectAI::checkGetPossThanGetPred() undo(threadNo, idPossibility[i], isOpponentLevel, pBackup, pPossibilities); } } - cout << endl << "LAYER OK: " << layerNum << endl; + cout << endl + << "LAYER OK: " << layerNum << endl; } // everything fine @@ -2464,61 +2807,77 @@ bool PerfectAI::checkGetPossThanGetPred() //----------------------------------------------------------------------------- // Name: checkGetPredThanGetPoss() -// Desc: +// Desc: //----------------------------------------------------------------------------- bool PerfectAI::checkGetPredThanGetPoss() { // locals - unsigned int threadNo = 0; + unsigned int threadNo = 0; ThreadVars *tv = &threadVars[threadNo]; - unsigned int stateNum, layerNum, i, j, k; - unsigned int stateNumB, layerNumB; + unsigned int stateNum, layerNum, i, j, k; + unsigned int stateNumB, layerNumB; unsigned int *idPossibility; - unsigned int numPossibilities; - unsigned int amountOfPred; - bool isOpponentLevel; + unsigned int numPossibilities; + unsigned int amountOfPred; + bool isOpponentLevel; void *pPossibilities; void *pBackup; - int symField[fieldStruct::size]; - RetroAnalysisPredVars predVars[MAX_NUM_PREDECESSORS]; + int symField[fieldStruct::size]; + RetroAnalysisPredVars predVars[MAX_NUM_PREDECESSORS]; // test if each predecessor from getPredecessors() leads to the original state using getPossibilities() - for (layerNum = 0; layerNum < NUM_LAYERS; layerNum++) { + for (layerNum = 0; layerNum < NUM_LAYERS; layerNum++) + { // generate random state - cout << endl << "TESTING LAYER: " << layerNum; - if (layer[layerNum].subLayer[layer[layerNum].numSubLayers - 1].maxIndex == 0) continue; + cout << endl + << "TESTING LAYER: " << layerNum; + if (layer[layerNum].subLayer[layer[layerNum].numSubLayers - 1].maxIndex == 0) + continue; - // test each state of layer - for (stateNum = 0; stateNum < (layer[layerNum].subLayer[layer[layerNum].numSubLayers - 1].maxIndex + 1) * MAX_NUM_STONES_REMOVED_MINUS_1; stateNum++) { + // test each state of layer + for (stateNum = 0; stateNum < (layer[layerNum].subLayer[layer[layerNum].numSubLayers - 1].maxIndex + 1) * MAX_NUM_STONES_REMOVED_MINUS_1; stateNum++) + { // set situation - if (stateNum % 10000000 == 0) cout << endl << "TESTING STATE " << stateNum << " OF " << (layer[layerNum].subLayer[layer[layerNum].numSubLayers - 1].maxIndex + 1) * MAX_NUM_STONES_REMOVED_MINUS_1; - if (!setSituation(threadNo, layerNum, stateNum)) continue; + if (stateNum % 10000000 == 0) + cout << endl + << "TESTING STATE " << stateNum << " OF " << (layer[layerNum].subLayer[layer[layerNum].numSubLayers - 1].maxIndex + 1) * MAX_NUM_STONES_REMOVED_MINUS_1; + if (!setSituation(threadNo, layerNum, stateNum)) + continue; // get predecessors getPredecessors(threadNo, &amountOfPred, predVars); // test each returned predecessor - for (j = 0; j < amountOfPred; j++) { + for (j = 0; j < amountOfPred; j++) + { - // set situation - if (!setSituation(threadNo, predVars[j].predLayerNumbers, predVars[j].predStateNumbers)) { + // set situation + if (!setSituation(threadNo, predVars[j].predLayerNumbers, predVars[j].predStateNumbers)) + { - cout << endl << "ERROR SETTING SITUATION"; + cout << endl + << "ERROR SETTING SITUATION"; return false; // perform several commands to see in debug mode where the error occurs - for (k = 0; k < tv->field->size; k++) symField[k] = tv->field->board[k]; applySymmetrieOperationOnField(reverseSymOperation[predVars[j].predSymOperation], (unsigned int *)symField, (unsigned int *)tv->field->board); - for (k = 0; k < tv->field->size; k++) symField[k] = tv->field->stonePartOfMill[k]; applySymmetrieOperationOnField(reverseSymOperation[predVars[j].predSymOperation], (unsigned int *)symField, (unsigned int *)tv->field->stonePartOfMill); + for (k = 0; k < tv->field->size; k++) + symField[k] = tv->field->board[k]; + applySymmetrieOperationOnField(reverseSymOperation[predVars[j].predSymOperation], (unsigned int *)symField, (unsigned int *)tv->field->board); + for (k = 0; k < tv->field->size; k++) + symField[k] = tv->field->stonePartOfMill[k]; + applySymmetrieOperationOnField(reverseSymOperation[predVars[j].predSymOperation], (unsigned int *)symField, (unsigned int *)tv->field->stonePartOfMill); cout << "predecessor" << endl; cout << " layerNum: " << predVars[j].predLayerNumbers << "\tstateNum: " << predVars[j].predStateNumbers << endl; printBoard(threadNo, 0); - if (predVars[j].playerToMoveChanged) { + if (predVars[j].playerToMoveChanged) + { k = tv->field->curPlayer->id; tv->field->curPlayer->id = tv->field->oppPlayer->id; tv->field->oppPlayer->id = k; - for (k = 0; k < tv->field->size; k++) tv->field->board[k] = -1 * tv->field->board[k]; + for (k = 0; k < tv->field->size; k++) + tv->field->board[k] = -1 * tv->field->board[k]; } idPossibility = getPossibilities(threadNo, &numPossibilities, &isOpponentLevel, &pPossibilities); setSituation(threadNo, layerNum, stateNum); @@ -2529,20 +2888,27 @@ bool PerfectAI::checkGetPredThanGetPoss() } // regard used symmetry operation - for (k = 0; k < tv->field->size; k++) symField[k] = tv->field->board[k]; applySymmetrieOperationOnField(reverseSymOperation[predVars[j].predSymOperation], (unsigned int *)symField, (unsigned int *)tv->field->board); - for (k = 0; k < tv->field->size; k++) symField[k] = tv->field->stonePartOfMill[k]; applySymmetrieOperationOnField(reverseSymOperation[predVars[j].predSymOperation], (unsigned int *)symField, (unsigned int *)tv->field->stonePartOfMill); - if (predVars[j].playerToMoveChanged) { + for (k = 0; k < tv->field->size; k++) + symField[k] = tv->field->board[k]; + applySymmetrieOperationOnField(reverseSymOperation[predVars[j].predSymOperation], (unsigned int *)symField, (unsigned int *)tv->field->board); + for (k = 0; k < tv->field->size; k++) + symField[k] = tv->field->stonePartOfMill[k]; + applySymmetrieOperationOnField(reverseSymOperation[predVars[j].predSymOperation], (unsigned int *)symField, (unsigned int *)tv->field->stonePartOfMill); + if (predVars[j].playerToMoveChanged) + { k = tv->field->curPlayer->id; tv->field->curPlayer->id = tv->field->oppPlayer->id; tv->field->oppPlayer->id = k; - for (k = 0; k < tv->field->size; k++) tv->field->board[k] = -1 * tv->field->board[k]; + for (k = 0; k < tv->field->size; k++) + tv->field->board[k] = -1 * tv->field->board[k]; } // get all possible moves idPossibility = getPossibilities(threadNo, &numPossibilities, &isOpponentLevel, &pPossibilities); // go to each successor state - for (i = 0; i < numPossibilities; i++) { + for (i = 0; i < numPossibilities; i++) + { // move move(threadNo, idPossibility[i], isOpponentLevel, &pBackup, pPossibilities); @@ -2551,30 +2917,39 @@ bool PerfectAI::checkGetPredThanGetPoss() getLayerAndStateNumber(threadNo, layerNumB, stateNumB); // does states match ? - if (stateNum == stateNumB && layerNum == layerNumB) break; + if (stateNum == stateNumB && layerNum == layerNumB) + break; // undo move undo(threadNo, idPossibility[i], isOpponentLevel, pBackup, pPossibilities); } // error? - if (i == numPossibilities) { + if (i == numPossibilities) + { - cout << endl << "ERROR: Not all predecessors lead to state " << stateNum << " calling move()" << endl; + cout << endl + << "ERROR: Not all predecessors lead to state " << stateNum << " calling move()" << endl; //return false; // perform several commands to see in debug mode where the error occurs setSituation(threadNo, predVars[j].predLayerNumbers, predVars[j].predStateNumbers); - for (k = 0; k < tv->field->size; k++) symField[k] = tv->field->board[k]; applySymmetrieOperationOnField(reverseSymOperation[predVars[j].predSymOperation], (unsigned int *)symField, (unsigned int *)tv->field->board); - for (k = 0; k < tv->field->size; k++) symField[k] = tv->field->stonePartOfMill[k]; applySymmetrieOperationOnField(reverseSymOperation[predVars[j].predSymOperation], (unsigned int *)symField, (unsigned int *)tv->field->stonePartOfMill); + for (k = 0; k < tv->field->size; k++) + symField[k] = tv->field->board[k]; + applySymmetrieOperationOnField(reverseSymOperation[predVars[j].predSymOperation], (unsigned int *)symField, (unsigned int *)tv->field->board); + for (k = 0; k < tv->field->size; k++) + symField[k] = tv->field->stonePartOfMill[k]; + applySymmetrieOperationOnField(reverseSymOperation[predVars[j].predSymOperation], (unsigned int *)symField, (unsigned int *)tv->field->stonePartOfMill); cout << "predecessor" << endl; cout << " layerNum: " << predVars[j].predLayerNumbers << "\tstateNum: " << predVars[j].predStateNumbers << endl; printBoard(threadNo, 0); - if (predVars[j].playerToMoveChanged) { + if (predVars[j].playerToMoveChanged) + { k = tv->field->curPlayer->id; tv->field->curPlayer->id = tv->field->oppPlayer->id; tv->field->oppPlayer->id = k; - for (k = 0; k < tv->field->size; k++) tv->field->board[k] = -1 * tv->field->board[k]; + for (k = 0; k < tv->field->size; k++) + tv->field->board[k] = -1 * tv->field->board[k]; } idPossibility = getPossibilities(threadNo, &numPossibilities, &isOpponentLevel, &pPossibilities); setSituation(threadNo, layerNum, stateNum); @@ -2586,10 +2961,15 @@ bool PerfectAI::checkGetPredThanGetPoss() k = tv->field->curPlayer->id; tv->field->curPlayer->id = tv->field->oppPlayer->id; tv->field->oppPlayer->id = k; - for (k = 0; k < tv->field->size; k++) tv->field->board[k] = -1 * tv->field->board[k]; + for (k = 0; k < tv->field->size; k++) + tv->field->board[k] = -1 * tv->field->board[k]; setSituation(threadNo, predVars[j].predLayerNumbers, predVars[j].predStateNumbers); - for (k = 0; k < tv->field->size; k++) symField[k] = tv->field->board[k]; applySymmetrieOperationOnField(reverseSymOperation[predVars[j].predSymOperation], (unsigned int *)symField, (unsigned int *)tv->field->board); - for (k = 0; k < tv->field->size; k++) symField[k] = tv->field->stonePartOfMill[k]; applySymmetrieOperationOnField(reverseSymOperation[predVars[j].predSymOperation], (unsigned int *)symField, (unsigned int *)tv->field->stonePartOfMill); + for (k = 0; k < tv->field->size; k++) + symField[k] = tv->field->board[k]; + applySymmetrieOperationOnField(reverseSymOperation[predVars[j].predSymOperation], (unsigned int *)symField, (unsigned int *)tv->field->board); + for (k = 0; k < tv->field->size; k++) + symField[k] = tv->field->stonePartOfMill[k]; + applySymmetrieOperationOnField(reverseSymOperation[predVars[j].predSymOperation], (unsigned int *)symField, (unsigned int *)tv->field->stonePartOfMill); printBoard(threadNo, 0); idPossibility = getPossibilities(threadNo, &numPossibilities, &isOpponentLevel, &pPossibilities); move(threadNo, idPossibility[1], isOpponentLevel, &pBackup, pPossibilities); @@ -2598,7 +2978,8 @@ bool PerfectAI::checkGetPredThanGetPoss() } } } - cout << endl << "LAYER OK: " << layerNum << endl; + cout << endl + << "LAYER OK: " << layerNum << endl; } // free mem @@ -2606,7 +2987,7 @@ bool PerfectAI::checkGetPredThanGetPoss() } /*** To Do's *************************************** -- Womöglich alle cyclicArrays in einer Datei speichern. Besser sogar noch kompromieren (auf Windows oder Programm-Ebene?), was gut gehen sollte da ja eh blockweise gearbeitet wird. - Da Größe vorher unbekannt muss eine table her. Möglicher Klassenname "compressedCyclicArray(blockSize, numBlocks, numArrays, filePath)". +- Wom�glich alle cyclicArrays in einer Datei speichern. Besser sogar noch kompromieren (auf Windows oder Programm-Ebene?), was gut gehen sollte da ja eh blockweise gearbeitet wird. + Da Gr��e vorher unbekannt muss eine table her. M�glicher Klassenname "compressedCyclicArray(blockSize, numBlocks, numArrays, filePath)". - initFileReader implementieren ***************************************************/ diff --git a/src/perfect/perfectAI.h b/src/perfect/perfectAI.h index 786e8987..ace86da6 100644 --- a/src/perfect/perfectAI.h +++ b/src/perfect/perfectAI.h @@ -18,151 +18,150 @@ //using namespace std; // values of states/situations -#define VALUE_GAME_LOST -1000.0f -#define VALUE_GAME_WON 1000.0f +#define VALUE_GAME_LOST -1000.0f +#define VALUE_GAME_WON 1000.0f -// since a state must be saved two times, -// one time where no stone must be removed, +// since a state must be saved two times, +// one time where no stone must be removed, // one time where a stone must be removed -#define MAX_NUM_STONES_REMOVED_MINUS_1 2 +#define MAX_NUM_STONES_REMOVED_MINUS_1 2 // 10 x 10 since each color can range from 0 to 9 stones // x2 since there is the setting phase and the moving phase -#define NUM_LAYERS 200 -#define MAX_NUM_SUB_LAYERS 100 -#define LAYER_INDEX_SETTING_PHASE 1 -#define LAYER_INDEX_MOVING_PHASE 0 -#define NOT_INDEXED 4294967295 -#define MAX_DEPTH_OF_TREE 100 -#define NUM_STONES_PER_PLAYER 9 -#define NUM_STONES_PER_PLAYER_PLUS_ONE 10 +#define NUM_LAYERS 200 +#define MAX_NUM_SUB_LAYERS 100 +#define LAYER_INDEX_SETTING_PHASE 1 +#define LAYER_INDEX_MOVING_PHASE 0 +#define NOT_INDEXED 4294967295 +#define MAX_DEPTH_OF_TREE 100 +#define NUM_STONES_PER_PLAYER 9 +#define NUM_STONES_PER_PLAYER_PLUS_ONE 10 // The Four Groups (the board position is divided in four groups A,B,C,D) -#define numSquaresGroupA 4 -#define numSquaresGroupB 4 -#define numSquaresGroupC 8 -#define numSquaresGroupD 8 -#define GROUP_A 0 -#define GROUP_B 1 -#define GROUP_C 2 -#define GROUP_D 3 -#define MAX_ANZ_STELLUNGEN_A 81 -#define MAX_ANZ_STELLUNGEN_B 81 -#define MAX_ANZ_STELLUNGEN_C (81*81) -#define MAX_ANZ_STELLUNGEN_D (81*81) +#define numSquaresGroupA 4 +#define numSquaresGroupB 4 +#define numSquaresGroupC 8 +#define numSquaresGroupD 8 +#define GROUP_A 0 +#define GROUP_B 1 +#define GROUP_C 2 +#define GROUP_D 3 +#define MAX_ANZ_STELLUNGEN_A 81 +#define MAX_ANZ_STELLUNGEN_B 81 +#define MAX_ANZ_STELLUNGEN_C (81 * 81) +#define MAX_ANZ_STELLUNGEN_D (81 * 81) -#define FREE_SQUARE 0 -#define WHITE_STONE 1 -#define BLACK_STONE 2 +#define FREE_SQUARE 0 +#define WHITE_STONE 1 +#define BLACK_STONE 2 // Symmetry Operations -#define SO_TURN_LEFT 0 -#define SO_TURN_180 1 -#define SO_TURN_RIGHT 2 -#define SO_DO_NOTHING 3 -#define SO_INVERT 4 -#define SO_MIRROR_VERT 5 -#define SO_MIRROR_HORI 6 -#define SO_MIRROR_DIAG_1 7 -#define SO_MIRROR_DIAG_2 8 -#define SO_INV_LEFT 9 -#define SO_INV_RIGHT 10 -#define SO_INV_180 11 -#define SO_INV_MIR_VERT 12 -#define SO_INV_MIR_HORI 13 -#define SO_INV_MIR_DIAG_1 14 -#define SO_INV_MIR_DIAG_2 15 -#define NUM_SYM_OPERATIONS 16 +#define SO_TURN_LEFT 0 +#define SO_TURN_180 1 +#define SO_TURN_RIGHT 2 +#define SO_DO_NOTHING 3 +#define SO_INVERT 4 +#define SO_MIRROR_VERT 5 +#define SO_MIRROR_HORI 6 +#define SO_MIRROR_DIAG_1 7 +#define SO_MIRROR_DIAG_2 8 +#define SO_INV_LEFT 9 +#define SO_INV_RIGHT 10 +#define SO_INV_180 11 +#define SO_INV_MIR_VERT 12 +#define SO_INV_MIR_HORI 13 +#define SO_INV_MIR_DIAG_1 14 +#define SO_INV_MIR_DIAG_2 15 +#define NUM_SYM_OPERATIONS 16 /*** Klassen *********************************************************/ class PerfectAI : public MillAI, public MiniMax { protected: - // structs struct SubLayer { - unsigned int minIndex; - unsigned int maxIndex; - unsigned int numWhiteStonesGroupCD, numBlackStonesGroupCD; - unsigned int numWhiteStonesGroupAB, numBlackStonesGroupAB; + unsigned int minIndex; + unsigned int maxIndex; + unsigned int numWhiteStonesGroupCD, numBlackStonesGroupCD; + unsigned int numWhiteStonesGroupAB, numBlackStonesGroupAB; }; struct Layer { - unsigned int numWhiteStones; - unsigned int numBlackStones; - unsigned int numSubLayers; - unsigned int subLayerIndexAB[NUM_STONES_PER_PLAYER_PLUS_ONE][NUM_STONES_PER_PLAYER_PLUS_ONE]; - unsigned int subLayerIndexCD[NUM_STONES_PER_PLAYER_PLUS_ONE][NUM_STONES_PER_PLAYER_PLUS_ONE]; - SubLayer subLayer[MAX_NUM_SUB_LAYERS]; + unsigned int numWhiteStones; + unsigned int numBlackStones; + unsigned int numSubLayers; + unsigned int subLayerIndexAB[NUM_STONES_PER_PLAYER_PLUS_ONE][NUM_STONES_PER_PLAYER_PLUS_ONE]; + unsigned int subLayerIndexCD[NUM_STONES_PER_PLAYER_PLUS_ONE][NUM_STONES_PER_PLAYER_PLUS_ONE]; + SubLayer subLayer[MAX_NUM_SUB_LAYERS]; }; struct Possibility { - unsigned int from[MAX_NUM_POS_MOVES]; - unsigned int to[MAX_NUM_POS_MOVES]; + unsigned int from[MAX_NUM_POS_MOVES]; + unsigned int to[MAX_NUM_POS_MOVES]; }; struct Backup { - float floatValue; - TwoBit shortValue; - bool gameHasFinished; - bool settingPhase; - int fieldFrom, fieldTo; // value of board - unsigned int from, to; // index of board - unsigned int curNumStones, oppNumStones; - unsigned int curPosMoves, oppPosMoves; - unsigned int curMissStones, oppMissStones; - unsigned int stonesSet; - unsigned int stoneMustBeRemoved; - unsigned int stonePartOfMill[fieldStruct::size]; + float floatValue; + TwoBit shortValue; + bool gameHasFinished; + bool settingPhase; + int fieldFrom, fieldTo; // value of board + unsigned int from, to; // index of board + unsigned int curNumStones, oppNumStones; + unsigned int curPosMoves, oppPosMoves; + unsigned int curMissStones, oppMissStones; + unsigned int stonesSet; + unsigned int stoneMustBeRemoved; + unsigned int stonePartOfMill[fieldStruct::size]; Player *curPlayer, *oppPlayer; }; // preCalcedVars.dat struct PreCalcedVarsFileHeader { - unsigned int sizeInBytes; + unsigned int sizeInBytes; }; // constant variables for state addressing in the database - Layer layer[NUM_LAYERS]; // the layers - unsigned int layerIndex[2][NUM_STONES_PER_PLAYER_PLUS_ONE][NUM_STONES_PER_PLAYER_PLUS_ONE]; // indices of layer [moving/setting phase][number of white stones][number of black stones] - unsigned int anzahlStellungenCD[NUM_STONES_PER_PLAYER_PLUS_ONE][NUM_STONES_PER_PLAYER_PLUS_ONE]; - unsigned int anzahlStellungenAB[NUM_STONES_PER_PLAYER_PLUS_ONE][NUM_STONES_PER_PLAYER_PLUS_ONE]; - unsigned int indexAB[MAX_ANZ_STELLUNGEN_A * MAX_ANZ_STELLUNGEN_B]; - unsigned int indexCD[MAX_ANZ_STELLUNGEN_C * MAX_ANZ_STELLUNGEN_D]; - unsigned char symmetryOperationCD[MAX_ANZ_STELLUNGEN_C * MAX_ANZ_STELLUNGEN_D]; // index of symmetry operation used to get from the original state to the current one - unsigned int powerOfThree[numSquaresGroupC + numSquaresGroupD]; // 3^0, 3^1, 3^2, ... - unsigned int symmetryOperationTable[NUM_SYM_OPERATIONS][fieldStruct::size]; // Matrix used for application of the symmetry operations + Layer layer[NUM_LAYERS]; // the layers + unsigned int layerIndex[2][NUM_STONES_PER_PLAYER_PLUS_ONE][NUM_STONES_PER_PLAYER_PLUS_ONE]; // indices of layer [moving/setting phase][number of white stones][number of black stones] + unsigned int anzahlStellungenCD[NUM_STONES_PER_PLAYER_PLUS_ONE][NUM_STONES_PER_PLAYER_PLUS_ONE]; + unsigned int anzahlStellungenAB[NUM_STONES_PER_PLAYER_PLUS_ONE][NUM_STONES_PER_PLAYER_PLUS_ONE]; + unsigned int indexAB[MAX_ANZ_STELLUNGEN_A * MAX_ANZ_STELLUNGEN_B]; + unsigned int indexCD[MAX_ANZ_STELLUNGEN_C * MAX_ANZ_STELLUNGEN_D]; + unsigned char symmetryOperationCD[MAX_ANZ_STELLUNGEN_C * MAX_ANZ_STELLUNGEN_D]; // index of symmetry operation used to get from the original state to the current one + unsigned int powerOfThree[numSquaresGroupC + numSquaresGroupD]; // 3^0, 3^1, 3^2, ... + unsigned int symmetryOperationTable[NUM_SYM_OPERATIONS][fieldStruct::size]; // Matrix used for application of the symmetry operations unsigned int *originalStateCD[NUM_STONES_PER_PLAYER_PLUS_ONE][NUM_STONES_PER_PLAYER_PLUS_ONE]; unsigned int *originalStateAB[NUM_STONES_PER_PLAYER_PLUS_ONE][NUM_STONES_PER_PLAYER_PLUS_ONE]; - unsigned int reverseSymOperation[NUM_SYM_OPERATIONS]; // index of the reverse symmetry operation - unsigned int concSymOperation[NUM_SYM_OPERATIONS][NUM_SYM_OPERATIONS]; // symmetry operation, which is identical to applying those two in the index - unsigned int mOverN[fieldStruct::size + 1][fieldStruct::size + 1]; // m over n - unsigned char valueOfMove[fieldStruct::size * fieldStruct::size]; // contains the value of the situation, which will be achieved by that move - unsigned short plyInfoForOutput[fieldStruct::size * fieldStruct::size]; // contains the value of the situation, which will be achieved by that move - unsigned int incidencesValuesSubMoves[fieldStruct::size * fieldStruct::size][4]; // contains the number of ... - unsigned int symmetricStateNumberArray[NUM_SYM_OPERATIONS]; // array for state numbers - string databaseDirectory; // directory containing the database files + unsigned int reverseSymOperation[NUM_SYM_OPERATIONS]; // index of the reverse symmetry operation + unsigned int concSymOperation[NUM_SYM_OPERATIONS][NUM_SYM_OPERATIONS]; // symmetry operation, which is identical to applying those two in the index + unsigned int mOverN[fieldStruct::size + 1][fieldStruct::size + 1]; // m over n + unsigned char valueOfMove[fieldStruct::size * fieldStruct::size]; // contains the value of the situation, which will be achieved by that move + unsigned short plyInfoForOutput[fieldStruct::size * fieldStruct::size]; // contains the value of the situation, which will be achieved by that move + unsigned int incidencesValuesSubMoves[fieldStruct::size * fieldStruct::size][4]; // contains the number of ... + unsigned int symmetricStateNumberArray[NUM_SYM_OPERATIONS]; // array for state numbers + string databaseDirectory; // directory containing the database files // Variables used individually by each single thread class ThreadVars { public: - fieldStruct *field; // pointer of the current board [changed by move()] - float floatValue; // value of current situation for board->currentPlayer - TwoBit shortValue; // '' - bool gameHasFinished; // someone has won or current board is full - int ownId; // id of the player who called the play()-function - unsigned int curSearchDepth; // current level - unsigned int depthOfFullTree; // search depth where the whole tree is explored - unsigned int *idPossibilities; // returned pointer of getPossibilities()-function - Backup *oldStates; // for undo()-function - Possibility *possibilities; // for getPossNormalMove()-function - PerfectAI *parent; // + fieldStruct *field; // pointer of the current board [changed by move()] + float floatValue; // value of current situation for board->currentPlayer + TwoBit shortValue; // '' + bool gameHasFinished; // someone has won or current board is full + int ownId; // id of the player who called the play()-function + unsigned int curSearchDepth; // current level + unsigned int depthOfFullTree; // search depth where the whole tree is explored + unsigned int *idPossibilities; // returned pointer of getPossibilities()-function + Backup *oldStates; // for undo()-function + Possibility *possibilities; // for getPossNormalMove()-function + PerfectAI *parent; // // constructor ThreadVars(); @@ -173,57 +172,57 @@ protected: unsigned int *getPossStoneRemove(unsigned int *numPossibilities, void **pPossibilities); // move functions - inline void updatePossibleMoves(unsigned int stone, Player *stoneOwner, bool stoneRemoved, unsigned int ignoreStone); - inline void updateWarning(unsigned int firstStone, unsigned int secondStone); - inline void setWarning(unsigned int stoneOne, unsigned int stoneTwo, unsigned int stoneThree); - inline void removeStone(unsigned int from, Backup *backup); - inline void setStone(unsigned int to, Backup *backup); - inline void normalMove(unsigned int from, unsigned int to, Backup *backup); + inline void updatePossibleMoves(unsigned int stone, Player *stoneOwner, bool stoneRemoved, unsigned int ignoreStone); + inline void updateWarning(unsigned int firstStone, unsigned int secondStone); + inline void setWarning(unsigned int stoneOne, unsigned int stoneTwo, unsigned int stoneThree); + inline void removeStone(unsigned int from, Backup *backup); + inline void setStone(unsigned int to, Backup *backup); + inline void normalMove(unsigned int from, unsigned int to, Backup *backup); // database functions - unsigned int getLayerAndStateNumber(unsigned int &layerNum, unsigned int &stateNumber); - void setWarningAndMill(unsigned int stone, unsigned int firstNeighbour, unsigned int secondNeighbour); - bool fieldIntegrityOK(unsigned int numberOfMillsCurrentPlayer, unsigned int numberOfMillsOpponentPlayer, bool aStoneCanBeRemovedFromCurPlayer); - void calcPossibleMoves(Player *player); - void storePredecessor(unsigned int numberOfMillsCurrentPlayer, unsigned int numberOfMillsOpponentPlayer, unsigned int *amountOfPred, RetroAnalysisPredVars *predVars); + unsigned int getLayerAndStateNumber(unsigned int &layerNum, unsigned int &stateNumber); + void setWarningAndMill(unsigned int stone, unsigned int firstNeighbour, unsigned int secondNeighbour); + bool fieldIntegrityOK(unsigned int numberOfMillsCurrentPlayer, unsigned int numberOfMillsOpponentPlayer, bool aStoneCanBeRemovedFromCurPlayer); + void calcPossibleMoves(Player *player); + void storePredecessor(unsigned int numberOfMillsCurrentPlayer, unsigned int numberOfMillsOpponentPlayer, unsigned int *amountOfPred, RetroAnalysisPredVars *predVars); }; ThreadVars *threadVars; // database functions - unsigned int getNumberOfLayers(); - unsigned int getNumberOfKnotsInLayer(unsigned int layerNum); - long long mOverN_Function(unsigned int m, unsigned int n); - void applySymmetrieOperationOnField(unsigned char symmetryOperationNumber, unsigned int *sourceField, unsigned int *destField); - bool isSymOperationInvariantOnGroupCD(unsigned int symmetryOperation, int *theField); - bool shallRetroAnalysisBeUsed(unsigned int layerNum); - void getSuccLayers(unsigned int layerNum, unsigned int *amountOfSuccLayers, unsigned int *succLayers); - void getPredecessors(unsigned int threadNo, unsigned int *amountOfPred, RetroAnalysisPredVars *predVars); - bool setSituation(unsigned int threadNo, unsigned int layerNum, unsigned int stateNumber); - unsigned int getLayerNumber(unsigned int threadNo); - unsigned int getLayerAndStateNumber(unsigned int threadNo, unsigned int &layerNum, unsigned int &stateNumber); + unsigned int getNumberOfLayers(); + unsigned int getNumberOfKnotsInLayer(unsigned int layerNum); + long long mOverN_Function(unsigned int m, unsigned int n); + void applySymmetrieOperationOnField(unsigned char symmetryOperationNumber, unsigned int *sourceField, unsigned int *destField); + bool isSymOperationInvariantOnGroupCD(unsigned int symmetryOperation, int *theField); + bool shallRetroAnalysisBeUsed(unsigned int layerNum); + void getSuccLayers(unsigned int layerNum, unsigned int *amountOfSuccLayers, unsigned int *succLayers); + void getPredecessors(unsigned int threadNo, unsigned int *amountOfPred, RetroAnalysisPredVars *predVars); + bool setSituation(unsigned int threadNo, unsigned int layerNum, unsigned int stateNumber); + unsigned int getLayerNumber(unsigned int threadNo); + unsigned int getLayerAndStateNumber(unsigned int threadNo, unsigned int &layerNum, unsigned int &stateNumber); // integrity test functions - bool checkMoveAndSetSituation(); - bool checkGetPossThanGetPred(); - bool checkGetPredThanGetPoss(); + bool checkMoveAndSetSituation(); + bool checkGetPossThanGetPred(); + bool checkGetPredThanGetPoss(); // Virtual Functions - void prepareBestChoiceCalculation(); - void getValueOfSituation(unsigned int threadNo, float &floatValue, TwoBit &shortValue); - void setOpponentLevel(unsigned int threadNo, bool isOpponentLevel); - bool getOpponentLevel(unsigned int threadNo); - void deletePossibilities(unsigned int threadNo, void *pPossibilities); + void prepareBestChoiceCalculation(); + void getValueOfSituation(unsigned int threadNo, float &floatValue, TwoBit &shortValue); + void setOpponentLevel(unsigned int threadNo, bool isOpponentLevel); + bool getOpponentLevel(unsigned int threadNo); + void deletePossibilities(unsigned int threadNo, void *pPossibilities); unsigned int *getPossibilities(unsigned int threadNo, unsigned int *numPossibilities, bool *opponentsMove, void **pPossibilities); - void undo(unsigned int threadNo, unsigned int idPossibility, bool opponentsMove, void *pBackup, void *pPossibilities); - void move(unsigned int threadNo, unsigned int idPossibility, bool opponentsMove, void **pBackup, void *pPossibilities); - void printMoveInformation(unsigned int threadNo, unsigned int idPossibility, void *pPossibilities); - void storeValueOfMove(unsigned int threadNo, unsigned int idPossibility, void *pPossibilities, unsigned char value, unsigned int *freqValuesSubMoves, PlyInfoVarType plyInfo); - void getSymStateNumWithDoubles(unsigned int threadNo, unsigned int *numSymmetricStates, unsigned int **symStateNumbers); - void printBoard(unsigned int threadNo, unsigned char value); - string getOutputInformation(unsigned int layerNum); - unsigned int getPartnerLayer(unsigned int layerNum); - void prepareDatabaseCalculation(); - void wrapUpDatabaseCalculation(bool calculationAborted); + void undo(unsigned int threadNo, unsigned int idPossibility, bool opponentsMove, void *pBackup, void *pPossibilities); + void move(unsigned int threadNo, unsigned int idPossibility, bool opponentsMove, void **pBackup, void *pPossibilities); + void printMoveInformation(unsigned int threadNo, unsigned int idPossibility, void *pPossibilities); + void storeValueOfMove(unsigned int threadNo, unsigned int idPossibility, void *pPossibilities, unsigned char value, unsigned int *freqValuesSubMoves, PlyInfoVarType plyInfo); + void getSymStateNumWithDoubles(unsigned int threadNo, unsigned int *numSymmetricStates, unsigned int **symStateNumbers); + void printBoard(unsigned int threadNo, unsigned char value); + string getOutputInformation(unsigned int layerNum); + unsigned int getPartnerLayer(unsigned int layerNum); + void prepareDatabaseCalculation(); + void wrapUpDatabaseCalculation(bool calculationAborted); public: // Constructor / destructor @@ -231,14 +230,14 @@ public: ~PerfectAI(); // Functions - bool setDatabasePath(const char *directory); - void play(fieldStruct *theField, unsigned int *pushFrom, unsigned int *pushTo); - void getValueOfMoves(unsigned char *moveValue, unsigned int *freqValuesSubMoves, PlyInfoVarType *plyInfo, unsigned int *moveQuality, unsigned char &knotValue, PlyInfoVarType &bestAmountOfPlies); - void getField(unsigned int layerNum, unsigned int stateNumber, fieldStruct *field, bool *gameHasFinished); - void getLayerAndStateNumber(unsigned int &layerNum, unsigned int &stateNumber); + bool setDatabasePath(const char *directory); + void play(fieldStruct *theField, unsigned int *pushFrom, unsigned int *pushTo); + void getValueOfMoves(unsigned char *moveValue, unsigned int *freqValuesSubMoves, PlyInfoVarType *plyInfo, unsigned int *moveQuality, unsigned char &knotValue, PlyInfoVarType &bestAmountOfPlies); + void getField(unsigned int layerNum, unsigned int stateNumber, fieldStruct *field, bool *gameHasFinished); + void getLayerAndStateNumber(unsigned int &layerNum, unsigned int &stateNumber); // Testing functions - bool testLayers(unsigned int startTestFromLayer, unsigned int endTestAtLayer); + bool testLayers(unsigned int startTestFromLayer, unsigned int endTestAtLayer); }; #endif \ No newline at end of file diff --git a/src/perfect/position.cpp b/src/perfect/position.cpp index 0f2a6c75..c0271591 100644 --- a/src/perfect/position.cpp +++ b/src/perfect/position.cpp @@ -62,9 +62,12 @@ void Position::beginNewGame(MillAI *firstPlayerAI, MillAI *secondPlayerAI, int c initialField.createBoard(); // calc beginning player - if (currentPlayer == field.playerOne || currentPlayer == field.playerTwo) { + if (currentPlayer == field.playerOne || currentPlayer == field.playerTwo) + { beginningPlayer = currentPlayer; - } else { + } + else + { beginningPlayer = (rand() % 2) ? field.playerOne : field.playerTwo; } field.curPlayer->id = beginningPlayer; @@ -83,7 +86,7 @@ void Position::beginNewGame(MillAI *firstPlayerAI, MillAI *secondPlayerAI, int c //----------------------------------------------------------------------------- // Name: startSettingPhase() -// Desc: +// Desc: //----------------------------------------------------------------------------- bool Position::startSettingPhase(MillAI *firstPlayerAI, MillAI *secondPlayerAI, int currentPlayer, bool settingPhase) { @@ -103,8 +106,10 @@ void Position::setUpCalcPossibleMoves(Player *player) // locals unsigned int i, j, k, movingDirection; - for (player->numPossibleMoves = 0, i = 0; i < fieldStruct::size; i++) { - for (j = 0; j < fieldStruct::size; j++) { + for (player->numPossibleMoves = 0, i = 0; i < fieldStruct::size; i++) + { + for (j = 0; j < fieldStruct::size; j++) + { // is stone from player ? if (field.board[i] != player->id) @@ -115,7 +120,8 @@ void Position::setUpCalcPossibleMoves(Player *player) continue; // when current player has only 3 stones he is allowed to spring his stone - if (player->numStones > 3 || field.settingPhase) { + if (player->numStones > 3 || field.settingPhase) + { // determine moving direction for (k = 0, movingDirection = 4; k < 4; k++) @@ -135,7 +141,7 @@ void Position::setUpCalcPossibleMoves(Player *player) //----------------------------------------------------------------------------- // Name: setUpSetWarningAndMill() -// Desc: +// Desc: //----------------------------------------------------------------------------- void Position::setUpSetWarningAndMill(unsigned int stone, unsigned int firstNeighbour, unsigned int secondNeighbour) { @@ -143,7 +149,8 @@ void Position::setUpSetWarningAndMill(unsigned int stone, unsigned int firstNeig int rowOwner = field.board[stone]; // mill closed ? - if (rowOwner != field.squareIsFree && field.board[firstNeighbour] == rowOwner && field.board[secondNeighbour] == rowOwner) { + if (rowOwner != field.squareIsFree && field.board[firstNeighbour] == rowOwner && field.board[secondNeighbour] == rowOwner) + { field.stonePartOfMill[stone]++; field.stonePartOfMill[firstNeighbour]++; @@ -163,9 +170,12 @@ bool Position::put_piece(unsigned int pos, int player) Player *myPlayer = (player == field.curPlayer->id) ? field.curPlayer : field.oppPlayer; // check parameters - if (player != fieldStruct::playerOne && player != fieldStruct::playerTwo) return false; - if (pos >= fieldStruct::size) return false; - if (field.board[pos] != field.squareIsFree) return false; + if (player != fieldStruct::playerOne && player != fieldStruct::playerTwo) + return false; + if (pos >= fieldStruct::size) + return false; + if (field.board[pos] != field.squareIsFree) + return false; // set stone field.board[pos] = player; @@ -173,50 +183,63 @@ bool Position::put_piece(unsigned int pos, int player) field.stonesSet++; // setting phase finished ? - if (field.stonesSet == 18) field.settingPhase = false; + if (field.stonesSet == 18) + field.settingPhase = false; // calc possible moves setUpCalcPossibleMoves(field.curPlayer); setUpCalcPossibleMoves(field.oppPlayer); // zero - for (i = 0; i < fieldStruct::size; i++) field.stonePartOfMill[i] = 0; + for (i = 0; i < fieldStruct::size; i++) + field.stonePartOfMill[i] = 0; // go in every direction - for (i = 0; i < fieldStruct::size; i++) { + for (i = 0; i < fieldStruct::size; i++) + { setUpSetWarningAndMill(i, field.neighbour[i][0][0], field.neighbour[i][0][1]); setUpSetWarningAndMill(i, field.neighbour[i][1][0], field.neighbour[i][1][1]); } // since every mill was detected 3 times - for (i = 0; i < fieldStruct::size; i++) field.stonePartOfMill[i] /= 3; + for (i = 0; i < fieldStruct::size; i++) + field.stonePartOfMill[i] /= 3; // count completed mills - for (i = 0; i < fieldStruct::size; i++) { - if (field.board[i] == field.curPlayer->id) numberOfMillsCurrentPlayer += field.stonePartOfMill[i]; - else numberOfMillsOpponentPlayer += field.stonePartOfMill[i]; + for (i = 0; i < fieldStruct::size; i++) + { + if (field.board[i] == field.curPlayer->id) + numberOfMillsCurrentPlayer += field.stonePartOfMill[i]; + else + numberOfMillsOpponentPlayer += field.stonePartOfMill[i]; } numberOfMillsCurrentPlayer /= 3; numberOfMillsOpponentPlayer /= 3; // stonesSet & numStonesMissing - if (field.settingPhase) { + if (field.settingPhase) + { // ... This calculation is not correct! It is possible that some mills did not cause a stone removal. field.curPlayer->numStonesMissing = numberOfMillsOpponentPlayer; field.oppPlayer->numStonesMissing = numberOfMillsCurrentPlayer - field.stoneMustBeRemoved; field.stonesSet = field.curPlayer->numStones + field.oppPlayer->numStones + field.curPlayer->numStonesMissing + field.oppPlayer->numStonesMissing; - } else { + } + else + { field.stonesSet = 18; field.curPlayer->numStonesMissing = 9 - field.curPlayer->numStones; field.oppPlayer->numStonesMissing = 9 - field.oppPlayer->numStones; } // when opponent is unable to move than current player has won - if ((!field.curPlayer->numPossibleMoves) && (!field.settingPhase) - && (!field.stoneMustBeRemoved) && (field.curPlayer->numStones > 3)) winner = field.oppPlayer->id; - else if ((field.curPlayer->numStones < 3) && (!field.settingPhase)) winner = field.oppPlayer->id; - else if ((field.oppPlayer->numStones < 3) && (!field.settingPhase)) winner = field.curPlayer->id; - else winner = 0; + if ((!field.curPlayer->numPossibleMoves) && (!field.settingPhase) && (!field.stoneMustBeRemoved) && (field.curPlayer->numStones > 3)) + winner = field.oppPlayer->id; + else if ((field.curPlayer->numStones < 3) && (!field.settingPhase)) + winner = field.oppPlayer->id; + else if ((field.oppPlayer->numStones < 3) && (!field.settingPhase)) + winner = field.curPlayer->id; + else + winner = 0; // everything is ok return true; @@ -243,11 +266,15 @@ bool Position::getField(int *pField) unsigned int index; // if no log is available than no game is in progress and board is invalid - if (moveLogFrom == nullptr) return false; + if (moveLogFrom == nullptr) + return false; - for (index = 0; index < field.size; index++) { - if (field.warnings[index] != field.noWarning) pField[index] = (int)field.warnings[index]; - else pField[index] = field.board[index]; + for (index = 0; index < field.size; index++) + { + if (field.warnings[index] != field.noWarning) + pField[index] = (int)field.warnings[index]; + else + pField[index] = field.board[index]; } return true; @@ -263,7 +290,8 @@ void Position::getLog(unsigned int &numMovesDone, unsigned int *from, unsigned i numMovesDone = movesDone; - for (index = 0; index < movesDone; index++) { + for (index = 0; index < movesDone; index++) + { from[index] = moveLogFrom[index]; to[index] = moveLogTo[index]; } @@ -288,8 +316,10 @@ void Position::setNextPlayer() //----------------------------------------------------------------------------- bool Position::isCurrentPlayerHuman() { - if (field.curPlayer->id == field.playerOne) return (playerOneAI == nullptr) ? true : false; - else return (playerTwoAI == nullptr) ? true : false; + if (field.curPlayer->id == field.playerOne) + return (playerOneAI == nullptr) ? true : false; + else + return (playerTwoAI == nullptr) ? true : false; } //----------------------------------------------------------------------------- @@ -298,8 +328,10 @@ bool Position::isCurrentPlayerHuman() //----------------------------------------------------------------------------- bool Position::isOpponentPlayerHuman() { - if (field.oppPlayer->id == field.playerOne) return (playerOneAI == nullptr) ? true : false; - else return (playerTwoAI == nullptr) ? true : false; + if (field.oppPlayer->id == field.playerOne) + return (playerOneAI == nullptr) ? true : false; + else + return (playerTwoAI == nullptr) ? true : false; } //----------------------------------------------------------------------------- @@ -308,10 +340,12 @@ bool Position::isOpponentPlayerHuman() //----------------------------------------------------------------------------- void Position::setAI(int player, MillAI *AI) { - if (player == field.playerOne) { + if (player == field.playerOne) + { playerOneAI = AI; } - if (player == field.playerTwo) { + if (player == field.playerTwo) + { playerTwoAI = AI; } } @@ -327,7 +361,8 @@ void Position::getChoiceOfSpecialAI(MillAI *AI, unsigned int *pushFrom, unsigned *pushTo = field.size; theField.createBoard(); field.copyBoard(&theField); - if (AI != nullptr && (field.settingPhase || field.curPlayer->numPossibleMoves > 0) && winner == 0) AI->play(&theField, pushFrom, pushTo); + if (AI != nullptr && (field.settingPhase || field.curPlayer->numPossibleMoves > 0) && winner == 0) + AI->play(&theField, pushFrom, pushTo); theField.deleteBoard(); } @@ -343,11 +378,17 @@ void Position::getComputersChoice(unsigned int *pushFrom, unsigned int *pushTo) theField.createBoard(); field.copyBoard(&theField); - if ((field.settingPhase || field.curPlayer->numPossibleMoves > 0) && winner == 0) { - if (field.curPlayer->id == field.playerOne) { - if (playerOneAI != nullptr) playerOneAI->play(&theField, pushFrom, pushTo); - } else { - if (playerTwoAI != nullptr) playerTwoAI->play(&theField, pushFrom, pushTo); + if ((field.settingPhase || field.curPlayer->numPossibleMoves > 0) && winner == 0) + { + if (field.curPlayer->id == field.playerOne) + { + if (playerOneAI != nullptr) + playerOneAI->play(&theField, pushFrom, pushTo); + } + else + { + if (playerTwoAI != nullptr) + playerTwoAI->play(&theField, pushFrom, pushTo); } } @@ -364,23 +405,31 @@ bool Position::isNormalMovePossible(unsigned int from, unsigned int to, Player * unsigned int movingDirection, i; // parameter ok ? - if (from >= field.size) return false; - if (to >= field.size) return false; + if (from >= field.size) + return false; + if (to >= field.size) + return false; // is stone from player ? - if (field.board[from] != player->id) return false; + if (field.board[from] != player->id) + return false; // is destination free ? - if (field.board[to] != field.squareIsFree) return false; + if (field.board[to] != field.squareIsFree) + return false; // when current player has only 3 stones he is allowed to spring his stone - if (player->numStones > 3 || field.settingPhase) { + if (player->numStones > 3 || field.settingPhase) + { // determine moving direction - for (i = 0, movingDirection = 4; i < 4; i++) if (field.connectedSquare[from][i] == to) movingDirection = i; + for (i = 0, movingDirection = 4; i < 4; i++) + if (field.connectedSquare[from][i] == to) + movingDirection = i; // are both squares connected ? - if (movingDirection == 4) return false; + if (movingDirection == 4) + return false; } // everything is ok @@ -397,13 +446,18 @@ void Position::calcPossibleMoves(Player *player) unsigned int i, j; // zero - for (i = 0; i < MAX_NUM_POS_MOVES; i++) player->posTo[i] = field.size; - for (i = 0; i < MAX_NUM_POS_MOVES; i++) player->posFrom[i] = field.size; + for (i = 0; i < MAX_NUM_POS_MOVES; i++) + player->posTo[i] = field.size; + for (i = 0; i < MAX_NUM_POS_MOVES; i++) + player->posFrom[i] = field.size; // calc - for (player->numPossibleMoves = 0, i = 0; i < field.size; i++) { - for (j = 0; j < field.size; j++) { - if (isNormalMovePossible(i, j, player)) { + for (player->numPossibleMoves = 0, i = 0; i < field.size; i++) + { + for (j = 0; j < field.size; j++) + { + if (isNormalMovePossible(i, j, player)) + { player->posFrom[player->numPossibleMoves] = i; player->posTo[player->numPossibleMoves] = j; player->numPossibleMoves++; @@ -412,73 +466,88 @@ void Position::calcPossibleMoves(Player *player) } // stoneMoveAble - for (i = 0; i < field.size; i++) { - for (j = 0; j < 4; j++) { - if (field.board[i] == player->id) field.stoneMoveAble[i][j] = isNormalMovePossible(i, field.connectedSquare[i][j], player); - else field.stoneMoveAble[i][j] = false; + for (i = 0; i < field.size; i++) + { + for (j = 0; j < 4; j++) + { + if (field.board[i] == player->id) + field.stoneMoveAble[i][j] = isNormalMovePossible(i, field.connectedSquare[i][j], player); + else + field.stoneMoveAble[i][j] = false; } } } //----------------------------------------------------------------------------- // Name: setWarningAndMill() -// Desc: +// Desc: //----------------------------------------------------------------------------- void Position::setWarningAndMill(unsigned int stone, unsigned int firstNeighbour, unsigned int secondNeighbour, bool isNewStone) { // locals - int rowOwner = field.board[stone]; - unsigned int rowOwnerWarning = (rowOwner == field.playerOne) ? field.playerOneWarning : field.playerTwoWarning; + int rowOwner = field.board[stone]; + unsigned int rowOwnerWarning = (rowOwner == field.playerOne) ? field.playerOneWarning : field.playerTwoWarning; // mill closed ? - if (rowOwner != field.squareIsFree && field.board[firstNeighbour] == rowOwner && field.board[secondNeighbour] == rowOwner) { + if (rowOwner != field.squareIsFree && field.board[firstNeighbour] == rowOwner && field.board[secondNeighbour] == rowOwner) + { field.stonePartOfMill[stone]++; field.stonePartOfMill[firstNeighbour]++; field.stonePartOfMill[secondNeighbour]++; - if (isNewStone) field.stoneMustBeRemoved = 1; + if (isNewStone) + field.stoneMustBeRemoved = 1; } //warning ? - if (rowOwner != field.squareIsFree && field.board[firstNeighbour] == field.squareIsFree && field.board[secondNeighbour] == rowOwner) field.warnings[firstNeighbour] |= rowOwnerWarning; - if (rowOwner != field.squareIsFree && field.board[secondNeighbour] == field.squareIsFree && field.board[firstNeighbour] == rowOwner) field.warnings[secondNeighbour] |= rowOwnerWarning; + if (rowOwner != field.squareIsFree && field.board[firstNeighbour] == field.squareIsFree && field.board[secondNeighbour] == rowOwner) + field.warnings[firstNeighbour] |= rowOwnerWarning; + if (rowOwner != field.squareIsFree && field.board[secondNeighbour] == field.squareIsFree && field.board[firstNeighbour] == rowOwner) + field.warnings[secondNeighbour] |= rowOwnerWarning; } //----------------------------------------------------------------------------- // Name: updateMillsAndWarnings() -// Desc: +// Desc: //----------------------------------------------------------------------------- void Position::updateMillsAndWarnings(unsigned int newStone) { // locals - unsigned int i; - bool atLeastOneStoneRemoveAble; + unsigned int i; + bool atLeastOneStoneRemoveAble; // zero - for (i = 0; i < field.size; i++) field.stonePartOfMill[i] = 0; - for (i = 0; i < field.size; i++) field.warnings[i] = field.noWarning; + for (i = 0; i < field.size; i++) + field.stonePartOfMill[i] = 0; + for (i = 0; i < field.size; i++) + field.warnings[i] = field.noWarning; field.stoneMustBeRemoved = 0; // go in every direction - for (i = 0; i < field.size; i++) { + for (i = 0; i < field.size; i++) + { setWarningAndMill(i, field.neighbour[i][0][0], field.neighbour[i][0][1], i == newStone); setWarningAndMill(i, field.neighbour[i][1][0], field.neighbour[i][1][1], i == newStone); } // since every mill was detected 3 times - for (i = 0; i < field.size; i++) field.stonePartOfMill[i] /= 3; + for (i = 0; i < field.size; i++) + field.stonePartOfMill[i] /= 3; // no stone must be removed if each belongs to a mill - for (atLeastOneStoneRemoveAble = false, i = 0; i < field.size; i++) if (field.stonePartOfMill[i] == 0 && field.board[i] == field.oppPlayer->id) atLeastOneStoneRemoveAble = true; - if (!atLeastOneStoneRemoveAble) field.stoneMustBeRemoved = 0; + for (atLeastOneStoneRemoveAble = false, i = 0; i < field.size; i++) + if (field.stonePartOfMill[i] == 0 && field.board[i] == field.oppPlayer->id) + atLeastOneStoneRemoveAble = true; + if (!atLeastOneStoneRemoveAble) + field.stoneMustBeRemoved = 0; } //----------------------------------------------------------------------------- // Name: do_move() -// Desc: +// Desc: //----------------------------------------------------------------------------- -bool Position::do_move(unsigned int pushFrom, unsigned int pushTo) +bool Position::do_move(unsigned int pushFrom, unsigned int pushTo) { // avoid index override if (movesDone >= MAX_NUM_MOVES) @@ -489,7 +558,8 @@ bool Position::do_move(unsigned int pushFrom, unsigned int pushTo) return false; // handle the remove of a stone - if (field.stoneMustBeRemoved) { + if (field.stoneMustBeRemoved) + { // parameter ok ? if (pushFrom >= field.size) @@ -513,7 +583,8 @@ bool Position::do_move(unsigned int pushFrom, unsigned int pushTo) movesDone++; // is the game finished ? - if ((field.oppPlayer->numStones < 3) && (!field.settingPhase)) winner = field.curPlayer->id; + if ((field.oppPlayer->numStones < 3) && (!field.settingPhase)) + winner = field.curPlayer->id; // update warnings & mills updateMillsAndWarnings(field.size); @@ -523,16 +594,20 @@ bool Position::do_move(unsigned int pushFrom, unsigned int pushTo) calcPossibleMoves(field.oppPlayer); // is opponent unable to move ? - if (field.oppPlayer->numPossibleMoves == 0 && !field.settingPhase) winner = field.curPlayer->id; + if (field.oppPlayer->numPossibleMoves == 0 && !field.settingPhase) + winner = field.curPlayer->id; // next player - if (!field.stoneMustBeRemoved) setNextPlayer(); + if (!field.stoneMustBeRemoved) + setNextPlayer(); // everything is ok return true; // handle setting phase - } else if (field.settingPhase) { + } + else if (field.settingPhase) + { // parameter ok ? if (pushTo >= field.size) @@ -558,19 +633,24 @@ bool Position::do_move(unsigned int pushFrom, unsigned int pushTo) calcPossibleMoves(field.oppPlayer); // setting phase finished ? - if (field.stonesSet == 18) field.settingPhase = false; + if (field.stonesSet == 18) + field.settingPhase = false; // is opponent unable to move ? - if (field.oppPlayer->numPossibleMoves == 0 && !field.settingPhase) winner = field.curPlayer->id; + if (field.oppPlayer->numPossibleMoves == 0 && !field.settingPhase) + winner = field.curPlayer->id; // next player - if (!field.stoneMustBeRemoved) setNextPlayer(); + if (!field.stoneMustBeRemoved) + setNextPlayer(); // everything is ok return true; // normal move - } else { + } + else + { // is move possible ? if (!isNormalMovePossible(pushFrom, pushTo, field.curPlayer)) @@ -591,10 +671,12 @@ bool Position::do_move(unsigned int pushFrom, unsigned int pushTo) calcPossibleMoves(field.oppPlayer); // is opponent unable to move ? - if (field.oppPlayer->numPossibleMoves == 0 && !field.settingPhase) winner = field.curPlayer->id; + if (field.oppPlayer->numPossibleMoves == 0 && !field.settingPhase) + winner = field.curPlayer->id; // next player - if (!field.stoneMustBeRemoved) setNextPlayer(); + if (!field.stoneMustBeRemoved) + setNextPlayer(); // everything is ok return true; @@ -612,9 +694,12 @@ bool Position::setCurrentGameState(fieldStruct *curState) winner = 0; movesDone = 0; - if ((field.curPlayer->numStones < 3) && (!field.settingPhase)) winner = field.oppPlayer->id; - if ((field.oppPlayer->numStones < 3) && (!field.settingPhase)) winner = field.curPlayer->id; - if ((field.curPlayer->numPossibleMoves == 0) && (!field.settingPhase)) winner = field.oppPlayer->id; + if ((field.curPlayer->numStones < 3) && (!field.settingPhase)) + winner = field.oppPlayer->id; + if ((field.oppPlayer->numStones < 3) && (!field.settingPhase)) + winner = field.curPlayer->id; + if ((field.curPlayer->numPossibleMoves == 0) && (!field.settingPhase)) + winner = field.oppPlayer->id; return true; } @@ -628,43 +713,65 @@ bool Position::compareWithField(fieldStruct *compareField) unsigned int i, j; bool ret = true; - if (!comparePlayers(field.curPlayer, compareField->curPlayer)) { - cout << "error - curPlayer differs!" << endl; ret = false; + if (!comparePlayers(field.curPlayer, compareField->curPlayer)) + { + cout << "error - curPlayer differs!" << endl; + ret = false; } - if (!comparePlayers(field.oppPlayer, compareField->oppPlayer)) { - cout << "error - oppPlayer differs!" << endl; ret = false; + if (!comparePlayers(field.oppPlayer, compareField->oppPlayer)) + { + cout << "error - oppPlayer differs!" << endl; + ret = false; } - if (field.stonesSet != compareField->stonesSet) { - cout << "error - stonesSet differs!" << endl; ret = false; + if (field.stonesSet != compareField->stonesSet) + { + cout << "error - stonesSet differs!" << endl; + ret = false; } - if (field.settingPhase != compareField->settingPhase) { - cout << "error - settingPhase differs!" << endl; ret = false; + if (field.settingPhase != compareField->settingPhase) + { + cout << "error - settingPhase differs!" << endl; + ret = false; } - if (field.stoneMustBeRemoved != compareField->stoneMustBeRemoved) { - cout << "error - stoneMustBeRemoved differs!" << endl; ret = false; + if (field.stoneMustBeRemoved != compareField->stoneMustBeRemoved) + { + cout << "error - stoneMustBeRemoved differs!" << endl; + ret = false; } - for (i = 0; i < field.size; i++) { + for (i = 0; i < field.size; i++) + { - if (field.board[i] != compareField->board[i]) { - cout << "error - board[] differs!" << endl; ret = false; + if (field.board[i] != compareField->board[i]) + { + cout << "error - board[] differs!" << endl; + ret = false; } - if (field.warnings[i] != compareField->warnings[i]) { - cout << "error - warnings[] differs!" << endl; ret = false; + if (field.warnings[i] != compareField->warnings[i]) + { + cout << "error - warnings[] differs!" << endl; + ret = false; } - if (field.stonePartOfMill[i] != compareField->stonePartOfMill[i]) { - cout << "error - stonePart[] differs!" << endl; ret = false; + if (field.stonePartOfMill[i] != compareField->stonePartOfMill[i]) + { + cout << "error - stonePart[] differs!" << endl; + ret = false; } - for (j = 0; j < 4; j++) { + for (j = 0; j < 4; j++) + { - if (field.connectedSquare[i][j] != compareField->connectedSquare[i][j]) { - cout << "error - connectedSquare[] differs!" << endl; ret = false; + if (field.connectedSquare[i][j] != compareField->connectedSquare[i][j]) + { + cout << "error - connectedSquare[] differs!" << endl; + ret = false; } // if (board.stoneMoveAble[i][j] != compareField->stoneMoveAble[i][j]) { cout << "error - stoneMoveAble differs!" << endl; ret = false; } - if (field.neighbour[i][j / 2][j % 2] != compareField->neighbour[i][j / 2][j % 2]) { - cout << "error - neighbour differs!" << endl; ret = false; + if (field.neighbour[i][j / 2][j % 2] != compareField->neighbour[i][j / 2][j % 2]) + { + cout << "error - neighbour differs!" << endl; + ret = false; } } } @@ -681,20 +788,30 @@ bool Position::comparePlayers(Player *playerA, Player *playerB) // unsigned int i; bool ret = true; - if (playerA->numStonesMissing != playerB->numStonesMissing) { - cout << "error - numStonesMissing differs!" << endl; ret = false; + if (playerA->numStonesMissing != playerB->numStonesMissing) + { + cout << "error - numStonesMissing differs!" << endl; + ret = false; } - if (playerA->numStones != playerB->numStones) { - cout << "error - numStones differs!" << endl; ret = false; + if (playerA->numStones != playerB->numStones) + { + cout << "error - numStones differs!" << endl; + ret = false; } - if (playerA->id != playerB->id) { - cout << "error - id differs!" << endl; ret = false; + if (playerA->id != playerB->id) + { + cout << "error - id differs!" << endl; + ret = false; } - if (playerA->warning != playerB->warning) { - cout << "error - warning differs!" << endl; ret = false; + if (playerA->warning != playerB->warning) + { + cout << "error - warning differs!" << endl; + ret = false; } - if (playerA->numPossibleMoves != playerB->numPossibleMoves) { - cout << "error - numPossibleMoves differs!" << endl; ret = false; + if (playerA->numPossibleMoves != playerB->numPossibleMoves) + { + cout << "error - numPossibleMoves differs!" << endl; + ret = false; } // for (i=0; iposFrom[i] = playerB->posFrom[i]) return false; @@ -726,10 +843,12 @@ void Position::undo_move(void) unsigned int i; // at least one move must be done - if (movesDone) { + if (movesDone) + { // make backup of log - for (i = 0; i < movesDone; i++) { + for (i = 0; i < movesDone; i++) + { moveLogFrom_bak[i] = moveLogFrom[i]; moveLogTo_bak[i] = moveLogTo[i]; } @@ -740,7 +859,8 @@ void Position::undo_move(void) movesDone = 0; // and play again - for (i = 0; i < movesDone_bak - 1; i++) { + for (i = 0; i < movesDone_bak - 1; i++) + { do_move(moveLogFrom_bak[i], moveLogTo_bak[i]); } } @@ -752,14 +872,17 @@ void Position::undo_move(void) //----------------------------------------------------------------------------- // Name: calcNumberOfRestingStones() -// Desc: +// Desc: //----------------------------------------------------------------------------- void Position::calcNumberOfRestingStones(int &numWhiteStonesResting, int &numBlackStonesResting) { - if (getCurrentPlayer() == fieldStruct::playerTwo) { + if (getCurrentPlayer() == fieldStruct::playerTwo) + { numWhiteStonesResting = fieldStruct::numStonesPerPlayer - field.curPlayer->numStonesMissing - field.curPlayer->numStones; numBlackStonesResting = fieldStruct::numStonesPerPlayer - field.oppPlayer->numStonesMissing - field.oppPlayer->numStones; - } else { + } + else + { numWhiteStonesResting = fieldStruct::numStonesPerPlayer - field.oppPlayer->numStonesMissing - field.oppPlayer->numStones; numBlackStonesResting = fieldStruct::numStonesPerPlayer - field.curPlayer->numStonesMissing - field.curPlayer->numStones; } diff --git a/src/perfect/position.h b/src/perfect/position.h index 5354667c..50824670 100644 --- a/src/perfect/position.h +++ b/src/perfect/position.h @@ -6,7 +6,6 @@ https://github.com/madweasel/madweasels-cpp \*********************************************************************/ - #ifndef MUEHLE_H #define MUEHLE_H @@ -18,16 +17,28 @@ #include "types.h" - - using namespace std; /*** Konstanten ******************************************************/ -#define MAX_NUM_MOVES 10000 +#define MAX_NUM_MOVES 10000 /*** Makros ******************************************************/ -#define SAFE_DELETE(p) { if(p) { delete (p); (p)=nullptr; } } -#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=nullptr; } } +#define SAFE_DELETE(p) \ + { \ + if (p) \ + { \ + delete (p); \ + (p) = nullptr; \ + } \ + } +#define SAFE_DELETE_ARRAY(p) \ + { \ + if (p) \ + { \ + delete[](p); \ + (p) = nullptr; \ + } \ + } /*** Klassen *********************************************************/ @@ -35,21 +46,21 @@ class Position { private: // Variables - unsigned int *moveLogFrom, *moveLogTo, movesDone; // array containing the history of moves done - MillAI *playerOneAI; // class-pointer to the AI of player one - MillAI *playerTwoAI; // class-pointer to the AI of player two - fieldStruct field; // current board - fieldStruct initialField; // undo of the last move is done by setting the initial board und performing all moves saved in history - int winner; // playerId of the player who has won the game. zero if game is still running. - int beginningPlayer; // playerId of the player who makes the first move + unsigned int *moveLogFrom, *moveLogTo, movesDone; // array containing the history of moves done + MillAI *playerOneAI; // class-pointer to the AI of player one + MillAI *playerTwoAI; // class-pointer to the AI of player two + fieldStruct field; // current board + fieldStruct initialField; // undo of the last move is done by setting the initial board und performing all moves saved in history + int winner; // playerId of the player who has won the game. zero if game is still running. + int beginningPlayer; // playerId of the player who makes the first move // Functions - void exit(); - void setNextPlayer(); - void calcPossibleMoves(Player *player); - void updateMillsAndWarnings(unsigned int newStone); - bool isNormalMovePossible(unsigned int from, unsigned int to, Player *player); - void setWarningAndMill(unsigned int stone, unsigned int firstNeighbour, unsigned int secondNeighbour, bool isNewStone); + void exit(); + void setNextPlayer(); + void calcPossibleMoves(Player *player); + void updateMillsAndWarnings(unsigned int newStone); + bool isNormalMovePossible(unsigned int from, unsigned int to, Player *player); + void setWarningAndMill(unsigned int stone, unsigned int firstNeighbour, unsigned int secondNeighbour, bool isNewStone); public: // Constructor / destructor @@ -57,73 +68,72 @@ public: ~Position(); // Functions - void undo_move(); - void beginNewGame(MillAI *firstPlayerAI, MillAI *secondPlayerAI, int currentPlayer); - void setAI(int player, MillAI *AI); - bool do_move(unsigned int pushFrom, unsigned int pushTo); - void getComputersChoice(unsigned int *pushFrom, unsigned int *pushTo); - bool setCurrentGameState(fieldStruct *curState); - bool compareWithField(fieldStruct *compareField); - bool comparePlayers(Player *playerA, Player *playerB); - void printBoard(); - bool startSettingPhase(MillAI *firstPlayerAI, MillAI *secondPlayerAI, int currentPlayer, bool settingPhase); - bool put_piece(unsigned int pos, int player); - bool settingPhaseHasFinished(); - void getChoiceOfSpecialAI(MillAI *AI, unsigned int *pushFrom, unsigned int *pushTo); - void setUpCalcPossibleMoves(Player *player); - void setUpSetWarningAndMill(unsigned int stone, unsigned int firstNeighbour, unsigned int secondNeighbour); - void calcNumberOfRestingStones(int &numWhiteStonesResting, int &numBlackStonesResting); + void undo_move(); + void beginNewGame(MillAI *firstPlayerAI, MillAI *secondPlayerAI, int currentPlayer); + void setAI(int player, MillAI *AI); + bool do_move(unsigned int pushFrom, unsigned int pushTo); + void getComputersChoice(unsigned int *pushFrom, unsigned int *pushTo); + bool setCurrentGameState(fieldStruct *curState); + bool compareWithField(fieldStruct *compareField); + bool comparePlayers(Player *playerA, Player *playerB); + void printBoard(); + bool startSettingPhase(MillAI *firstPlayerAI, MillAI *secondPlayerAI, int currentPlayer, bool settingPhase); + bool put_piece(unsigned int pos, int player); + bool settingPhaseHasFinished(); + void getChoiceOfSpecialAI(MillAI *AI, unsigned int *pushFrom, unsigned int *pushTo); + void setUpCalcPossibleMoves(Player *player); + void setUpSetWarningAndMill(unsigned int stone, unsigned int firstNeighbour, unsigned int secondNeighbour); + void calcNumberOfRestingStones(int &numWhiteStonesResting, int &numBlackStonesResting); // getter - void getLog(unsigned int &numMovesDone, unsigned int *from, unsigned int *to); - bool getField(int *pField); - bool isCurrentPlayerHuman(); - bool isOpponentPlayerHuman(); - bool inSettingPhase() + void getLog(unsigned int &numMovesDone, unsigned int *from, unsigned int *to); + bool getField(int *pField); + bool isCurrentPlayerHuman(); + bool isOpponentPlayerHuman(); + bool inSettingPhase() { return field.settingPhase; } - unsigned int mustStoneBeRemoved() + unsigned int mustStoneBeRemoved() { return field.stoneMustBeRemoved; } - int getWinner() + int getWinner() { return winner; } - int getCurrentPlayer() + int getCurrentPlayer() { return field.curPlayer->id; } - unsigned int getLastMoveFrom() + unsigned int getLastMoveFrom() { return (movesDone ? moveLogFrom[movesDone - 1] : field.size); } - unsigned int getLastMoveTo() + unsigned int getLastMoveTo() { return (movesDone ? moveLogTo[movesDone - 1] : field.size); } - unsigned int getMovesDone() + unsigned int getMovesDone() { return movesDone; } - unsigned int getNumStonesSet() + unsigned int getNumStonesSet() { return field.stonesSet; } - int getBeginningPlayer() + int getBeginningPlayer() { return beginningPlayer; } - unsigned int getNumStonOfCurPlayer() + unsigned int getNumStonOfCurPlayer() { return field.curPlayer->numStones; } - unsigned int getNumStonOfOppPlayer() + unsigned int getNumStonOfOppPlayer() { return field.oppPlayer->numStones; } }; #endif - diff --git a/src/perfect/randomAI.cpp b/src/perfect/randomAI.cpp index b535f752..be963f55 100644 --- a/src/perfect/randomAI.cpp +++ b/src/perfect/randomAI.cpp @@ -25,55 +25,68 @@ RandomAI::RandomAI() RandomAI::~RandomAI() { // Locals - } //----------------------------------------------------------------------------- // Name: play() -// Desc: +// Desc: //----------------------------------------------------------------------------- void RandomAI::play(fieldStruct *theField, unsigned int *pushFrom, unsigned int *pushTo) { // locals - unsigned int from, to, direction; - bool allowedToSpring = (theField->curPlayer->numStones == 3) ? true : false; + unsigned int from, to, direction; + bool allowedToSpring = (theField->curPlayer->numStones == 3) ? true : false; // must stone be removed ? - if (theField->stoneMustBeRemoved) { + if (theField->stoneMustBeRemoved) + { // search a stone from the enemy - do { + do + { from = rand() % theField->size; to = theField->size; } while (theField->board[from] != theField->oppPlayer->id || theField->stonePartOfMill[from]); // still in setting phase ? - } else if (theField->settingPhase) { + } + else if (theField->settingPhase) + { // search a free square - do { + do + { from = theField->size; to = rand() % theField->size; } while (theField->board[to] != theField->squareIsFree); // try to push randomly - } else { + } + else + { - do { + do + { // search an own stone - do { + do + { from = rand() % theField->size; } while (theField->board[from] != theField->curPlayer->id); // select a free square - if (allowedToSpring) { - do { + if (allowedToSpring) + { + do + { to = rand() % theField->size; } while (theField->board[to] != theField->squareIsFree); // select a connected square - } else { - do { + } + else + { + do + { direction = rand() % 4; to = theField->connectedSquare[from][direction]; } while (to == theField->size); diff --git a/src/perfect/strLib.cpp b/src/perfect/strLib.cpp index 33ba0f6c..b5e12a9c 100644 --- a/src/perfect/strLib.cpp +++ b/src/perfect/strLib.cpp @@ -10,7 +10,7 @@ //----------------------------------------------------------------------------- // Name: hibit() -// Desc: +// Desc: //----------------------------------------------------------------------------- int MyString::hibit(unsigned int n) { @@ -24,7 +24,7 @@ int MyString::hibit(unsigned int n) //----------------------------------------------------------------------------- // Name: MyString() -// Desc: +// Desc: //----------------------------------------------------------------------------- MyString::MyString() { @@ -32,7 +32,7 @@ MyString::MyString() //----------------------------------------------------------------------------- // Name: MyString() -// Desc: +// Desc: //----------------------------------------------------------------------------- MyString::MyString(const char *cStr) { @@ -41,7 +41,7 @@ MyString::MyString(const char *cStr) //----------------------------------------------------------------------------- // Name: MyString() -// Desc: +// Desc: //----------------------------------------------------------------------------- MyString::MyString(const WCHAR *cStr) { @@ -50,15 +50,19 @@ MyString::MyString(const WCHAR *cStr) //----------------------------------------------------------------------------- // Name: MyString() -// Desc: +// Desc: //----------------------------------------------------------------------------- MyString::~MyString() { - if (strA != nullptr) { - delete[] strA; strA = nullptr; + if (strA != nullptr) + { + delete[] strA; + strA = nullptr; } - if (strW != nullptr) { - delete[] strW; strW = nullptr; + if (strW != nullptr) + { + delete[] strW; + strW = nullptr; } strW = nullptr; strA = nullptr; @@ -68,7 +72,7 @@ MyString::~MyString() //----------------------------------------------------------------------------- // Name: c_strA() -// Desc: +// Desc: //----------------------------------------------------------------------------- const char *MyString::c_strA() { @@ -77,7 +81,7 @@ const char *MyString::c_strA() //----------------------------------------------------------------------------- // Name: c_strW() -// Desc: +// Desc: //----------------------------------------------------------------------------- const WCHAR *MyString::c_strW() { @@ -86,7 +90,7 @@ const WCHAR *MyString::c_strW() //----------------------------------------------------------------------------- // Name: assign() -// Desc: +// Desc: //----------------------------------------------------------------------------- MyString &MyString::assign(const char *cStr) { @@ -95,9 +99,12 @@ MyString &MyString::assign(const char *cStr) size_t newLength = strlen(cStr); size_t newReserved = (size_t)hibit((unsigned int)newLength) * 2; - if (reserved < newReserved) this->~MyString(); - if (strA == nullptr) strA = new char[newReserved]; - if (strW == nullptr) strW = new WCHAR[newReserved]; + if (reserved < newReserved) + this->~MyString(); + if (strA == nullptr) + strA = new char[newReserved]; + if (strW == nullptr) + strW = new WCHAR[newReserved]; reserved = newReserved; length = newLength; @@ -110,7 +117,7 @@ MyString &MyString::assign(const char *cStr) //----------------------------------------------------------------------------- // Name: assign() -// Desc: +// Desc: //----------------------------------------------------------------------------- MyString &MyString::assign(const WCHAR *cStr) { @@ -119,9 +126,12 @@ MyString &MyString::assign(const WCHAR *cStr) size_t newLength = wcslen(cStr); size_t newReserved = (size_t)hibit((unsigned int)newLength) * 2; - if (reserved < newReserved) this->~MyString(); - if (strA == nullptr) strA = new char[newReserved]; - if (strW == nullptr) strW = new WCHAR[newReserved]; + if (reserved < newReserved) + this->~MyString(); + if (strA == nullptr) + strA = new char[newReserved]; + if (strW == nullptr) + strW = new WCHAR[newReserved]; reserved = newReserved; length = newLength; @@ -139,41 +149,43 @@ MyString &MyString::assign(const WCHAR *cStr) bool readAsciiData(HANDLE hFile, double *pData, unsigned int numValues, unsigned char decimalSeperator, unsigned char columnSeparator) { // constants - const unsigned int maxValueLengthInBytes = 32; - const unsigned int bufferSize = 1000; + const unsigned int maxValueLengthInBytes = 32; + const unsigned int bufferSize = 1000; // locals - DWORD dwBytesRead; - unsigned char buffer[bufferSize]; + DWORD dwBytesRead; + unsigned char buffer[bufferSize]; unsigned char *curByte = &buffer[0]; - unsigned int curReadValue = 0; - unsigned int actualBufferSize = 0; - unsigned int curBufferPos = bufferSize; - unsigned int decimalPos = 0; - int integralValue = 0; // ACHTUNG: Erlaubt nur 8 Vorkommastellen - int fractionalValue = 0; // ACHTUNG: Erlaubt nur 8 Nachkommastellen - int exponentialValue = 1; - bool valIsNegativ = false; - bool expIsNegativ = false; - bool decimalPlace = false; - bool exponent = false; - double fractionalFactor[] = { 0, - 0.1, - 0.01, - 0.001, - 0.0001, - 0.00001, - 0.000001, - 0.0000001, - 0.00000001, - 0.000000001, - 0.0000000001 }; + unsigned int curReadValue = 0; + unsigned int actualBufferSize = 0; + unsigned int curBufferPos = bufferSize; + unsigned int decimalPos = 0; + int integralValue = 0; // ACHTUNG: Erlaubt nur 8 Vorkommastellen + int fractionalValue = 0; // ACHTUNG: Erlaubt nur 8 Nachkommastellen + int exponentialValue = 1; + bool valIsNegativ = false; + bool expIsNegativ = false; + bool decimalPlace = false; + bool exponent = false; + double fractionalFactor[] = {0, + 0.1, + 0.01, + 0.001, + 0.0001, + 0.00001, + 0.000001, + 0.0000001, + 0.00000001, + 0.000000001, + 0.0000000001}; // read each value - do { + do + { // read from buffer if necessary - if (curBufferPos >= bufferSize - maxValueLengthInBytes) { + if (curBufferPos >= bufferSize - maxValueLengthInBytes) + { memcpy(&buffer[0], &buffer[curBufferPos], bufferSize - curBufferPos); ReadFile(hFile, &buffer[bufferSize - curBufferPos], curBufferPos, &dwBytesRead, nullptr); actualBufferSize = bufferSize - curBufferPos + dwBytesRead; @@ -182,105 +194,233 @@ bool readAsciiData(HANDLE hFile, double *pData, unsigned int numValues, unsigned } // process current byte - switch (*curByte) { - case '-': if (exponent) { - expIsNegativ = true; - } else { - valIsNegativ = true; - } break; - case '+': /* ignore */ break; - case 'e': case 'E': exponent = true; decimalPlace = false; break; - case '0': if (decimalPlace) { - fractionalValue *= 10; fractionalValue += 0; decimalPos++; - } else if (exponent) { - exponentialValue *= 10; exponentialValue += 0; - } else { - integralValue *= 10; integralValue += 0; - } break; - case '1': if (decimalPlace) { - fractionalValue *= 10; fractionalValue += 1; decimalPos++; - } else if (exponent) { - exponentialValue *= 10; exponentialValue += 1; - } else { - integralValue *= 10; integralValue += 1; - } break; - case '2': if (decimalPlace) { - fractionalValue *= 10; fractionalValue += 2; decimalPos++; - } else if (exponent) { - exponentialValue *= 10; exponentialValue += 2; - } else { - integralValue *= 10; integralValue += 2; - } break; - case '3': if (decimalPlace) { - fractionalValue *= 10; fractionalValue += 3; decimalPos++; - } else if (exponent) { - exponentialValue *= 10; exponentialValue += 3; - } else { - integralValue *= 10; integralValue += 3; - } break; - case '4': if (decimalPlace) { - fractionalValue *= 10; fractionalValue += 4; decimalPos++; - } else if (exponent) { - exponentialValue *= 10; exponentialValue += 4; - } else { - integralValue *= 10; integralValue += 4; - } break; - case '5': if (decimalPlace) { - fractionalValue *= 10; fractionalValue += 5; decimalPos++; - } else if (exponent) { - exponentialValue *= 10; exponentialValue += 5; - } else { - integralValue *= 10; integralValue += 5; - } break; - case '6': if (decimalPlace) { - fractionalValue *= 10; fractionalValue += 6; decimalPos++; - } else if (exponent) { - exponentialValue *= 10; exponentialValue += 6; - } else { - integralValue *= 10; integralValue += 6; - } break; - case '7': if (decimalPlace) { - fractionalValue *= 10; fractionalValue += 7; decimalPos++; - } else if (exponent) { - exponentialValue *= 10; exponentialValue += 7; - } else { - integralValue *= 10; integralValue += 7; - } break; - case '8': if (decimalPlace) { - fractionalValue *= 10; fractionalValue += 8; decimalPos++; - } else if (exponent) { - exponentialValue *= 10; exponentialValue += 8; - } else { - integralValue *= 10; integralValue += 8; - } break; - case '9': if (decimalPlace) { - fractionalValue *= 10; fractionalValue += 9; decimalPos++; - } else if (exponent) { - exponentialValue *= 10; exponentialValue += 9; - } else { - integralValue *= 10; integralValue += 9; - } break; + switch (*curByte) + { + case '-': + if (exponent) + { + expIsNegativ = true; + } + else + { + valIsNegativ = true; + } + break; + case '+': /* ignore */ + break; + case 'e': + case 'E': + exponent = true; + decimalPlace = false; + break; + case '0': + if (decimalPlace) + { + fractionalValue *= 10; + fractionalValue += 0; + decimalPos++; + } + else if (exponent) + { + exponentialValue *= 10; + exponentialValue += 0; + } + else + { + integralValue *= 10; + integralValue += 0; + } + break; + case '1': + if (decimalPlace) + { + fractionalValue *= 10; + fractionalValue += 1; + decimalPos++; + } + else if (exponent) + { + exponentialValue *= 10; + exponentialValue += 1; + } + else + { + integralValue *= 10; + integralValue += 1; + } + break; + case '2': + if (decimalPlace) + { + fractionalValue *= 10; + fractionalValue += 2; + decimalPos++; + } + else if (exponent) + { + exponentialValue *= 10; + exponentialValue += 2; + } + else + { + integralValue *= 10; + integralValue += 2; + } + break; + case '3': + if (decimalPlace) + { + fractionalValue *= 10; + fractionalValue += 3; + decimalPos++; + } + else if (exponent) + { + exponentialValue *= 10; + exponentialValue += 3; + } + else + { + integralValue *= 10; + integralValue += 3; + } + break; + case '4': + if (decimalPlace) + { + fractionalValue *= 10; + fractionalValue += 4; + decimalPos++; + } + else if (exponent) + { + exponentialValue *= 10; + exponentialValue += 4; + } + else + { + integralValue *= 10; + integralValue += 4; + } + break; + case '5': + if (decimalPlace) + { + fractionalValue *= 10; + fractionalValue += 5; + decimalPos++; + } + else if (exponent) + { + exponentialValue *= 10; + exponentialValue += 5; + } + else + { + integralValue *= 10; + integralValue += 5; + } + break; + case '6': + if (decimalPlace) + { + fractionalValue *= 10; + fractionalValue += 6; + decimalPos++; + } + else if (exponent) + { + exponentialValue *= 10; + exponentialValue += 6; + } + else + { + integralValue *= 10; + integralValue += 6; + } + break; + case '7': + if (decimalPlace) + { + fractionalValue *= 10; + fractionalValue += 7; + decimalPos++; + } + else if (exponent) + { + exponentialValue *= 10; + exponentialValue += 7; + } + else + { + integralValue *= 10; + integralValue += 7; + } + break; + case '8': + if (decimalPlace) + { + fractionalValue *= 10; + fractionalValue += 8; + decimalPos++; + } + else if (exponent) + { + exponentialValue *= 10; + exponentialValue += 8; + } + else + { + integralValue *= 10; + integralValue += 8; + } + break; + case '9': + if (decimalPlace) + { + fractionalValue *= 10; + fractionalValue += 9; + decimalPos++; + } + else if (exponent) + { + exponentialValue *= 10; + exponentialValue += 9; + } + else + { + integralValue *= 10; + integralValue += 9; + } + break; default: - if (*curByte == decimalSeperator) { + if (*curByte == decimalSeperator) + { decimalPlace = true; exponent = false; - } else if (*curByte == columnSeparator) { + } + else if (*curByte == columnSeparator) + { // everything ok? - if (decimalPos > 8) { + if (decimalPos > 8) + { cout << "ERROR in function readAsciiData(): Too many digits on decimal place. Maximum is 8 !" << endl; return false; } // calc final value (*pData) = integralValue; - if (decimalPos) { + if (decimalPos) + { (*pData) += fractionalValue * fractionalFactor[decimalPos]; } - if (valIsNegativ) { + if (valIsNegativ) + { (*pData) *= -1; } - if (exponent) { + if (exponent) + { (*pData) *= pow(10, expIsNegativ ? -1 * exponentialValue : 1); } @@ -297,8 +437,9 @@ bool readAsciiData(HANDLE hFile, double *pData, unsigned int numValues, unsigned // save value pData++; curReadValue++; - - } else { + } + else + { // do nothing } break; @@ -309,7 +450,8 @@ bool readAsciiData(HANDLE hFile, double *pData, unsigned int numValues, unsigned curByte++; // buffer overrun? - if (curBufferPos >= actualBufferSize) return false; + if (curBufferPos >= actualBufferSize) + return false; } while (curReadValue < numValues); diff --git a/src/perfect/strLib.h b/src/perfect/strLib.h index 1428d3b5..b452abdb 100644 --- a/src/perfect/strLib.h +++ b/src/perfect/strLib.h @@ -24,17 +24,15 @@ bool readAsciiData(HANDLE hFile, double *pData, unsigned int numValues, unsigned class MyString { private: - // variables WCHAR *strW = nullptr; char *strA = nullptr; - size_t length = 0; - size_t reserved = 0; + size_t length = 0; + size_t reserved = 0; // functions public: - // functions MyString(); MyString(const char *cStr); @@ -46,7 +44,7 @@ public: MyString &assign(const char *cStr); MyString &assign(const WCHAR *cStr); - static int hibit(unsigned int n); + static int hibit(unsigned int n); }; #endif diff --git a/src/perfect/threadManager.cpp b/src/perfect/threadManager.cpp index 9e48e602..cac5a101 100644 --- a/src/perfect/threadManager.cpp +++ b/src/perfect/threadManager.cpp @@ -15,8 +15,8 @@ ThreadManager::ThreadManager() { // locals - unsigned int curThreadNo; - SYSTEM_INFO m_si = { 0 }; + unsigned int curThreadNo; + SYSTEM_INFO m_si = {0}; GetSystemInfo(&m_si); @@ -32,7 +32,8 @@ ThreadManager::ThreadManager() InitializeCriticalSection(&csBarrier); hEventBarrierPassedByEveryBody = CreateEvent(nullptr, true, false, nullptr); - for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) { + for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) + { hThread[curThreadNo] = nullptr; threadId[curThreadNo] = 0; hBarrier[curThreadNo] = CreateEvent(nullptr, false, false, nullptr); @@ -46,56 +47,66 @@ ThreadManager::ThreadManager() ThreadManager::~ThreadManager() { // locals - unsigned int curThreadNo; + unsigned int curThreadNo; - for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) { + for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) + { CloseHandle(hBarrier[curThreadNo]); } DeleteCriticalSection(&csBarrier); CloseHandle(hEventBarrierPassedByEveryBody); - if (hBarrier != nullptr) delete[] hBarrier; hBarrier = nullptr; - if (hThread != nullptr) delete[] hThread; hThread = nullptr; - if (threadId != nullptr) delete[] threadId; threadId = nullptr; + if (hBarrier != nullptr) + delete[] hBarrier; + hBarrier = nullptr; + if (hThread != nullptr) + delete[] hThread; + hThread = nullptr; + if (threadId != nullptr) + delete[] threadId; + threadId = nullptr; } //----------------------------------------------------------------------------- // Name: waitForOtherThreads() -// Desc: +// Desc: //----------------------------------------------------------------------------- void ThreadManager::waitForOtherThreads(unsigned int threadNo) { // wait if other threads are still waiting at the barrier -//cout << endl << "thread=" << threadNo << ", numThreadsPassedBarrier= " << numThreadsPassedBarrier << ": " << "while (numThreadsPassedBarrier>0)"; - if (numThreadsPassedBarrier > 0) { + //cout << endl << "thread=" << threadNo << ", numThreadsPassedBarrier= " << numThreadsPassedBarrier << ": " << "while (numThreadsPassedBarrier>0)"; + if (numThreadsPassedBarrier > 0) + { WaitForSingleObject(hEventBarrierPassedByEveryBody, INFINITE); } // a simple while (numThreadsPassedBarrier>0) {}; does not work, since the variable 'numThreadsPassedBarrier' is not updated, due to compiler optimizations // set signal that barrier is reached -//cout << endl << "thread=" << threadNo << ", numThreadsPassedBarrier= " << numThreadsPassedBarrier << ": " << "SetEvent()"; + //cout << endl << "thread=" << threadNo << ", numThreadsPassedBarrier= " << numThreadsPassedBarrier << ": " << "SetEvent()"; SetEvent(hBarrier[threadNo]); // enter the barrier one by one -//cout << endl << "thread=" << threadNo << ", numThreadsPassedBarrier= " << numThreadsPassedBarrier << ": " << "EnterCriticalSection()"; + //cout << endl << "thread=" << threadNo << ", numThreadsPassedBarrier= " << numThreadsPassedBarrier << ": " << "EnterCriticalSection()"; EnterCriticalSection(&csBarrier); // if the first one which entered, then wait until other threads - if (numThreadsPassedBarrier == 0) { + if (numThreadsPassedBarrier == 0) + { //cout << endl << "thread=" << threadNo << ", numThreadsPassedBarrier= " << numThreadsPassedBarrier << ": " << "WaitForMultipleObjects()"; WaitForMultipleObjects(numThreads, hBarrier, TRUE, INFINITE); ResetEvent(hEventBarrierPassedByEveryBody); } // count threads which passed the barrier -//cout << endl << "thread=" << threadNo << ", numThreadsPassedBarrier= " << numThreadsPassedBarrier << ": " << "numThreadsPassedBarrier++"; + //cout << endl << "thread=" << threadNo << ", numThreadsPassedBarrier= " << numThreadsPassedBarrier << ": " << "numThreadsPassedBarrier++"; numThreadsPassedBarrier++; // the last one closes the door -//cout << endl << "thread=" << threadNo << ", numThreadsPassedBarrier= " << numThreadsPassedBarrier << ": " << "if (numThreadsPassedBarrier == numThreads) numThreadsPassedBarrier = 0"; - if (numThreadsPassedBarrier == numThreads) { + //cout << endl << "thread=" << threadNo << ", numThreadsPassedBarrier= " << numThreadsPassedBarrier << ": " << "if (numThreadsPassedBarrier == numThreads) numThreadsPassedBarrier = 0"; + if (numThreadsPassedBarrier == numThreads) + { numThreadsPassedBarrier = 0; SetEvent(hEventBarrierPassedByEveryBody); } @@ -106,7 +117,7 @@ void ThreadManager::waitForOtherThreads(unsigned int threadNo) //----------------------------------------------------------------------------- // Name: getNumThreads() -// Desc: +// Desc: //----------------------------------------------------------------------------- unsigned int ThreadManager::getNumThreads() { @@ -115,20 +126,24 @@ unsigned int ThreadManager::getNumThreads() //----------------------------------------------------------------------------- // Name: setNumThreads() -// Desc: +// Desc: //----------------------------------------------------------------------------- bool ThreadManager::setNumThreads(unsigned int newNumThreads) { // cancel if any thread running EnterCriticalSection(&csBarrier); - for (unsigned int curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) { - if (hThread[curThreadNo]) return false; + for (unsigned int curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) + { + if (hThread[curThreadNo]) + return false; } - for (unsigned int curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) { + for (unsigned int curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) + { CloseHandle(hBarrier[curThreadNo]); } numThreads = newNumThreads; - for (unsigned int curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) { + for (unsigned int curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) + { hBarrier[curThreadNo] = CreateEvent(nullptr, false, false, nullptr); } LeaveCriticalSection(&csBarrier); @@ -137,17 +152,21 @@ bool ThreadManager::setNumThreads(unsigned int newNumThreads) //----------------------------------------------------------------------------- // Name: pauseExecution() -// Desc: +// Desc: //----------------------------------------------------------------------------- void ThreadManager::pauseExecution() { - for (unsigned int curThread = 0; curThread < numThreads; curThread++) { + for (unsigned int curThread = 0; curThread < numThreads; curThread++) + { // unsuspend all threads - if (!executionPaused) { + if (!executionPaused) + { SuspendThread(hThread[curThread]); // suspend all threads - } else { + } + else + { ResumeThread(hThread[curThread]); } } @@ -163,14 +182,15 @@ void ThreadManager::cancelExecution() { termineAllThreads = true; executionCancelled = true; - if (executionPaused) { + if (executionPaused) + { pauseExecution(); } } //----------------------------------------------------------------------------- // Name: uncancelExecution() -// Desc: +// Desc: //----------------------------------------------------------------------------- void ThreadManager::uncancelExecution() { @@ -179,7 +199,7 @@ void ThreadManager::uncancelExecution() //----------------------------------------------------------------------------- // Name: wasExecutionCancelled() -// Desc: +// Desc: //----------------------------------------------------------------------------- bool ThreadManager::wasExecutionCancelled() { @@ -193,11 +213,13 @@ bool ThreadManager::wasExecutionCancelled() unsigned int ThreadManager::getThreadNumber() { // locals - DWORD curThreadId = GetCurrentThreadId(); - unsigned int curThreadNo; + DWORD curThreadId = GetCurrentThreadId(); + unsigned int curThreadNo; - for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) { - if (curThreadId == threadId[curThreadNo]) { + for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) + { + if (curThreadId == threadId[curThreadNo]) + { return curThreadNo; } } @@ -208,26 +230,30 @@ unsigned int ThreadManager::getThreadNumber() // Name: executeInParallel() // Desc: lpParameter is an array of size numThreads. //----------------------------------------------------------------------------- -unsigned int ThreadManager::executeInParallel(DWORD threadProc(void *pParameter), void *pParameter, unsigned int parameterStructSize) +unsigned int ThreadManager::executeInParallel(DWORD threadProc(void *pParameter), void *pParameter, unsigned int parameterStructSize) { // locals - unsigned int curThreadNo; - SIZE_T dwStackSize = 0; + unsigned int curThreadNo; + SIZE_T dwStackSize = 0; // parameters ok? - if (pParameter == nullptr) return TM_RETURN_VALUE_INVALID_PARAM; + if (pParameter == nullptr) + return TM_RETURN_VALUE_INVALID_PARAM; // globals termineAllThreads = false; // create threads - for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) { + for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) + { hThread[curThreadNo] = CreateThread(nullptr, dwStackSize, (LPTHREAD_START_ROUTINE)threadProc, (void *)(((char *)pParameter) + curThreadNo * parameterStructSize), CREATE_SUSPENDED, &threadId[curThreadNo]); SetThreadPriority(hThread[curThreadNo], THREAD_PRIORITY_BELOW_NORMAL); - if (hThread[curThreadNo] == nullptr) { - for (curThreadNo; curThreadNo > 0; curThreadNo--) { + if (hThread[curThreadNo] == nullptr) + { + for (curThreadNo; curThreadNo > 0; curThreadNo--) + { CloseHandle(hThread[curThreadNo - 1]); hThread[curThreadNo - 1] = nullptr; } @@ -236,61 +262,73 @@ unsigned int ThreadManager::executeInParallel(DWORD threadProc(void *pParameter } // start threads - for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) { - if (!executionPaused) ResumeThread(hThread[curThreadNo]); + for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) + { + if (!executionPaused) + ResumeThread(hThread[curThreadNo]); } // wait for every thread to end WaitForMultipleObjects(numThreads, hThread, TRUE, INFINITE); // Close all thread handles upon completion. - for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) { + for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) + { CloseHandle(hThread[curThreadNo]); hThread[curThreadNo] = nullptr; threadId[curThreadNo] = 0; } // everything ok - if (executionCancelled) { + if (executionCancelled) + { return TM_RETURN_VALUE_EXECUTION_CANCELLED; - } else { + } + else + { return TM_RETURN_VALUE_OK; } } //----------------------------------------------------------------------------- // Name: executeInParallel() -// Desc: +// Desc: // lpParameter - an array of size numThreads // finalValue - this value is part of the iteration, meaning that index ranges from initialValue to finalValue including both border values //----------------------------------------------------------------------------- -unsigned int ThreadManager::executeParallelLoop(DWORD threadProc(void *pParameter, int index), - void *pParameter, - unsigned int parameterStructSize, - unsigned int scheduleType, - int initialValue, - int finalValue, - int inkrement) +unsigned int ThreadManager::executeParallelLoop(DWORD threadProc(void *pParameter, int index), + void *pParameter, + unsigned int parameterStructSize, + unsigned int scheduleType, + int initialValue, + int finalValue, + int inkrement) { // parameters ok? - if (executionCancelled == true) return TM_RETURN_VALUE_EXECUTION_CANCELLED; - if (pParameter == nullptr) return TM_RETURN_VALUE_INVALID_PARAM; - if (scheduleType >= TM_SCHEDULE_NUM_TYPES) return TM_RETURN_VALUE_INVALID_PARAM; - if (inkrement == 0) return TM_RETURN_VALUE_INVALID_PARAM; - if (abs(finalValue - initialValue) == abs(inkrement)) return TM_RETURN_VALUE_INVALID_PARAM; + if (executionCancelled == true) + return TM_RETURN_VALUE_EXECUTION_CANCELLED; + if (pParameter == nullptr) + return TM_RETURN_VALUE_INVALID_PARAM; + if (scheduleType >= TM_SCHEDULE_NUM_TYPES) + return TM_RETURN_VALUE_INVALID_PARAM; + if (inkrement == 0) + return TM_RETURN_VALUE_INVALID_PARAM; + if (abs(finalValue - initialValue) == abs(inkrement)) + return TM_RETURN_VALUE_INVALID_PARAM; // locals - unsigned int curThreadNo; // the threads are enumerated from 0 to numThreads-1 - int numIterations = (finalValue - initialValue) / inkrement + 1; // total number of iterations - int chunkSize = 0; // number of iterations per chunk - SIZE_T dwStackSize = 0; // initital stack size of each thread. 0 means default size ~1MB - ForLoop *forLoopParameters = new ForLoop[numThreads]; // + unsigned int curThreadNo; // the threads are enumerated from 0 to numThreads-1 + int numIterations = (finalValue - initialValue) / inkrement + 1; // total number of iterations + int chunkSize = 0; // number of iterations per chunk + SIZE_T dwStackSize = 0; // initital stack size of each thread. 0 means default size ~1MB + ForLoop *forLoopParameters = new ForLoop[numThreads]; // // globals termineAllThreads = false; // create threads - for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) { + for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) + { forLoopParameters[curThreadNo].pParameter = (pParameter != nullptr ? (void *)(((char *)pParameter) + curThreadNo * parameterStructSize) : nullptr); forLoopParameters[curThreadNo].threadManager = this; @@ -298,12 +336,16 @@ unsigned int ThreadManager::executeParallelLoop(DWORD threadProc(void *pParam forLoopParameters[curThreadNo].inkrement = inkrement; forLoopParameters[curThreadNo].scheduleType = scheduleType; - switch (scheduleType) { + switch (scheduleType) + { case TM_SCHEDULE_STATIC: - chunkSize = numIterations / numThreads + (curThreadNo < numIterations %numThreads ? 1 : 0); - if (curThreadNo == 0) { + chunkSize = numIterations / numThreads + (curThreadNo < numIterations % numThreads ? 1 : 0); + if (curThreadNo == 0) + { forLoopParameters[curThreadNo].initialValue = initialValue; - } else { + } + else + { forLoopParameters[curThreadNo].initialValue = forLoopParameters[curThreadNo - 1].finalValue + 1; } forLoopParameters[curThreadNo].finalValue = forLoopParameters[curThreadNo].initialValue + chunkSize - 1; @@ -322,8 +364,10 @@ unsigned int ThreadManager::executeParallelLoop(DWORD threadProc(void *pParam // create suspended thread hThread[curThreadNo] = CreateThread(nullptr, dwStackSize, threadForLoop, (LPVOID)(&forLoopParameters[curThreadNo]), CREATE_SUSPENDED, &threadId[curThreadNo]); SetThreadPriority(hThread[curThreadNo], THREAD_PRIORITY_BELOW_NORMAL); - if (hThread[curThreadNo] == nullptr) { - for (curThreadNo; curThreadNo > 0; curThreadNo--) { + if (hThread[curThreadNo] == nullptr) + { + for (curThreadNo; curThreadNo > 0; curThreadNo--) + { CloseHandle(hThread[curThreadNo - 1]); hThread[curThreadNo - 1] = nullptr; } @@ -334,15 +378,18 @@ unsigned int ThreadManager::executeParallelLoop(DWORD threadProc(void *pParam } // start threads, but don't resume if in pause mode - for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) { - if (!executionPaused) ResumeThread(hThread[curThreadNo]); + for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) + { + if (!executionPaused) + ResumeThread(hThread[curThreadNo]); } // wait for every thread to end WaitForMultipleObjects(numThreads, hThread, TRUE, INFINITE); // Close all thread handles upon completion. - for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) { + for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) + { CloseHandle(hThread[curThreadNo]); hThread[curThreadNo] = nullptr; threadId[curThreadNo] = 0; @@ -350,27 +397,33 @@ unsigned int ThreadManager::executeParallelLoop(DWORD threadProc(void *pParam delete[] forLoopParameters; // everything ok - if (executionCancelled) { + if (executionCancelled) + { return TM_RETURN_VALUE_EXECUTION_CANCELLED; - } else { + } + else + { return TM_RETURN_VALUE_OK; } } //----------------------------------------------------------------------------- // Name: threadForLoop() -// Desc: +// Desc: //----------------------------------------------------------------------------- DWORD WINAPI ThreadManager::threadForLoop(LPVOID lpParameter) { // locals ForLoop *forLoopParameters = (ForLoop *)lpParameter; - int index; + int index; - switch (forLoopParameters->scheduleType) { + switch (forLoopParameters->scheduleType) + { case TM_SCHEDULE_STATIC: - for (index = forLoopParameters->initialValue; (forLoopParameters->inkrement < 0) ? index >= forLoopParameters->finalValue : index <= forLoopParameters->finalValue; index += forLoopParameters->inkrement) { - switch (forLoopParameters->threadProc(forLoopParameters->pParameter, index)) { + for (index = forLoopParameters->initialValue; (forLoopParameters->inkrement < 0) ? index >= forLoopParameters->finalValue : index <= forLoopParameters->finalValue; index += forLoopParameters->inkrement) + { + switch (forLoopParameters->threadProc(forLoopParameters->pParameter, index)) + { case TM_RETURN_VALUE_OK: break; case TM_RETURN_VALUE_TERMINATE_ALL_THREADS: @@ -379,7 +432,8 @@ DWORD WINAPI ThreadManager::threadForLoop(LPVOID lpParameter) default: break; } - if (forLoopParameters->threadManager->termineAllThreads) break; + if (forLoopParameters->threadManager->termineAllThreads) + break; } break; case TM_SCHEDULE_DYNAMIC: @@ -397,6 +451,6 @@ DWORD WINAPI ThreadManager::threadForLoop(LPVOID lpParameter) } /*** To Do's ******************************************************************************** -- Beschränkung auf 'int' kann zu Überlauf führen, wenn mehr states in einer layer vorliegen. +- Beschr�nkung auf 'int' kann zu �berlauf f�hren, wenn mehr states in einer layer vorliegen. ==> Vielleicht mit class templates arbeiten *********************************************************************************************/ \ No newline at end of file diff --git a/src/perfect/threadManager.h b/src/perfect/threadManager.h index 5b317577..977437cd 100644 --- a/src/perfect/threadManager.h +++ b/src/perfect/threadManager.h @@ -14,21 +14,21 @@ #include #include -using namespace std; // use standard library namespace +using namespace std; // use standard library namespace /*** Konstanten ******************************************************/ -#define TM_SCHEDULE_USER_DEFINED 0 -#define TM_SCHEDULE_STATIC 1 -#define TM_SCHEDULE_DYNAMIC 2 -#define TM_SCHEDULE_GUIDED 3 -#define TM_SCHEDULE_RUNTIME 4 -#define TM_SCHEDULE_NUM_TYPES 5 +#define TM_SCHEDULE_USER_DEFINED 0 +#define TM_SCHEDULE_STATIC 1 +#define TM_SCHEDULE_DYNAMIC 2 +#define TM_SCHEDULE_GUIDED 3 +#define TM_SCHEDULE_RUNTIME 4 +#define TM_SCHEDULE_NUM_TYPES 5 -#define TM_RETURN_VALUE_OK 0 -#define TM_RETURN_VALUE_TERMINATE_ALL_THREADS 1 -#define TM_RETURN_VALUE_EXECUTION_CANCELLED 2 -#define TM_RETURN_VALUE_INVALID_PARAM 3 -#define TM_RETURN_VALUE_UNEXPECTED_ERROR 4 +#define TM_RETURN_VALUE_OK 0 +#define TM_RETURN_VALUE_TERMINATE_ALL_THREADS 1 +#define TM_RETURN_VALUE_EXECUTION_CANCELLED 2 +#define TM_RETURN_VALUE_INVALID_PARAM 3 +#define TM_RETURN_VALUE_UNEXPECTED_ERROR 4 /*** Makros ******************************************************/ @@ -39,58 +39,52 @@ using namespace std; // use standard library namespace class ThreadManager { private: - // structures struct ForLoop { - unsigned int scheduleType; - int inkrement; - int initialValue; - int finalValue; + unsigned int scheduleType; + int inkrement; + int initialValue; + int finalValue; void *pParameter; - DWORD(*threadProc)(void *pParameter, int index); // pointer to the user function to be executed by the threads + DWORD (*threadProc) + (void *pParameter, int index); // pointer to the user function to be executed by the threads ThreadManager *threadManager; }; // Variables - unsigned int numThreads; // number of threads - HANDLE *hThread; // array of size 'numThreads' containing the thread handles - DWORD *threadId; // array of size 'numThreads' containing the thread ids - bool termineAllThreads; - bool executionPaused; // switch for the - bool executionCancelled; // true when cancelExecution() was called + unsigned int numThreads; // number of threads + HANDLE *hThread; // array of size 'numThreads' containing the thread handles + DWORD *threadId; // array of size 'numThreads' containing the thread ids + bool termineAllThreads; + bool executionPaused; // switch for the + bool executionCancelled; // true when cancelExecution() was called // barier stuff - HANDLE hEventBarrierPassedByEveryBody; - HANDLE *hBarrier; // array of size 'numThreads' containing the event handles for the barrier - unsigned int numThreadsPassedBarrier; - CRITICAL_SECTION csBarrier; + HANDLE hEventBarrierPassedByEveryBody; + HANDLE *hBarrier; // array of size 'numThreads' containing the event handles for the barrier + unsigned int numThreadsPassedBarrier; + CRITICAL_SECTION csBarrier; // functions - static DWORD WINAPI threadForLoop(LPVOID lpParameter); + static DWORD WINAPI threadForLoop(LPVOID lpParameter); public: - class ThreadVarsArrayItem { public: - unsigned int curThreadNo; + unsigned int curThreadNo; - virtual void initializeElement() - { - }; - virtual void destroyElement() - { - }; - virtual void reduce() - { - }; + virtual void initializeElement(){}; + virtual void destroyElement(){}; + virtual void reduce(){}; }; - template class ThreadVarsArray + template + class ThreadVarsArray { public: - unsigned int numberOfThreads; + unsigned int numberOfThreads; varType *item; ThreadVarsArray(unsigned int numberOfThreads, varType &master) @@ -98,16 +92,18 @@ public: this->numberOfThreads = numberOfThreads; this->item = new varType[numberOfThreads]; - for (unsigned int threadCounter = 0; threadCounter < numberOfThreads; threadCounter++) { + for (unsigned int threadCounter = 0; threadCounter < numberOfThreads; threadCounter++) + { item[threadCounter].curThreadNo = threadCounter; item[threadCounter].initializeElement(master); - item[threadCounter].curThreadNo = threadCounter; // if 'curThreadNo' is overwritten in 'initializeElement()' + item[threadCounter].curThreadNo = threadCounter; // if 'curThreadNo' is overwritten in 'initializeElement()' } }; ~ThreadVarsArray() { - for (unsigned int threadCounter = 0; threadCounter < numberOfThreads; threadCounter++) { + for (unsigned int threadCounter = 0; threadCounter < numberOfThreads; threadCounter++) + { item[threadCounter].destroyElement(); } delete[] item; @@ -125,7 +121,8 @@ public: void reduce() { - for (unsigned int threadCounter = 0; threadCounter < numberOfThreads; threadCounter++) { + for (unsigned int threadCounter = 0; threadCounter < numberOfThreads; threadCounter++) + { item[threadCounter].reduce(); } }; @@ -136,20 +133,20 @@ public: ~ThreadManager(); // Functions - unsigned int getThreadNumber(); - unsigned int getNumThreads(); + unsigned int getThreadNumber(); + unsigned int getNumThreads(); - bool setNumThreads(unsigned int newNumThreads); - void waitForOtherThreads(unsigned int threadNo); - void pauseExecution(); // un-/suspend all threads - void cancelExecution(); // termineAllThreads auf true - bool wasExecutionCancelled(); - void uncancelExecution(); // sets executionCancelled to false, otherwise executeParellelLoop returns immediatelly -//... void setCallBackFunction (void userFunction(void* pUser), void* pUser, DWORD milliseconds); // a user function which is called every x-milliseconds during execution between two iterations + bool setNumThreads(unsigned int newNumThreads); + void waitForOtherThreads(unsigned int threadNo); + void pauseExecution(); // un-/suspend all threads + void cancelExecution(); // termineAllThreads auf true + bool wasExecutionCancelled(); + void uncancelExecution(); // sets executionCancelled to false, otherwise executeParellelLoop returns immediatelly + //... void setCallBackFunction (void userFunction(void* pUser), void* pUser, DWORD milliseconds); // a user function which is called every x-milliseconds during execution between two iterations // execute - unsigned int executeInParallel(DWORD threadProc(void *pParameter), void *pParameter, unsigned int parameterStructSize); - unsigned int executeParallelLoop(DWORD threadProc(void *pParameter, int index), void *pParameter, unsigned int parameterStructSize, unsigned int scheduleType, int initialValue, int finalValue, int inkrement); + unsigned int executeInParallel(DWORD threadProc(void *pParameter), void *pParameter, unsigned int parameterStructSize); + unsigned int executeParallelLoop(DWORD threadProc(void *pParameter, int index), void *pParameter, unsigned int parameterStructSize, unsigned int scheduleType, int initialValue, int finalValue, int inkrement); }; #endif