perfect: Format code with vscode

This commit is contained in:
Calcitem 2021-01-20 01:33:20 +08:00
parent 50b9574101
commit 5c71717a9c
27 changed files with 4194 additions and 2817 deletions

View File

@ -15,7 +15,7 @@
BufferedFile::BufferedFile(unsigned int numberOfThreads, unsigned int bufferSizeInBytes, const char *fileName) BufferedFile::BufferedFile(unsigned int numberOfThreads, unsigned int bufferSizeInBytes, const char *fileName)
{ {
// locals // locals
unsigned int curThread; unsigned int curThread;
// Init blocks // Init blocks
bufferSize = bufferSizeInBytes; bufferSize = bufferSizeInBytes;
@ -27,7 +27,8 @@ BufferedFile::BufferedFile(unsigned int numberOfThreads, unsigned int bufferSize
bytesInReadBuffer = new unsigned int[numThreads]; bytesInReadBuffer = new unsigned int[numThreads];
bytesInWriteBuffer = new unsigned int[numThreads]; bytesInWriteBuffer = new unsigned int[numThreads];
for (curThread = 0; curThread < numThreads; curThread++) { for (curThread = 0; curThread < numThreads; curThread++)
{
curReadingPointer[curThread] = 0; curReadingPointer[curThread] = 0;
curWritingPointer[curThread] = 0; curWritingPointer[curThread] = 0;
bytesInReadBuffer[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); hFile = CreateFileA(fileName, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
// opened file succesfully // opened file succesfully
if (hFile == INVALID_HANDLE_VALUE) { if (hFile == INVALID_HANDLE_VALUE)
{
hFile = nullptr; hFile = nullptr;
return; return;
} }
@ -67,12 +69,13 @@ BufferedFile::~BufferedFile()
delete[] bytesInWriteBuffer; delete[] bytesInWriteBuffer;
// close file // close file
if (hFile != nullptr) CloseHandle(hFile); if (hFile != nullptr)
CloseHandle(hFile);
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: getFileSize() // Name: getFileSize()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
long long BufferedFile::getFileSize() long long BufferedFile::getFileSize()
{ {
@ -84,11 +87,12 @@ long long BufferedFile::getFileSize()
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: flushBuffers() // Name: flushBuffers()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
bool BufferedFile::flushBuffers() 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]); writeDataToFile(hFile, curWritingPointer[threadNo] - bytesInWriteBuffer[threadNo], bytesInWriteBuffer[threadNo], &writeBuffer[threadNo * bufferSize + 0]);
bytesInWriteBuffer[threadNo] = 0; bytesInWriteBuffer[threadNo] = 0;
} }
@ -101,21 +105,30 @@ bool BufferedFile::flushBuffers()
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void BufferedFile::writeDataToFile(HANDLE hFile, long long offset, unsigned int sizeInBytes, void *pData) void BufferedFile::writeDataToFile(HANDLE hFile, long long offset, unsigned int sizeInBytes, void *pData)
{ {
DWORD dwBytesWritten; DWORD dwBytesWritten;
LARGE_INTEGER liDistanceToMove; LARGE_INTEGER liDistanceToMove;
unsigned int restingBytes = sizeInBytes; unsigned int restingBytes = sizeInBytes;
liDistanceToMove.QuadPart = offset; liDistanceToMove.QuadPart = offset;
EnterCriticalSection(&csIO); EnterCriticalSection(&csIO);
while (!SetFilePointerEx(hFile, liDistanceToMove, nullptr, FILE_BEGIN)) cout << endl << "SetFilePointerEx failed!"; while (!SetFilePointerEx(hFile, liDistanceToMove, nullptr, FILE_BEGIN))
while (restingBytes > 0) { cout << endl
if (WriteFile(hFile, pData, sizeInBytes, &dwBytesWritten, nullptr) == TRUE) { << "SetFilePointerEx failed!";
while (restingBytes > 0)
{
if (WriteFile(hFile, pData, sizeInBytes, &dwBytesWritten, nullptr) == TRUE)
{
restingBytes -= dwBytesWritten; restingBytes -= dwBytesWritten;
pData = (void *)(((unsigned char *)pData) + dwBytesWritten); pData = (void *)(((unsigned char *)pData) + dwBytesWritten);
if (restingBytes > 0) cout << endl << "Still " << restingBytes << " to write!"; if (restingBytes > 0)
} else { cout << endl
cout << endl << "WriteFile Failed!"; << "Still " << restingBytes << " to write!";
}
else
{
cout << endl
<< "WriteFile Failed!";
} }
} }
LeaveCriticalSection(&csIO); 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) void BufferedFile::readDataFromFile(HANDLE hFile, long long offset, unsigned int sizeInBytes, void *pData)
{ {
DWORD dwBytesRead; DWORD dwBytesRead;
LARGE_INTEGER liDistanceToMove; LARGE_INTEGER liDistanceToMove;
unsigned int restingBytes = sizeInBytes; unsigned int restingBytes = sizeInBytes;
liDistanceToMove.QuadPart = offset; liDistanceToMove.QuadPart = offset;
EnterCriticalSection(&csIO); EnterCriticalSection(&csIO);
while (!SetFilePointerEx(hFile, liDistanceToMove, nullptr, FILE_BEGIN)) cout << endl << "SetFilePointerEx failed!"; while (!SetFilePointerEx(hFile, liDistanceToMove, nullptr, FILE_BEGIN))
while (restingBytes > 0) { cout << endl
if (ReadFile(hFile, pData, sizeInBytes, &dwBytesRead, nullptr) == TRUE) { << "SetFilePointerEx failed!";
while (restingBytes > 0)
{
if (ReadFile(hFile, pData, sizeInBytes, &dwBytesRead, nullptr) == TRUE)
{
restingBytes -= dwBytesRead; restingBytes -= dwBytesRead;
pData = (void *)(((unsigned char *)pData) + dwBytesRead); pData = (void *)(((unsigned char *)pData) + dwBytesRead);
if (restingBytes > 0) cout << endl << "Still " << restingBytes << " to read!"; if (restingBytes > 0)
} else { cout << endl
cout << endl << "ReadFile Failed!"; << "Still " << restingBytes << " to read!";
}
else
{
cout << endl
<< "ReadFile Failed!";
} }
} }
LeaveCriticalSection(&csIO); LeaveCriticalSection(&csIO);
@ -149,7 +171,7 @@ void BufferedFile::readDataFromFile(HANDLE hFile, long long offset, unsigned int
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: writeBytes() // Name: writeBytes()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
bool BufferedFile::writeBytes(unsigned int numBytes, unsigned char *pData) bool BufferedFile::writeBytes(unsigned int numBytes, unsigned char *pData)
{ {
@ -158,18 +180,21 @@ bool BufferedFile::writeBytes(unsigned int numBytes, unsigned char *pData)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: writeBytes() // Name: writeBytes()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
bool BufferedFile::writeBytes(unsigned int threadNo, long long positionInFile, unsigned int numBytes, unsigned char *pData) bool BufferedFile::writeBytes(unsigned int threadNo, long long positionInFile, unsigned int numBytes, unsigned char *pData)
{ {
// parameters ok? // parameters ok?
if (threadNo >= numThreads) return false; if (threadNo >= numThreads)
if (pData == nullptr) return false; return false;
if (pData == nullptr)
return false;
// locals // locals
// if buffer full or not sequential write operation write buffer to file // 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]); writeDataToFile(hFile, curWritingPointer[threadNo] - bytesInWriteBuffer[threadNo], bytesInWriteBuffer[threadNo], &writeBuffer[threadNo * bufferSize + 0]);
bytesInWriteBuffer[threadNo] = 0; bytesInWriteBuffer[threadNo] = 0;
@ -186,7 +211,7 @@ bool BufferedFile::writeBytes(unsigned int threadNo, long long positionInFile, u
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: takeBytes() // Name: takeBytes()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
bool BufferedFile::readBytes(unsigned int numBytes, unsigned char *pData) bool BufferedFile::readBytes(unsigned int numBytes, unsigned char *pData)
{ {
@ -195,18 +220,22 @@ bool BufferedFile::readBytes(unsigned int numBytes, unsigned char *pData)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: takeBytes() // Name: takeBytes()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
bool BufferedFile::readBytes(unsigned int threadNo, long long positionInFile, unsigned int numBytes, unsigned char *pData) bool BufferedFile::readBytes(unsigned int threadNo, long long positionInFile, unsigned int numBytes, unsigned char *pData)
{ {
// parameters ok? // parameters ok?
if (threadNo >= numThreads) return false; if (threadNo >= numThreads)
if (pData == nullptr) return false; 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? // 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)); 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]]); readDataFromFile(hFile, positionInFile, bytesInReadBuffer[threadNo], &readBuffer[threadNo * bufferSize + bufferSize - bytesInReadBuffer[threadNo]]);
} }
memcpy(pData, &readBuffer[threadNo * bufferSize + bufferSize - bytesInReadBuffer[threadNo]], numBytes); memcpy(pData, &readBuffer[threadNo * bufferSize + bufferSize - bytesInReadBuffer[threadNo]], numBytes);

View File

@ -21,21 +21,21 @@ class BufferedFile
{ {
private: private:
// Variables // Variables
HANDLE hFile; // Handle of the file HANDLE hFile; // Handle of the file
unsigned int numThreads; // number of threads 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 *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] 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 *curReadingPointer; // array of size [numThreads] with pointers to the byte which is currently read
long long *curWritingPointer; // '' long long *curWritingPointer; // ''
unsigned int *bytesInReadBuffer; // unsigned int *bytesInReadBuffer; //
unsigned int *bytesInWriteBuffer; // unsigned int *bytesInWriteBuffer; //
unsigned int bufferSize; // size in bytes of a buffer unsigned int bufferSize; // size in bytes of a buffer
long long fileSize; // size in bytes long long fileSize; // size in bytes
CRITICAL_SECTION csIO; CRITICAL_SECTION csIO;
// Functions // Functions
void writeDataToFile(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); void readDataFromFile(HANDLE hFile, long long offset, unsigned int sizeInBytes, void *pData);
public: public:
// Constructor / destructor // Constructor / destructor
@ -43,12 +43,12 @@ public:
~BufferedFile(); ~BufferedFile();
// Functions // Functions
bool flushBuffers(); bool flushBuffers();
bool writeBytes(unsigned int numBytes, unsigned char *pData); bool writeBytes(unsigned int numBytes, unsigned char *pData);
bool readBytes(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 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); bool readBytes(unsigned int threadNo, long long positionInFile, unsigned int numBytes, unsigned char *pData);
long long getFileSize(); long long getFileSize();
}; };
#endif #endif

View File

@ -6,7 +6,6 @@
https://github.com/madweasel/madweasels-cpp https://github.com/madweasel/madweasels-cpp
\*********************************************************************/ \*********************************************************************/
#ifndef CONFIG_H #ifndef CONFIG_H
#define CONFIG_H #define CONFIG_H

View File

@ -11,7 +11,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: CyclicArray() // Name: CyclicArray()
// Desc: Creates a cyclic array. The passed file is used as temporary data buffer for the cyclic array. // 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) CyclicArray::CyclicArray(unsigned int blockSizeInBytes, unsigned int numberOfBlocks, const char *fileName)
{ {
// Init blocks // 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); hFile = CreateFileA(fileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
// opened file succesfully // opened file succesfully
if (hFile == INVALID_HANDLE_VALUE) { if (hFile == INVALID_HANDLE_VALUE)
{
hFile = nullptr; hFile = nullptr;
return; return;
} }
@ -46,7 +47,8 @@ CyclicArray::~CyclicArray()
delete[] writingBlock; delete[] writingBlock;
// close file // 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) void CyclicArray::writeDataToFile(HANDLE hFile, long long offset, unsigned int sizeInBytes, void *pData)
{ {
DWORD dwBytesWritten; DWORD dwBytesWritten;
LARGE_INTEGER liDistanceToMove; LARGE_INTEGER liDistanceToMove;
unsigned int restingBytes = sizeInBytes; unsigned int restingBytes = sizeInBytes;
liDistanceToMove.QuadPart = offset; 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) { while (restingBytes > 0)
if (WriteFile(hFile, pData, sizeInBytes, &dwBytesWritten, nullptr) == TRUE) { {
if (WriteFile(hFile, pData, sizeInBytes, &dwBytesWritten, nullptr) == TRUE)
{
restingBytes -= dwBytesWritten; restingBytes -= dwBytesWritten;
pData = (void *)(((unsigned char *)pData) + dwBytesWritten); pData = (void *)(((unsigned char *)pData) + dwBytesWritten);
if (restingBytes > 0) cout << endl << "Still " << restingBytes << " to write!"; if (restingBytes > 0)
} else { cout << endl
cout << endl << "WriteFile Failed!"; << "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) void CyclicArray::readDataFromFile(HANDLE hFile, long long offset, unsigned int sizeInBytes, void *pData)
{ {
DWORD dwBytesRead; DWORD dwBytesRead;
LARGE_INTEGER liDistanceToMove; LARGE_INTEGER liDistanceToMove;
unsigned int restingBytes = sizeInBytes; unsigned int restingBytes = sizeInBytes;
liDistanceToMove.QuadPart = offset; 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) { while (restingBytes > 0)
if (ReadFile(hFile, pData, sizeInBytes, &dwBytesRead, nullptr) == TRUE) { {
if (ReadFile(hFile, pData, sizeInBytes, &dwBytesRead, nullptr) == TRUE)
{
restingBytes -= dwBytesRead; restingBytes -= dwBytesRead;
pData = (void *)(((unsigned char *)pData) + dwBytesRead); pData = (void *)(((unsigned char *)pData) + dwBytesRead);
if (restingBytes > 0) cout << endl << "Still " << restingBytes << " to read!"; if (restingBytes > 0)
} else { cout << endl
cout << endl << "ReadFile Failed!"; << "Still " << restingBytes << " to read!";
}
else
{
cout << endl
<< "ReadFile Failed!";
} }
} }
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: addBytes() // 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. // 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) bool CyclicArray::addBytes(unsigned int numBytes, unsigned char *pData)
{ {
// locals // locals
unsigned int bytesWritten = 0; unsigned int bytesWritten = 0;
// write each byte // write each byte
while (bytesWritten < numBytes) { while (bytesWritten < numBytes)
{
// store byte in current reading block // store byte in current reading block
*curWritingPointer = *pData; *curWritingPointer = *pData;
@ -119,16 +140,19 @@ bool CyclicArray::addBytes(unsigned int numBytes, unsigned char *pData)
pData++; pData++;
// when block is full then save current one to file and begin new one // 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? // copy data into reading block?
if (curReadingBlock == curWritingBlock) { if (curReadingBlock == curWritingBlock)
{
memcpy(readingBlock, writingBlock, blockSize); memcpy(readingBlock, writingBlock, blockSize);
curReadingPointer = readingBlock + (curReadingPointer - writingBlock); curReadingPointer = readingBlock + (curReadingPointer - writingBlock);
} }
// will reading block be overwritten? // will reading block be overwritten?
if (curReadingBlock == curWritingBlock && !readWriteInSameRound) return false; if (curReadingBlock == curWritingBlock && !readWriteInSameRound)
return false;
// store bock in file // store bock in file
writeDataToFile(hFile, ((long long)blockSize) * ((long long)curWritingBlock), blockSize, writingBlock); 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 // set pointer to beginnig of writing block
curWritingPointer = writingBlock; curWritingPointer = writingBlock;
curWritingBlock = (curWritingBlock + 1) % numBlocks; 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() // Name: bytesAvailable()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
bool CyclicArray::bytesAvailable() bool CyclicArray::bytesAvailable()
{ {
if (curReadingBlock == curWritingBlock && curReadingPointer == curWritingPointer && readWriteInSameRound) return false; if (curReadingBlock == curWritingBlock && curReadingPointer == curWritingPointer && readWriteInSameRound)
else return true; return false;
else
return true;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: takeBytes() // 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. // the data of the next whole block is read from the file.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
bool CyclicArray::takeBytes(unsigned int numBytes, unsigned char *pData) bool CyclicArray::takeBytes(unsigned int numBytes, unsigned char *pData)
@ -164,11 +191,13 @@ bool CyclicArray::takeBytes(unsigned int numBytes, unsigned char *pData)
// locals // locals
unsigned int bytesRead = 0; unsigned int bytesRead = 0;
// read each byte // read each byte
while (bytesRead < numBytes) { while (bytesRead < numBytes)
{
// was current reading byte already written ? // 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 // read current byte
*pData = *curReadingPointer; *pData = *curReadingPointer;
@ -177,17 +206,21 @@ bool CyclicArray::takeBytes(unsigned int numBytes, unsigned char *pData)
pData++; pData++;
// load next block? // load next block?
if (curReadingPointer == readingBlock + blockSize) { if (curReadingPointer == readingBlock + blockSize)
{
// go to next block // go to next block
curReadingBlock = (curReadingBlock + 1) % numBlocks; curReadingBlock = (curReadingBlock + 1) % numBlocks;
if (curReadingBlock == 0) readWriteInSameRound = true; if (curReadingBlock == 0)
readWriteInSameRound = true;
// writing block reached ? // writing block reached ?
if (curReadingBlock == curWritingBlock) { if (curReadingBlock == curWritingBlock)
{
curReadingPointer = writingBlock; curReadingPointer = writingBlock;
}
} else { else
{
// set pointer to beginnig of reading block // set pointer to beginnig of reading block
curReadingPointer = readingBlock; curReadingPointer = readingBlock;
@ -210,31 +243,34 @@ bool CyclicArray::takeBytes(unsigned int numBytes, unsigned char *pData)
bool CyclicArray::loadFile(const char *fileName, LONGLONG &numBytesLoaded) bool CyclicArray::loadFile(const char *fileName, LONGLONG &numBytesLoaded)
{ {
// locals // locals
HANDLE hLoadFile; HANDLE hLoadFile;
unsigned char *dataInFile; unsigned char *dataInFile;
LARGE_INTEGER largeInt; LARGE_INTEGER largeInt;
LONGLONG maxFileSize = ((LONGLONG)blockSize) * ((LONGLONG)numBlocks); LONGLONG maxFileSize = ((LONGLONG)blockSize) * ((LONGLONG)numBlocks);
LONGLONG curOffset = 0; LONGLONG curOffset = 0;
unsigned int numBlocksInFile; unsigned int numBlocksInFile;
unsigned int curBlock; unsigned int curBlock;
unsigned int numBytesInLastBlock; unsigned int numBytesInLastBlock;
numBytesLoaded = 0; numBytesLoaded = 0;
// cyclic array file must be open // 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) // 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); hLoadFile = CreateFileA(fileName, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
// opened file succesfully // opened file succesfully
if (hLoadFile == INVALID_HANDLE_VALUE) { if (hLoadFile == INVALID_HANDLE_VALUE)
{
return false; return false;
} }
// does data of file fit into cyclic array ? // does data of file fit into cyclic array ?
GetFileSizeEx(hLoadFile, &largeInt); GetFileSizeEx(hLoadFile, &largeInt);
if (maxFileSize < largeInt.QuadPart) { if (maxFileSize < largeInt.QuadPart)
{
CloseHandle(hLoadFile); CloseHandle(hLoadFile);
return false; return false;
} }
@ -250,8 +286,9 @@ bool CyclicArray::loadFile(const char *fileName, LONGLONG &numBytesLoaded)
numBytesInLastBlock = (unsigned int)(largeInt.QuadPart % ((LONGLONG)blockSize)); numBytesInLastBlock = (unsigned int)(largeInt.QuadPart % ((LONGLONG)blockSize));
dataInFile = new unsigned char[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 // load data from file
readDataFromFile(hLoadFile, curOffset, blockSize, dataInFile); readDataFromFile(hLoadFile, curOffset, blockSize, dataInFile);
@ -281,14 +318,15 @@ bool CyclicArray::saveFile(const char *fileName)
{ {
// locals // locals
unsigned char *dataInFile; unsigned char *dataInFile;
HANDLE hSaveFile; HANDLE hSaveFile;
LONGLONG curOffset; LONGLONG curOffset;
unsigned int curBlock; unsigned int curBlock;
unsigned int bytesToWrite; unsigned int bytesToWrite;
void *pointer; void *pointer;
// cyclic array file must be open // cyclic array file must be open
if (hFile == nullptr) { if (hFile == nullptr)
{
return false; 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); hSaveFile = CreateFileA(fileName, GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
// opened file succesfully // opened file succesfully
if (hSaveFile == INVALID_HANDLE_VALUE) { if (hSaveFile == INVALID_HANDLE_VALUE)
{
return false; return false;
} }
@ -305,22 +344,27 @@ bool CyclicArray::saveFile(const char *fileName)
curBlock = curReadingBlock; curBlock = curReadingBlock;
dataInFile = new unsigned char[blockSize]; dataInFile = new unsigned char[blockSize];
do { do
{
// copy current block // copy current block
if (curBlock == curWritingBlock && curBlock == curReadingBlock) { if (curBlock == curWritingBlock && curBlock == curReadingBlock)
{
pointer = curReadingPointer; pointer = curReadingPointer;
bytesToWrite = (unsigned int)(curWritingPointer - curReadingPointer); bytesToWrite = (unsigned int)(curWritingPointer - curReadingPointer);
}
} else if (curBlock == curWritingBlock) { else if (curBlock == curWritingBlock)
{
pointer = writingBlock; pointer = writingBlock;
bytesToWrite = (unsigned int)(curWritingPointer - writingBlock); bytesToWrite = (unsigned int)(curWritingPointer - writingBlock);
}
} else if (curBlock == curReadingBlock) { else if (curBlock == curReadingBlock)
{
pointer = curReadingPointer; pointer = curReadingPointer;
bytesToWrite = blockSize - (unsigned int)(curReadingPointer - readingBlock); bytesToWrite = blockSize - (unsigned int)(curReadingPointer - readingBlock);
}
} else { else
{
readDataFromFile(hFile, ((long long)curBlock) * ((long long)blockSize), blockSize, dataInFile); readDataFromFile(hFile, ((long long)curBlock) * ((long long)blockSize), blockSize, dataInFile);
pointer = dataInFile; pointer = dataInFile;
bytesToWrite = blockSize; bytesToWrite = blockSize;
@ -331,8 +375,10 @@ bool CyclicArray::saveFile(const char *fileName)
curOffset += bytesToWrite; curOffset += bytesToWrite;
// exit? // exit?
if (curBlock == curWritingBlock) break; if (curBlock == curWritingBlock)
else curBlock = (curBlock + 1) % numBlocks; break;
else
curBlock = (curBlock + 1) % numBlocks;
} while (true); } while (true);

View File

@ -21,16 +21,16 @@ class CyclicArray
{ {
private: private:
// Variables // Variables
HANDLE hFile; // Handle of the file 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 *readingBlock; // Array of size [blockSize] containing the data of the block, where reading is taking place
unsigned char *writingBlock; // '' unsigned char *writingBlock; // ''
unsigned char *curReadingPointer; // pointer to the byte which is currently read unsigned char *curReadingPointer; // pointer to the byte which is currently read
unsigned char *curWritingPointer; // '' unsigned char *curWritingPointer; // ''
unsigned int blockSize; // size in bytes of a block unsigned int blockSize; // size in bytes of a block
unsigned int curReadingBlock; // index of the block, where reading is taking place 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 curWritingBlock; // index of the block, where writing is taking place
unsigned int numBlocks; // amount of blocks unsigned int numBlocks; // amount of blocks
bool readWriteInSameRound; // true if curReadingBlock > curWritingBlock, false otherwise bool readWriteInSameRound; // true if curReadingBlock > curWritingBlock, false otherwise
// Functions // Functions
void writeDataToFile(HANDLE hFile, long long offset, unsigned int sizeInBytes, void *pData); void writeDataToFile(HANDLE hFile, long long offset, unsigned int sizeInBytes, void *pData);
@ -42,11 +42,11 @@ public:
~CyclicArray(); ~CyclicArray();
// Functions // Functions
bool addBytes(unsigned int numBytes, unsigned char *pData); bool addBytes(unsigned int numBytes, unsigned char *pData);
bool takeBytes(unsigned int numBytes, unsigned char *pData); bool takeBytes(unsigned int numBytes, unsigned char *pData);
bool loadFile(const char *fileName, LONGLONG &numBytesLoaded); bool loadFile(const char *fileName, LONGLONG &numBytesLoaded);
bool saveFile(const char *fileName); bool saveFile(const char *fileName);
bool bytesAvailable(); bool bytesAvailable();
}; };
#endif #endif

View File

@ -10,22 +10,22 @@
using namespace std; using namespace std;
unsigned int startTestFromLayer = 0; unsigned int startTestFromLayer = 0;
unsigned int endTestAtLayer = NUM_LAYERS - 1; unsigned int endTestAtLayer = NUM_LAYERS - 1;
#ifdef _DEBUG #ifdef _DEBUG
char databaseDirectory[] = "D:\\database"; char databaseDirectory[] = "D:\\database";
#elif _RELEASE_X64 #elif _RELEASE_X64
char databaseDirectory[] = ""; char databaseDirectory[] = "";
#endif #endif
bool calculateDatabase = false; bool calculateDatabase = false;
int main(void) int main(void)
{ {
// locals // locals
bool playerOneHuman = false; bool playerOneHuman = false;
bool playerTwoHuman = false; bool playerTwoHuman = false;
char ch[100]; char ch[100];
unsigned int pushFrom, pushTo; unsigned int pushFrom, pushTo;
Position *pos = new Position(); Position *pos = new Position();
PerfectAI *ai = new PerfectAI(databaseDirectory); PerfectAI *ai = new PerfectAI(databaseDirectory);
@ -35,7 +35,8 @@ int main(void)
// intro // intro
cout << "*************************" << endl; cout << "*************************" << endl;
cout << "* Muehle *" << endl; cout << "* Muehle *" << endl;
cout << "*************************" << endl << endl; cout << "*************************" << endl
<< endl;
ai->setDatabasePath(databaseDirectory); ai->setDatabasePath(databaseDirectory);
@ -46,28 +47,40 @@ int main(void)
pos->beginNewGame(ai, ai, (rand() % 2) ? fieldStruct::playerOne : fieldStruct::playerTwo); pos->beginNewGame(ai, ai, (rand() % 2) ? fieldStruct::playerOne : fieldStruct::playerTwo);
#endif // SELF_PLAY #endif // SELF_PLAY
if (calculateDatabase) { if (calculateDatabase)
{
// calculate // calculate
ai->calculateDatabase(MAX_DEPTH_OF_TREE, false); ai->calculateDatabase(MAX_DEPTH_OF_TREE, false);
// test database // test database
cout << endl << "Begin test starting from layer: "; startTestFromLayer; cout << endl
cout << endl << "End test at layer: "; endTestAtLayer; << "Begin test starting from layer: ";
startTestFromLayer;
cout << endl
<< "End test at layer: ";
endTestAtLayer;
ai->testLayers(startTestFromLayer, endTestAtLayer); ai->testLayers(startTestFromLayer, endTestAtLayer);
}
} else { else
{
#ifdef SELF_PLAY #ifdef SELF_PLAY
int moveCount = 0; int moveCount = 0;
#else #else
cout << "Is Player 1 human? (y/n):"; cin >> ch; if (ch[0] == 'y') playerOneHuman = true; cout << "Is Player 1 human? (y/n):";
cout << "Is Player 2 human? (y/n):"; cin >> ch; if (ch[0] == 'y') playerTwoHuman = true; 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 #endif // SELF_PLAY
// play // play
do { do
{
// print board // print board
cout << "\n\n\n\n\n\n\n\n\n\n\n"; cout << "\n\n\n\n\n\n\n\n\n\n\n";
pos->getComputersChoice(&pushFrom, &pushTo); pos->getComputersChoice(&pushFrom, &pushTo);
@ -76,7 +89,8 @@ int main(void)
#ifdef SELF_PLAY #ifdef SELF_PLAY
moveCount++; moveCount++;
if (moveCount > 99) { if (moveCount > 99)
{
goto out; goto out;
} }
#endif // SELF_PLAY #endif // SELF_PLAY
@ -84,32 +98,49 @@ int main(void)
pos->printBoard(); pos->printBoard();
// Human // Human
if ((pos->getCurrentPlayer() == fieldStruct::playerOne && playerOneHuman) if ((pos->getCurrentPlayer() == fieldStruct::playerOne && playerOneHuman) || (pos->getCurrentPlayer() == fieldStruct::playerTwo && playerTwoHuman))
|| (pos->getCurrentPlayer() == fieldStruct::playerTwo && playerTwoHuman)) { {
do { do
{
// Show text // Show text
if (pos->mustStoneBeRemoved()) cout << "\n Which stone do you want to remove? [a-x]: \n\n\n"; if (pos->mustStoneBeRemoved())
else if (pos->inSettingPhase()) cout << "\n Where are you going? [a-x]: \n\n\n"; cout << "\n Which stone do you want to remove? [a-x]: \n\n\n";
else cout << "\n Your train? [a-x][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 // get input
cin >> ch; 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 (pos->inSettingPhase())
if ((ch[0] >= 'a') && (ch[0] <= 'x')) pushTo = ch[0] - 'a'; else pushTo = fieldStruct::size; {
} else { if ((ch[0] >= 'a') && (ch[0] <= 'x'))
if ((ch[1] >= 'a') && (ch[1] <= 'x')) pushTo = ch[1] - 'a'; else pushTo = fieldStruct::size; 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 // 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 // undo moves until a human player shall move
do { do
{
pos->undo_move(); pos->undo_move();
} while (!((pos->getCurrentPlayer() == fieldStruct::playerOne && playerOneHuman) } while (!((pos->getCurrentPlayer() == fieldStruct::playerOne && playerOneHuman) || (pos->getCurrentPlayer() == fieldStruct::playerTwo && playerTwoHuman)));
|| (pos->getCurrentPlayer() == fieldStruct::playerTwo && playerTwoHuman)));
// reprint board // reprint board
break; break;
@ -118,7 +149,9 @@ int main(void)
} while (pos->do_move(pushFrom, pushTo) == false); } while (pos->do_move(pushFrom, pushTo) == false);
// Computer // Computer
} else { }
else
{
cout << "\n"; cout << "\n";
pos->do_move(pushFrom, pushTo); pos->do_move(pushFrom, pushTo);
} }
@ -130,13 +163,17 @@ int main(void)
pos->printBoard(); pos->printBoard();
if (pos->getWinner() == fieldStruct::playerOne) cout << "\n Player 1 (o) won after " << pos->getMovesDone() << " move.\n\n"; if (pos->getWinner() == fieldStruct::playerOne)
else if (pos->getWinner() == fieldStruct::playerTwo) cout << "\n Player 2 (x) won after " << pos->getMovesDone() << " move.\n\n"; cout << "\n Player 1 (o) won after " << pos->getMovesDone() << " move.\n\n";
else if (pos->getWinner() == fieldStruct::gameDrawn) cout << "\n Draw!\n\n"; else if (pos->getWinner() == fieldStruct::playerTwo)
else cout << "\n A program error has occurred!\n\n"; 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; char end;
cin >> end; cin >> end;

View File

@ -12,15 +12,16 @@ using namespace std;
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: printBoard() // Name: printBoard()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void fieldStruct::printBoard() void fieldStruct::printBoard()
{ {
// locals // locals
unsigned int index; 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 << "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"; 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 << "setting phase : " << (this->settingPhase ? "true" : "false");
cout << "\n"; cout << "\n";
cout << "\n a-----b-----c " << c[0] << "-----" << c[1] << "-----" << c[2]; cout << "\n a-----b-----c " << c[0] << "-----" << c[1] << "-----" << c[2];
cout << "\n | | | " << "| | |"; cout << "\n | | | "
cout << "\n | d---e---f | " << "| " << c[3] << "---" << c[4] << "---" << c[5] << " |"; << "| | |";
cout << "\n | | | | | " << "| | | | |"; cout << "\n | d---e---f | "
cout << "\n | | g-h-i | | " << "| | " << c[6] << "-" << c[7] << "-" << c[8] << " | |"; << "| " << c[3] << "---" << c[4] << "---" << c[5] << " |";
cout << "\n | | | | | | | " << "| | | | | |"; 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 j-k-l m-n-o " << c[9] << "-" << c[10] << "-" << c[11] << " " << c[12] << "-" << c[13] << "-" << c[14];
cout << "\n | | | | | | | " << "| | | | | |"; cout << "\n | | | | | | | "
cout << "\n | | p-q-r | | " << "| | " << c[15] << "-" << c[16] << "-" << c[17] << " | |"; << "| | | | | |";
cout << "\n | | | | | " << "| | | | |"; cout << "\n | | p-q-r | | "
cout << "\n | s---t---u | " << "| " << c[18] << "---" << c[19] << "---" << c[20] << " |"; << "| | " << c[15] << "-" << c[16] << "-" << c[17] << " | |";
cout << "\n | | | " << "| | |"; 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 v-----w-----x " << c[21] << "-----" << c[22] << "-----" << c[23];
cout << "\n"; cout << "\n";
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: GetCharFromStone() // Name: GetCharFromStone()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
char fieldStruct::GetCharFromStone(int stone) char fieldStruct::GetCharFromStone(int stone)
{ {
switch (stone) { switch (stone)
case fieldStruct::playerOne: return 'o'; {
case fieldStruct::playerTwo: return 'x'; case fieldStruct::playerOne:
case fieldStruct::playerOneWarning: return '1'; return 'o';
case fieldStruct::playerTwoWarning: return '2'; case fieldStruct::playerTwo:
case fieldStruct::playerBothWarning: return '3'; return 'x';
case fieldStruct::squareIsFree: return ' '; case fieldStruct::playerOneWarning:
return '1';
case fieldStruct::playerTwoWarning:
return '2';
case fieldStruct::playerBothWarning:
return '3';
case fieldStruct::squareIsFree:
return ' ';
} }
return 'f'; return 'f';
} }
@ -75,13 +93,15 @@ void fieldStruct::copyBoard(fieldStruct *destination)
destination->settingPhase = this->settingPhase; destination->settingPhase = this->settingPhase;
destination->stoneMustBeRemoved = this->stoneMustBeRemoved; 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->board[i] = this->board[i];
destination->warnings[i] = this->warnings[i]; destination->warnings[i] = this->warnings[i];
destination->stonePartOfMill[i] = this->stonePartOfMill[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->connectedSquare[i][j] = this->connectedSquare[i][j];
destination->stoneMoveAble[i][j] = this->stoneMoveAble[i][j]; destination->stoneMoveAble[i][j] = this->stoneMoveAble[i][j];
@ -104,11 +124,12 @@ void Player::copyPlayer(Player *destination)
destination->warning = this->warning; destination->warning = this->warning;
destination->numPossibleMoves = this->numPossibleMoves; 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++)
for (i = 0; i < MAX_NUM_POS_MOVES; i++) destination->posTo[i] = this->posTo[i]; destination->posFrom[i] = this->posFrom[i];
for (i = 0; i < MAX_NUM_POS_MOVES; i++)
destination->posTo[i] = this->posTo[i];
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: createBoard() // Name: createBoard()
// Desc: Creates, but doesn't initialize, the arrays of the of the passed board structure. // 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; oppPlayer->numStonesMissing = 0;
// zero // zero
for (i = 0; i < size; i++) { for (i = 0; i < size; i++)
{
board[i] = squareIsFree; board[i] = squareIsFree;
warnings[i] = noWarning; warnings[i] = noWarning;
stonePartOfMill[i] = 0; stonePartOfMill[i] = 0;
@ -203,7 +225,7 @@ void fieldStruct::createBoard()
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: deleteBoard() // Name: deleteBoard()
// Desc: ... // Desc: ...
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void fieldStruct::deleteBoard() void fieldStruct::deleteBoard()
{ {
@ -213,7 +235,7 @@ void fieldStruct::deleteBoard()
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: setConnection() // Name: setConnection()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
inline void fieldStruct::setConnection(unsigned int index, int firstDirection, int secondDirection, int thirdDirection, int fourthDirection) 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() // Name: setNeighbour()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
inline void fieldStruct::setNeighbour(unsigned int index, unsigned int firstNeighbour0, unsigned int secondNeighbour0, unsigned int firstNeighbour1, unsigned int secondNeighbour1) inline void fieldStruct::setNeighbour(unsigned int index, unsigned int firstNeighbour0, unsigned int secondNeighbour0, unsigned int firstNeighbour1, unsigned int secondNeighbour1)
{ {

View File

@ -15,72 +15,78 @@
//using namespace std; //using namespace std;
/*** Konstanten ******************************************************/ /*** Konstanten ******************************************************/
#define MAX_NUM_POS_MOVES (3 * 18) // not (9 * 4) = 36 since the possibilities with 3 stones are more #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 SAFE_DELETE(p) \
{ \
if (p) \
{ \
delete (p); \
(p) = nullptr; \
} \
}
/*** Klassen *********************************************************/ /*** Klassen *********************************************************/
class Player class Player
{ {
public: public:
int id; // static int id; // static
unsigned int warning; // static unsigned int warning; // static
unsigned int numStones; // number of stones of this player on the board 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 numStonesMissing; // number of stones, which where stolen by the opponent
unsigned int numPossibleMoves; // amount of possible moves unsigned int numPossibleMoves; // amount of possible moves
unsigned int posTo[MAX_NUM_POS_MOVES]; // target board position of a possible move 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 unsigned int posFrom[MAX_NUM_POS_MOVES]; // source board position of a possible move
void copyPlayer(Player *destination); void copyPlayer(Player *destination);
}; };
class fieldStruct class fieldStruct
{ {
public: public:
// constants // constants
static const int squareIsFree = 0; // trivial static const int squareIsFree = 0; // trivial
static const int playerOne = -1; // so rowOwner can be calculated easy static const int playerOne = -1; // so rowOwner can be calculated easy
static const int playerTwo = 1; static const int playerTwo = 1;
static const int playerBlack = -1; // so rowOwner can be calculated easy static const int playerBlack = -1; // so rowOwner can be calculated easy
static const int playerWhite = 1; 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 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 playerOneWarning = 2;
static const unsigned int playerTwoWarning = 4; static const unsigned int playerTwoWarning = 4;
static const unsigned int playerBothWarning = 6; static const unsigned int playerBothWarning = 6;
static const unsigned int numStonesPerPlayer = 9; static const unsigned int numStonesPerPlayer = 9;
static const unsigned int size = 24; // number of squares static const unsigned int size = 24; // number of squares
static const int gameDrawn = 3; // only a nonzero value static const int gameDrawn = 3; // only a nonzero value
// variables // variables
int board[size]; // one of the values above for each board position int board[size]; // one of the values above for each board position
unsigned int warnings[size]; // array containing the warnings 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 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 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 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 neighbour[size][2][2]; // static array containing the two neighbours of each squares
unsigned int stonesSet; // number of stones set in the setting phase unsigned int stonesSet; // number of stones set in the setting phase
bool settingPhase; // true if stonesSet < 18 bool settingPhase; // true if stonesSet < 18
unsigned int stoneMustBeRemoved; // number of stones which must be removed by the current player unsigned int stoneMustBeRemoved; // number of stones which must be removed by the current player
Player *curPlayer, *oppPlayer; // pointers to the current and opponent player Player *curPlayer, *oppPlayer; // pointers to the current and opponent player
// useful functions // useful functions
void printBoard(); void printBoard();
void copyBoard(fieldStruct *destination); void copyBoard(fieldStruct *destination);
void createBoard(); void createBoard();
void deleteBoard(); void deleteBoard();
private: private:
// helper functions // helper functions
char GetCharFromStone(int stone); char GetCharFromStone(int stone);
void setConnection(unsigned int index, int firstDirection, int secondDirection, int thirdDirection, int fourthDirection); 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); void setNeighbour(unsigned int index, unsigned int firstNeighbour0, unsigned int secondNeighbour0, unsigned int firstNeighbour1, unsigned int secondNeighbour1);
}; };
class MillAI abstract class MillAI abstract
{ {
protected: protected:
fieldStruct dummyField; fieldStruct dummyField;
public: public:
// Constructor / destructor // Constructor / destructor
@ -94,7 +100,7 @@ public:
}; };
// Functions // 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 #endif

View File

@ -27,7 +27,7 @@ MiniMaxAI::~MiniMaxAI()
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: play() // Name: play()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void MiniMaxAI::play(fieldStruct *theField, unsigned int *pushFrom, unsigned int *pushTo) 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; field = theField;
ownId = field->curPlayer->id; ownId = field->curPlayer->id;
curSearchDepth = 0; curSearchDepth = 0;
unsigned int bestChoice; unsigned int bestChoice;
unsigned int searchDepth; unsigned int searchDepth;
// automatic depth // automatic depth
if (depthOfFullTree == 0) { if (depthOfFullTree == 0)
if (theField->settingPhase) searchDepth = 5; {
else if (theField->curPlayer->numStones <= 4) searchDepth = 7; if (theField->settingPhase)
else if (theField->oppPlayer->numStones <= 4) searchDepth = 7; searchDepth = 5;
else searchDepth = 7; else if (theField->curPlayer->numStones <= 4)
} else { searchDepth = 7;
else if (theField->oppPlayer->numStones <= 4)
searchDepth = 7;
else
searchDepth = 7;
}
else
{
searchDepth = depthOfFullTree; 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); Possibility *rootPossibilities = (Possibility *)getBestChoice(searchDepth, &bestChoice, MAX_NUM_POS_MOVES);
// decode the best choice // decode the best choice
if (field->stoneMustBeRemoved) { if (field->stoneMustBeRemoved)
*pushFrom = bestChoice; *pushTo = 0; {
} else if (field->settingPhase) { *pushFrom = bestChoice;
*pushFrom = 0; *pushTo = bestChoice; *pushTo = 0;
} else { }
else if (field->settingPhase)
{
*pushFrom = 0;
*pushTo = bestChoice;
}
else
{
*pushFrom = rootPossibilities->from[bestChoice]; *pushFrom = rootPossibilities->from[bestChoice];
*pushTo = rootPossibilities->to[bestChoice]; *pushTo = rootPossibilities->to[bestChoice];
} }
@ -80,7 +94,7 @@ void MiniMaxAI::play(fieldStruct *theField, unsigned int *pushFrom, unsigned int
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: setSearchDepth() // Name: setSearchDepth()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void MiniMaxAI::setSearchDepth(unsigned int depth) void MiniMaxAI::setSearchDepth(unsigned int depth)
{ {
@ -89,7 +103,7 @@ void MiniMaxAI::setSearchDepth(unsigned int depth)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: prepareBestChoiceCalculation() // Name: prepareBestChoiceCalculation()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void MiniMaxAI::prepareBestChoiceCalculation() void MiniMaxAI::prepareBestChoiceCalculation()
{ {
@ -100,7 +114,7 @@ void MiniMaxAI::prepareBestChoiceCalculation()
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: getPossSettingPhase() // Name: getPossSettingPhase()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
unsigned int *MiniMaxAI::getPossSettingPhase(unsigned int *numPossibilities, void **pPossibilities) 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]; unsigned int *idPossibility = &idPossibilities[curSearchDepth * MAX_NUM_POS_MOVES];
// possibilities with cut off // possibilities with cut off
for ((*numPossibilities) = 0, i = 0; i < field->size; i++) { for ((*numPossibilities) = 0, i = 0; i < field->size; i++)
{
// move possible ? // move possible ?
if (field->board[i] == field->squareIsFree) { if (field->board[i] == field->squareIsFree)
{
idPossibility[*numPossibilities] = i; idPossibility[*numPossibilities] = i;
(*numPossibilities)++; (*numPossibilities)++;
@ -127,26 +143,30 @@ unsigned int *MiniMaxAI::getPossSettingPhase(unsigned int *numPossibilities, voi
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: getPossNormalMove() // Name: getPossNormalMove()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
unsigned int *MiniMaxAI::getPossNormalMove(unsigned int *numPossibilities, void **pPossibilities) unsigned int *MiniMaxAI::getPossNormalMove(unsigned int *numPossibilities, void **pPossibilities)
{ {
// locals // locals
unsigned int from, to, dir; unsigned int from, to, dir;
unsigned int *idPossibility = &idPossibilities[curSearchDepth * MAX_NUM_POS_MOVES]; unsigned int *idPossibility = &idPossibilities[curSearchDepth * MAX_NUM_POS_MOVES];
Possibility *possibility = &possibilities[curSearchDepth]; Possibility *possibility = &possibilities[curSearchDepth];
// if he is not allowed to spring // 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 ((*numPossibilities) = 0, from = 0; from < field->size; from++)
for (dir = 0; dir < 4; dir++) { {
for (dir = 0; dir < 4; dir++)
{
// destination // destination
to = field->connectedSquare[from][dir]; to = field->connectedSquare[from][dir];
// move possible ? // 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 // stone is moveable
idPossibility[*numPossibilities] = *numPossibilities; 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 ((*numPossibilities) = 0, from = 0; from < field->size; from++)
for (to = 0; to < field->size; to++) { {
for (to = 0; to < field->size; to++)
{
// move possible ? // 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 // stone is moveable
idPossibility[*numPossibilities] = *numPossibilities; idPossibility[*numPossibilities] = *numPossibilities;
@ -184,7 +209,7 @@ unsigned int *MiniMaxAI::getPossNormalMove(unsigned int *numPossibilities, void
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: getPossStoneRemove() // Name: getPossStoneRemove()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
unsigned int *MiniMaxAI::getPossStoneRemove(unsigned int *numPossibilities, void **pPossibilities) 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]; unsigned int *idPossibility = &idPossibilities[curSearchDepth * MAX_NUM_POS_MOVES];
// possibilities with cut off // possibilities with cut off
for ((*numPossibilities) = 0, i = 0; i < field->size; i++) { for ((*numPossibilities) = 0, i = 0; i < field->size; i++)
{
// move possible ? // 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; idPossibility[*numPossibilities] = i;
(*numPossibilities)++; (*numPossibilities)++;
@ -211,7 +238,7 @@ unsigned int *MiniMaxAI::getPossStoneRemove(unsigned int *numPossibilities, void
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: getPossibilities() // Name: getPossibilities()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
unsigned int *MiniMaxAI::getPossibilities(unsigned int threadNo, unsigned int *numPossibilities, bool *opponentsMove, void **pPossibilities) 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; *opponentsMove = (field->curPlayer->id == ownId) ? false : true;
// When game has ended of course nothing happens any more // When game has ended of course nothing happens any more
if (gameHasFinished) { if (gameHasFinished)
{
*numPossibilities = 0; *numPossibilities = 0;
return 0; return 0;
// look what is to do // look what is to do
} else { }
if (field->stoneMustBeRemoved) return getPossStoneRemove(numPossibilities, pPossibilities); else
else if (field->settingPhase) return getPossSettingPhase(numPossibilities, pPossibilities); {
else return getPossNormalMove(numPossibilities, pPossibilities); if (field->stoneMustBeRemoved)
return getPossStoneRemove(numPossibilities, pPossibilities);
else if (field->settingPhase)
return getPossSettingPhase(numPossibilities, pPossibilities);
else
return getPossNormalMove(numPossibilities, pPossibilities);
} }
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: getValueOfSituation() // Name: getValueOfSituation()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void MiniMaxAI::getValueOfSituation(unsigned int threadNo, float &floatValue, TwoBit &shortValue) 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() // Name: deletePossibilities()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void MiniMaxAI::deletePossibilities(unsigned int threadNo, void *pPossibilities) void MiniMaxAI::deletePossibilities(unsigned int threadNo, void *pPossibilities)
{ {
@ -250,7 +283,7 @@ void MiniMaxAI::deletePossibilities(unsigned int threadNo, void *pPossibilities)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: undo() // Name: undo()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void MiniMaxAI::undo(unsigned int threadNo, unsigned int idPossibility, bool opponentsMove, void *pBackup, void *pPossibilities) 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; field->board[oldState->to] = oldState->fieldTo;
// very expensive // 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->stonePartOfMill[i] = oldState->stonePartOfMill[i];
field->warnings[i] = oldState->warnings[i]; field->warnings[i] = oldState->warnings[i];
} }
@ -285,12 +319,13 @@ void MiniMaxAI::undo(unsigned int threadNo, unsigned int idPossibility, bool opp
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: setWarning() // Name: setWarning()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
inline void MiniMaxAI::setWarning(unsigned int stoneOne, unsigned int stoneTwo, unsigned int stoneThree) 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 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[stoneOne]++;
field->stonePartOfMill[stoneTwo]++; field->stonePartOfMill[stoneTwo]++;
@ -299,7 +334,8 @@ inline void MiniMaxAI::setWarning(unsigned int stoneOne, unsigned int stoneTwo,
} }
// is a mill destroyed ? // 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[stoneOne]--;
field->stonePartOfMill[stoneTwo]--; field->stonePartOfMill[stoneTwo]--;
@ -307,116 +343,159 @@ inline void MiniMaxAI::setWarning(unsigned int stoneOne, unsigned int stoneTwo,
} }
// stone was set // stone was set
if (field->board[stoneOne] == field->curPlayer->id) { if (field->board[stoneOne] == field->curPlayer->id)
{
// a warnig was destroyed // a warnig was destroyed
field->warnings[stoneOne] = field->noWarning; field->warnings[stoneOne] = field->noWarning;
// a warning is created // 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[stoneTwo] == field->curPlayer->id && field->board[stoneThree] == field->squareIsFree)
if (field->board[stoneThree] == field->curPlayer->id && field->board[stoneTwo] == field->squareIsFree) field->warnings[stoneTwo] |= field->curPlayer->warning; 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 // stone was removed
} else if (field->board[stoneOne] == field->squareIsFree) { }
else if (field->board[stoneOne] == field->squareIsFree)
{
// a warning is created // 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->curPlayer->id && field->board[stoneThree] == field->curPlayer->id)
if (field->board[stoneTwo] == field->oppPlayer->id && field->board[stoneThree] == field->oppPlayer->id) field->warnings[stoneOne] |= field->oppPlayer->warning; 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 // 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 // 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; if (field->board[field->neighbour[stoneTwo][0][0]] == field->curPlayer->id && field->board[field->neighbour[stoneTwo][0][1]] == field->curPlayer->id)
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; 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->curPlayer->id && field->board[field->neighbour[stoneTwo][1][1]] == field->curPlayer->id)
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; field->warnings[stoneTwo] = field->curPlayer->warning;
else field->warnings[stoneTwo] = field->noWarning; 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->warnings[stoneThree] && field->board[stoneTwo] != field->squareIsFree) { 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 // 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; if (field->board[field->neighbour[stoneThree][0][0]] == field->curPlayer->id && field->board[field->neighbour[stoneThree][0][1]] == field->curPlayer->id)
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; 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->curPlayer->id && field->board[field->neighbour[stoneThree][1][1]] == field->curPlayer->id)
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; field->warnings[stoneThree] = field->curPlayer->warning;
else field->warnings[stoneThree] = field->noWarning; 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() // Name: updateWarning()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
inline void MiniMaxAI::updateWarning(unsigned int firstStone, unsigned int secondStone) inline void MiniMaxAI::updateWarning(unsigned int firstStone, unsigned int secondStone)
{ {
// set warnings // set warnings
if (firstStone < field->size) setWarning(firstStone, field->neighbour[firstStone][0][0], field->neighbour[firstStone][0][1]); if (firstStone < field->size)
if (firstStone < field->size) setWarning(firstStone, field->neighbour[firstStone][1][0], field->neighbour[firstStone][1][1]); 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)
if (secondStone < field->size) setWarning(secondStone, field->neighbour[secondStone][1][0], field->neighbour[secondStone][1][1]); 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 // no stone must be removed if each belongs to a mill
unsigned int i; unsigned int i;
bool atLeastOneStoneRemoveAble = false; bool atLeastOneStoneRemoveAble = false;
if (field->stoneMustBeRemoved) for (i = 0; i < field->size; i++) if (field->stonePartOfMill[i] == 0 && field->board[i] == field->oppPlayer->id) { if (field->stoneMustBeRemoved)
atLeastOneStoneRemoveAble = true; break; for (i = 0; i < field->size; i++)
} if (field->stonePartOfMill[i] == 0 && field->board[i] == field->oppPlayer->id)
if (!atLeastOneStoneRemoveAble) field->stoneMustBeRemoved = 0; {
atLeastOneStoneRemoveAble = true;
break;
}
if (!atLeastOneStoneRemoveAble)
field->stoneMustBeRemoved = 0;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: updatePossibleMoves() // Name: updatePossibleMoves()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
inline void MiniMaxAI::updatePossibleMoves(unsigned int stone, Player *stoneOwner, bool stoneRemoved, unsigned int ignoreStone) inline void MiniMaxAI::updatePossibleMoves(unsigned int stone, Player *stoneOwner, bool stoneRemoved, unsigned int ignoreStone)
{ {
// locals // locals
unsigned int neighbor, direction; unsigned int neighbor, direction;
// look into every direction // look into every direction
for (direction = 0; direction < 4; direction++) { for (direction = 0; direction < 4; direction++)
{
neighbor = field->connectedSquare[stone][direction]; neighbor = field->connectedSquare[stone][direction];
// neighbor must exist // neighbor must exist
if (neighbor < field->size) { if (neighbor < field->size)
{
// relevant when moving from one square to another connected square // 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 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--; if (stoneRemoved)
else stoneOwner->numPossibleMoves++; stoneOwner->numPossibleMoves--;
else
stoneOwner->numPossibleMoves++;
// if there is a neighbour stone than it effects only this one // 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++; if (stoneRemoved)
else field->curPlayer->numPossibleMoves--; field->curPlayer->numPossibleMoves++;
else
field->curPlayer->numPossibleMoves--;
}
else
{
} else { if (stoneRemoved)
field->oppPlayer->numPossibleMoves++;
if (stoneRemoved) field->oppPlayer->numPossibleMoves++; else
else field->oppPlayer->numPossibleMoves--; field->oppPlayer->numPossibleMoves--;
} }
} }
} }
// only 3 stones resting // 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->curPlayer->numStones <= 3 && !field->settingPhase)
if (field->oppPlayer->numStones <= 3 && !field->settingPhase) field->oppPlayer->numPossibleMoves = field->oppPlayer->numStones * (field->size - field->curPlayer->numStones - field->oppPlayer->numStones); 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() // Name: setStone()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
inline void MiniMaxAI::setStone(unsigned int to, Backup *backup) inline void MiniMaxAI::setStone(unsigned int to, Backup *backup)
{ {
// backup // backup
backup->from = field->size; backup->from = field->size;
@ -430,7 +509,8 @@ inline void MiniMaxAI::setStone(unsigned int to, Backup *backup)
field->stonesSet++; field->stonesSet++;
// setting phase finished ? // setting phase finished ?
if (field->stonesSet == 18) field->settingPhase = false; if (field->stonesSet == 18)
field->settingPhase = false;
// update possible moves // update possible moves
updatePossibleMoves(to, field->curPlayer, false, field->size); updatePossibleMoves(to, field->curPlayer, false, field->size);
@ -441,9 +521,9 @@ inline void MiniMaxAI::setStone(unsigned int to, Backup *backup)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: normalMove() // 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
backup->from = from; backup->from = from;
@ -465,7 +545,7 @@ inline void MiniMaxAI::normalMove(unsigned int from, unsigned int to, Backup *ba
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: removeStone() // Name: removeStone()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
inline void MiniMaxAI::removeStone(unsigned int from, Backup *backup) 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); updateWarning(from, field->size);
// end of game ? // end of game ?
if ((field->oppPlayer->numStones < 3) && (!field->settingPhase)) gameHasFinished = true; if ((field->oppPlayer->numStones < 3) && (!field->settingPhase))
gameHasFinished = true;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: move() // Name: move()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void MiniMaxAI::move(unsigned int threadNo, unsigned int idPossibility, bool opponentsMove, void **pBackup, void *pPossibilities) 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]; Backup *oldState = &oldStates[curSearchDepth];
Possibility *tmpPossibility = (Possibility *)pPossibilities; Possibility *tmpPossibility = (Possibility *)pPossibilities;
Player *tmpPlayer; Player *tmpPlayer;
unsigned int i; unsigned int i;
// calculate place of stone // calculate place of stone
*pBackup = (void *)oldState; *pBackup = (void *)oldState;
@ -521,33 +602,45 @@ void MiniMaxAI::move(unsigned int threadNo, unsigned int idPossibility, bool opp
curSearchDepth++; curSearchDepth++;
// very expensive // very expensive
for (i = 0; i < field->size; i++) { for (i = 0; i < field->size; i++)
{
oldState->stonePartOfMill[i] = field->stonePartOfMill[i]; oldState->stonePartOfMill[i] = field->stonePartOfMill[i];
oldState->warnings[i] = field->warnings[i]; oldState->warnings[i] = field->warnings[i];
} }
// move // move
if (field->stoneMustBeRemoved) { if (field->stoneMustBeRemoved)
{
removeStone(idPossibility, oldState); removeStone(idPossibility, oldState);
} else if (field->settingPhase) { }
else if (field->settingPhase)
{
setStone(idPossibility, oldState); setStone(idPossibility, oldState);
} else { }
else
{
normalMove(tmpPossibility->from[idPossibility], tmpPossibility->to[idPossibility], oldState); normalMove(tmpPossibility->from[idPossibility], tmpPossibility->to[idPossibility], oldState);
} }
// when opponent is unable to move than current player has won // 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 // calc value
if (!opponentsMove) currentValue = (float)field->oppPlayer->numStonesMissing - field->curPlayer->numStonesMissing + field->stoneMustBeRemoved + field->curPlayer->numPossibleMoves * 0.1f - field->oppPlayer->numPossibleMoves * 0.1f; if (!opponentsMove)
else currentValue = (float)field->curPlayer->numStonesMissing - field->oppPlayer->numStonesMissing - field->stoneMustBeRemoved + field->oppPlayer->numPossibleMoves * 0.1f - field->curPlayer->numPossibleMoves * 0.1f; 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 // when game has finished - perfect for the current player
if (gameHasFinished && !opponentsMove) currentValue = VALUE_GAME_WON - curSearchDepth; if (gameHasFinished && !opponentsMove)
if (gameHasFinished && opponentsMove) currentValue = VALUE_GAME_LOST + curSearchDepth; currentValue = VALUE_GAME_WON - curSearchDepth;
if (gameHasFinished && opponentsMove)
currentValue = VALUE_GAME_LOST + curSearchDepth;
// set next player // set next player
if (!field->stoneMustBeRemoved) { if (!field->stoneMustBeRemoved)
{
tmpPlayer = field->curPlayer; tmpPlayer = field->curPlayer;
field->curPlayer = field->oppPlayer; field->curPlayer = field->oppPlayer;
field->oppPlayer = tmpPlayer; field->oppPlayer = tmpPlayer;
@ -556,7 +649,7 @@ void MiniMaxAI::move(unsigned int threadNo, unsigned int idPossibility, bool opp
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: printMoveInformation() // Name: printMoveInformation()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void MiniMaxAI::printMoveInformation(unsigned int threadNo, unsigned int idPossibility, void *pPossibilities) 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; Possibility *tmpPossibility = (Possibility *)pPossibilities;
// move // move
if (field->stoneMustBeRemoved) cout << "remove stone from " << (char)(idPossibility + 97); if (field->stoneMustBeRemoved)
else if (field->settingPhase) cout << "set stone to " << (char)(idPossibility + 97); cout << "remove stone from " << (char)(idPossibility + 97);
else cout << "move from " << (char)(tmpPossibility->from[idPossibility] + 97) << " to " << (char)(tmpPossibility->to[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);
} }

View File

@ -44,12 +44,15 @@ MiniMax::MiniMax()
numWriteSkvOperations = 0; numWriteSkvOperations = 0;
numReadPlyOperations = 0; numReadPlyOperations = 0;
numWritePlyOperations = 0; numWritePlyOperations = 0;
if (MEASURE_ONLY_IO) { if (MEASURE_ONLY_IO)
{
readSkvInterval.QuadPart = 0; readSkvInterval.QuadPart = 0;
writeSkvInterval.QuadPart = 0; writeSkvInterval.QuadPart = 0;
readPlyInterval.QuadPart = 0; readPlyInterval.QuadPart = 0;
writePlyInterval.QuadPart = 0; writePlyInterval.QuadPart = 0;
} else { }
else
{
QueryPerformanceCounter(&readSkvInterval); QueryPerformanceCounter(&readSkvInterval);
QueryPerformanceCounter(&writeSkvInterval); QueryPerformanceCounter(&writeSkvInterval);
QueryPerformanceCounter(&readPlyInterval); 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_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. // PL_TO_MOVE_UNCHANGED means that the player to move is still the one who shall move.
unsigned char skvPerspectiveMatrixTmp[4][2] = { unsigned char skvPerspectiveMatrixTmp[4][2] = {
// PL_TO_MOVE_UNCHANGED PL_TO_MOVE_CHANGED // PL_TO_MOVE_UNCHANGED PL_TO_MOVE_CHANGED
SKV_VALUE_INVALID, SKV_VALUE_INVALID, // SKV_VALUE_INVALID SKV_VALUE_INVALID, SKV_VALUE_INVALID, // SKV_VALUE_INVALID
SKV_VALUE_GAME_WON, SKV_VALUE_GAME_LOST, // SKV_VALUE_GAME_LOST 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_DRAWN, SKV_VALUE_GAME_DRAWN, // SKV_VALUE_GAME_DRAWN
SKV_VALUE_GAME_LOST, SKV_VALUE_GAME_WON // SKV_VALUE_GAME_WON SKV_VALUE_GAME_LOST, SKV_VALUE_GAME_WON // SKV_VALUE_GAME_WON
}; };
memcpy(skvPerspectiveMatrix, skvPerspectiveMatrixTmp, 4 * 2); memcpy(skvPerspectiveMatrix, skvPerspectiveMatrixTmp, 4 * 2);
@ -84,11 +87,12 @@ MiniMax::~MiniMax()
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: falseOrStop() // Name: falseOrStop()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
bool MiniMax::falseOrStop() bool MiniMax::falseOrStop()
{ {
if (stopOnCriticalError) WaitForSingleObject(GetCurrentProcess(), INFINITE); if (stopOnCriticalError)
WaitForSingleObject(GetCurrentProcess(), INFINITE);
return false; return false;
} }
@ -105,9 +109,9 @@ void *MiniMax::getBestChoice(unsigned int tilLevel, unsigned int *choice, unsign
calcDatabase = false; calcDatabase = false;
// Locals // Locals
Node root; Node root;
AlphaBetaGlobalVars alphaBetaVars(this, getLayerNumber(0)); AlphaBetaGlobalVars alphaBetaVars(this, getLayerNumber(0));
RunAlphaBetaVars tva(this, &alphaBetaVars, alphaBetaVars.layerNumber); RunAlphaBetaVars tva(this, &alphaBetaVars, alphaBetaVars.layerNumber);
srand((unsigned int)time(nullptr)); srand((unsigned int)time(nullptr));
tva.curThreadNo = 0; 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) void MiniMax::calculateDatabase(unsigned int maxDepthOfTree, bool onlyPrepareLayer)
{ {
// locals // locals
bool abortCalculation = false; bool abortCalculation = false;
this->onlyPrepareLayer = onlyPrepareLayer; this->onlyPrepareLayer = onlyPrepareLayer;
lastCalculatedLayer.clear(); lastCalculatedLayer.clear();
@ -143,7 +147,8 @@ void MiniMax::calculateDatabase(unsigned int maxDepthOfTree, bool onlyPrepareLay
prepareDatabaseCalculation(); prepareDatabaseCalculation();
// when database not completed then do it // when database not completed then do it
if (hFileShortKnotValues != nullptr && skvfHeader.completed == false) { if (hFileShortKnotValues != nullptr && skvfHeader.completed == false)
{
// reserve memory // reserve memory
lastCalculatedLayer.clear(); lastCalculatedLayer.clear();
@ -154,13 +159,16 @@ void MiniMax::calculateDatabase(unsigned int maxDepthOfTree, bool onlyPrepareLay
arrayInfos.vectorArrays.resize(ArrayInfo::numArrayTypes * skvfHeader.numLayers, arrayInfos.listArrays.end()); arrayInfos.vectorArrays.resize(ArrayInfo::numArrayTypes * skvfHeader.numLayers, arrayInfos.listArrays.end());
// calc layer after layer, beginning with the last one // 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? // 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 // 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 // calc
abortCalculation = (!calcLayer(curCalculatedLayer)); abortCalculation = (!calcLayer(curCalculatedLayer));
@ -170,17 +178,21 @@ void MiniMax::calculateDatabase(unsigned int maxDepthOfTree, bool onlyPrepareLay
unloadAllPlyInfos(); unloadAllPlyInfos();
// don't save layer and header when only preparing layers // don't save layer and header when only preparing layers
if (onlyPrepareLayer) return; if (onlyPrepareLayer)
if (abortCalculation) break; return;
if (abortCalculation)
break;
// save header // save header
saveHeader(&skvfHeader, layerStats); saveHeader(&skvfHeader, layerStats);
saveHeader(&plyInfoHeader, plyInfos); saveHeader(&plyInfoHeader, plyInfos);
} }
// don't save layer and header when only preparing layers or when // don't save layer and header when only preparing layers or when
if (onlyPrepareLayer) return; if (onlyPrepareLayer)
if (!abortCalculation) { return;
if (!abortCalculation)
{
// calc layer statistics // calc layer statistics
calcLayerStatistics("statistics.txt"); calcLayerStatistics("statistics.txt");
@ -194,7 +206,9 @@ void MiniMax::calculateDatabase(unsigned int maxDepthOfTree, bool onlyPrepareLay
// free mem // free mem
curCalculationActionId = MM_ACTION_NONE; curCalculationActionId = MM_ACTION_NONE;
} else { }
else
{
PRINT(1, this, "\nThe database is already fully calculated.\n"); PRINT(1, this, "\nThe database is already fully calculated.\n");
} }
@ -208,43 +222,53 @@ void MiniMax::calculateDatabase(unsigned int maxDepthOfTree, bool onlyPrepareLay
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: calcLayer() // Name: calcLayer()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
bool MiniMax::calcLayer(unsigned int layerNumber) bool MiniMax::calcLayer(unsigned int layerNumber)
{ {
// locals // locals
vector <unsigned int> layersToCalculate; vector<unsigned int> layersToCalculate;
// moves can be done reverse, leading to too depth searching trees // moves can be done reverse, leading to too depth searching trees
if (shallRetroAnalysisBeUsed(layerNumber)) { if (shallRetroAnalysisBeUsed(layerNumber))
{
// calc values for all states of layer // calc values for all states of layer
layersToCalculate.push_back(layerNumber); layersToCalculate.push_back(layerNumber);
if (layerNumber != layerStats[layerNumber].partnerLayer) layersToCalculate.push_back(layerStats[layerNumber].partnerLayer); if (layerNumber != layerStats[layerNumber].partnerLayer)
if (!calcKnotValuesByRetroAnalysis(layersToCalculate)) return false; layersToCalculate.push_back(layerStats[layerNumber].partnerLayer);
if (!calcKnotValuesByRetroAnalysis(layersToCalculate))
return false;
// save partner layer // save partner layer
if (layerStats[layerNumber].partnerLayer != layerNumber) { if (layerStats[layerNumber].partnerLayer != layerNumber)
{
saveLayerToFile(layerStats[layerNumber].partnerLayer); saveLayerToFile(layerStats[layerNumber].partnerLayer);
} }
// use minimax-algorithm // use minimax-algorithm
} else { }
if (!calcKnotValuesByAlphaBeta(layerNumber)) return false; else
{
if (!calcKnotValuesByAlphaBeta(layerNumber))
return false;
} }
// save layer // save layer
saveLayerToFile(layerNumber); saveLayerToFile(layerNumber);
// test layer // test layer
if (!testLayer(layerNumber)) { if (!testLayer(layerNumber))
{
PRINT(0, this, "ERROR: Layer calculation cancelled or failed!" << endl); PRINT(0, this, "ERROR: Layer calculation cancelled or failed!" << endl);
return false; return false;
} }
// test partner layer if retro-analysis has been used // test partner layer if retro-analysis has been used
if (shallRetroAnalysisBeUsed(layerNumber) && layerStats[layerNumber].partnerLayer != layerNumber) { if (shallRetroAnalysisBeUsed(layerNumber) && layerStats[layerNumber].partnerLayer != layerNumber)
if (!testLayer(layerStats[layerNumber].partnerLayer)) { {
if (!testLayer(layerStats[layerNumber].partnerLayer))
{
PRINT(0, this, "ERROR: Layer calculation cancelled or failed!" << endl); PRINT(0, this, "ERROR: Layer calculation cancelled or failed!" << endl);
return false; return false;
} }
@ -252,7 +276,8 @@ bool MiniMax::calcLayer(unsigned int layerNumber)
// update output information // update output information
EnterCriticalSection(&csOsPrint); 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(layerStats[layerNumber].partnerLayer);
} }
lastCalculatedLayer.push_back(layerNumber); lastCalculatedLayer.push_back(layerNumber);
@ -263,7 +288,7 @@ bool MiniMax::calcLayer(unsigned int layerNumber)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: pauseDatabaseCalculation() // Name: pauseDatabaseCalculation()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void MiniMax::pauseDatabaseCalculation() void MiniMax::pauseDatabaseCalculation()
{ {
@ -272,7 +297,7 @@ void MiniMax::pauseDatabaseCalculation()
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: cancelDatabaseCalculation() // Name: cancelDatabaseCalculation()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void MiniMax::cancelDatabaseCalculation() void MiniMax::cancelDatabaseCalculation()
{ {
@ -282,7 +307,7 @@ void MiniMax::cancelDatabaseCalculation()
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: wasDatabaseCalculationCancelled() // Name: wasDatabaseCalculationCancelled()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
bool MiniMax::wasDatabaseCalculationCancelled() bool MiniMax::wasDatabaseCalculationCancelled()
{ {

File diff suppressed because it is too large Load Diff

View File

@ -17,14 +17,13 @@
//using namespace std; //using namespace std;
#define VALUE_GAME_LOST -1000.0f #define VALUE_GAME_LOST -1000.0f
#define VALUE_GAME_WON 1000.0f #define VALUE_GAME_WON 1000.0f
/*** Klassen *********************************************************/ /*** Klassen *********************************************************/
class MiniMaxAI : public MillAI, MiniMax class MiniMaxAI : public MillAI, MiniMax
{ {
protected: protected:
// structs // structs
struct Possibility struct Possibility
{ {
@ -34,32 +33,32 @@ protected:
struct Backup struct Backup
{ {
float value; float value;
bool gameHasFinished; bool gameHasFinished;
bool settingPhase; bool settingPhase;
int fieldFrom, fieldTo; // value of board int fieldFrom, fieldTo; // value of board
unsigned int from, to; // index of board unsigned int from, to; // index of board
unsigned int curNumStones, oppNumStones; unsigned int curNumStones, oppNumStones;
unsigned int curPosMoves, oppPosMoves; unsigned int curPosMoves, oppPosMoves;
unsigned int curMissStones, oppMissStones; unsigned int curMissStones, oppMissStones;
unsigned int stonesSet; unsigned int stonesSet;
unsigned int stoneMustBeRemoved; unsigned int stoneMustBeRemoved;
unsigned int stonePartOfMill[fieldStruct::size]; unsigned int stonePartOfMill[fieldStruct::size];
unsigned int warnings[fieldStruct::size]; unsigned int warnings[fieldStruct::size];
Player *curPlayer, *oppPlayer; Player *curPlayer, *oppPlayer;
}; };
// Variables // Variables
fieldStruct *field; // pointer of the current board [changed by move()] fieldStruct *field; // pointer of the current board [changed by move()]
float currentValue; // value of current situation for board->currentPlayer float currentValue; // value of current situation for board->currentPlayer
bool gameHasFinished; // someone has won or current board is full bool gameHasFinished; // someone has won or current board is full
int ownId; // id of the player who called the play()-function int ownId; // id of the player who called the play()-function
unsigned int curSearchDepth; // current level unsigned int curSearchDepth; // current level
unsigned int depthOfFullTree; // search depth where the whole tree is explored unsigned int depthOfFullTree; // search depth where the whole tree is explored
unsigned int *idPossibilities; // returned pointer of getPossibilities()-function unsigned int *idPossibilities; // returned pointer of getPossibilities()-function
Backup *oldStates; // for undo()-function Backup *oldStates; // for undo()-function
Possibility *possibilities; // for getPossNormalMove()-function Possibility *possibilities; // for getPossNormalMove()-function
// Functions // Functions
unsigned int *getPossSettingPhase(unsigned int *numPossibilities, void **pPossibilities); unsigned int *getPossSettingPhase(unsigned int *numPossibilities, void **pPossibilities);
@ -67,75 +66,61 @@ protected:
unsigned int *getPossStoneRemove(unsigned int *numPossibilities, void **pPossibilities); unsigned int *getPossStoneRemove(unsigned int *numPossibilities, void **pPossibilities);
// move functions // move functions
inline void updatePossibleMoves(unsigned int stone, Player *stoneOwner, bool stoneRemoved, unsigned int ignoreStone); inline void updatePossibleMoves(unsigned int stone, Player *stoneOwner, bool stoneRemoved, unsigned int ignoreStone);
inline void updateWarning(unsigned int firstStone, unsigned int secondStone); inline void updateWarning(unsigned int firstStone, unsigned int secondStone);
inline void setWarning(unsigned int stoneOne, unsigned int stoneTwo, unsigned int stoneThree); inline void setWarning(unsigned int stoneOne, unsigned int stoneTwo, unsigned int stoneThree);
inline void removeStone(unsigned int from, Backup *backup); inline void removeStone(unsigned int from, Backup *backup);
inline void setStone(unsigned int to, Backup *backup); inline void setStone(unsigned int to, Backup *backup);
inline void normalMove(unsigned int from, unsigned int to, Backup *backup); inline void normalMove(unsigned int from, unsigned int to, Backup *backup);
// Virtual Functions // Virtual Functions
void prepareBestChoiceCalculation(); void prepareBestChoiceCalculation();
unsigned int *getPossibilities(unsigned int threadNo, unsigned int *numPossibilities, bool *opponentsMove, void **pPossibilities); unsigned int *getPossibilities(unsigned int threadNo, unsigned int *numPossibilities, bool *opponentsMove, void **pPossibilities);
void deletePossibilities(unsigned int threadNo, void *pPossibilities); void deletePossibilities(unsigned int threadNo, void *pPossibilities);
void move(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 undo(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 getValueOfSituation(unsigned int threadNo, float &floatValue, TwoBit &shortValue);
void printMoveInformation(unsigned int threadNo, unsigned int idPossibility, void *pPossibilities); void printMoveInformation(unsigned int threadNo, unsigned int idPossibility, void *pPossibilities);
unsigned int getNumberOfLayers() unsigned int getNumberOfLayers()
{ {
return 0; return 0;
}; };
unsigned int getNumberOfKnotsInLayer(unsigned int layerNum) unsigned int getNumberOfKnotsInLayer(unsigned int layerNum)
{ {
return 0; return 0;
}; };
void getSuccLayers(unsigned int layerNum, unsigned int *amountOfSuccLayers, unsigned int *succLayers) void getSuccLayers(unsigned int layerNum, unsigned int *amountOfSuccLayers, unsigned int *succLayers){};
{ unsigned int getPartnerLayer(unsigned int layerNum)
};
unsigned int getPartnerLayer(unsigned int layerNum)
{ {
return 0; return 0;
}; };
string getOutputInformation(unsigned int layerNum) string getOutputInformation(unsigned int layerNum)
{ {
return string(""); return string("");
}; };
void setOpponentLevel(unsigned int threadNo, bool isOpponentLevel) void setOpponentLevel(unsigned int threadNo, bool isOpponentLevel){};
{ bool setSituation(unsigned int threadNo, unsigned int layerNum, unsigned int stateNumber)
};
bool setSituation(unsigned int threadNo, unsigned int layerNum, unsigned int stateNumber)
{ {
return false; return false;
}; };
bool getOpponentLevel(unsigned int threadNo) bool getOpponentLevel(unsigned int threadNo)
{ {
return false; 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; return 0;
}; };
unsigned int getLayerNumber(unsigned int threadNo) unsigned int getLayerNumber(unsigned int threadNo)
{ {
return 0; return 0;
}; };
void getSymStateNumWithDoubles(unsigned int threadNo, unsigned int *numSymmetricStates, unsigned int **symStateNumbers) 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 getPredecessors(unsigned int threadNo, unsigned int *amountOfPred, RetroAnalysisPredVars *predVars) void prepareDatabaseCalculation(){};
{ void wrapUpDatabaseCalculation(bool calculationAborted){};
};
void printBoard(unsigned int threadNo, unsigned char value)
{
};
void prepareDatabaseCalculation()
{
};
void wrapUpDatabaseCalculation(bool calculationAborted)
{
};
public: public:
// Constructor / destructor // Constructor / destructor
@ -143,8 +128,8 @@ public:
~MiniMaxAI(); ~MiniMaxAI();
// Functions // Functions
void play(fieldStruct *theField, unsigned int *pushFrom, unsigned int *pushTo); void play(fieldStruct *theField, unsigned int *pushFrom, unsigned int *pushTo);
void setSearchDepth(unsigned int depth); void setSearchDepth(unsigned int depth);
}; };
#endif #endif

View File

@ -19,15 +19,9 @@
class MiniMaxGuiField class MiniMaxGuiField
{ {
public: public:
virtual void setAlignment(wildWeasel::alignment &newAlignment) virtual void setAlignment(wildWeasel::alignment &newAlignment){};
{ virtual void setVisibility(bool visible){};
}; virtual void setState(unsigned int curShowedLayer, MiniMax::StateNumberVarType curShowedState){};
virtual void setVisibility(bool visible)
{
};
virtual void setState(unsigned int curShowedLayer, MiniMax::StateNumberVarType curShowedState)
{
};
}; };
/*------------------------------------------------------------------------------------ /*------------------------------------------------------------------------------------
@ -58,25 +52,23 @@ public:
class MiniMaxWinInspectDb class MiniMaxWinInspectDb
{ {
protected: protected:
// General Variables // 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; MiniMaxGuiField *pGuiField = nullptr;
bool showingInspectionControls = false; bool showingInspectionControls = false;
unsigned int curShowedLayer = 0; // current showed layer unsigned int curShowedLayer = 0; // current showed layer
MiniMax::StateNumberVarType curShowedState = 0; // current showed state MiniMax::StateNumberVarType curShowedState = 0; // current showed state
const unsigned int scrollBarWidth = 20; const unsigned int scrollBarWidth = 20;
public: public:
// Constructor / destructor // Constructor / destructor
MiniMaxWinInspectDb(wildWeasel::masterMind *ww, MiniMax *pMiniMax, wildWeasel::alignment &amInspectDb, wildWeasel::font2D *font, wildWeasel::texture *textureLine, MiniMaxGuiField &guiField); MiniMaxWinInspectDb(wildWeasel::masterMind *ww, MiniMax *pMiniMax, wildWeasel::alignment &amInspectDb, wildWeasel::font2D *font, wildWeasel::texture *textureLine, MiniMaxGuiField &guiField);
~MiniMaxWinInspectDb(); ~MiniMaxWinInspectDb();
// Generals Functions // Generals Functions
bool createControls(); bool createControls();
bool showControls(bool visible); bool showControls(bool visible);
void resize(wildWeasel::alignment &rcNewArea); void resize(wildWeasel::alignment &rcNewArea);
}; };
/*------------------------------------------------------------------------------------ /*------------------------------------------------------------------------------------
@ -110,55 +102,51 @@ public:
class MiniMaxWinCalcDb class MiniMaxWinCalcDb
{ {
protected: protected:
// Calculation variables // Calculation variables
wildWeasel::masterMind *ww = nullptr; // pointer to engine wildWeasel::masterMind *ww = nullptr; // pointer to engine
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
ostream *outputStream = nullptr; // pointer to a stream for the console output of the calculation done by the class MiniMax 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 stringbuf outputStringBuf; // buffer linked to the stream, for reading out of the stream into the buffer
locale myLocale; // for formatting the output locale myLocale; // for formatting the output
queue<unsigned int> layersToTest; // layer numbers to be tested queue<unsigned int> layersToTest; // layer numbers to be tested
thread hThreadSolve; thread hThreadSolve;
thread hThreadTestLayer; thread hThreadTestLayer;
bool showingCalculationControls = false; bool showingCalculationControls = false;
bool threadSolveIsRunning = false; bool threadSolveIsRunning = false;
bool threadTestLayerIsRunning = false; bool threadTestLayerIsRunning = false;
condition_variable threadConditionVariable; condition_variable threadConditionVariable;
mutex threadMutex; mutex threadMutex;
// positions, metrics, sizes, dimensions // positions, metrics, sizes, dimensions
unsigned int listViewRowHeight = 20; // height in pixel of a single row unsigned int listViewRowHeight = 20; // height in pixel of a single row
const float defPixelDist = 15; // const float defPixelDist = 15; //
const float labelHeight = 30; // const float labelHeight = 30; //
const float buttonHeight = 30; // const float buttonHeight = 30; //
// Calculation Functions // Calculation Functions
void buttonFuncCalcStartOrContinue(void *pUser); void buttonFuncCalcStartOrContinue(void *pUser);
void buttonFuncCalcCancel(void *pUser); void buttonFuncCalcCancel(void *pUser);
void buttonFuncCalcPause(void *pUser); void buttonFuncCalcPause(void *pUser);
void buttonFuncCalcTest(); void buttonFuncCalcTest();
void buttonFuncCalcTestAll(void *pUser); void buttonFuncCalcTestAll(void *pUser);
void buttonFuncCalcTestLayer(void *pUser); void buttonFuncCalcTestLayer(void *pUser);
void lvSelectedLayerChanged(unsigned int row, unsigned int col, wildWeasel::guiElemEvFol *guiElem, void *pUser); void lvSelectedLayerChanged(unsigned int row, unsigned int col, wildWeasel::guiElemEvFol *guiElem, void *pUser);
static void updateOutputControls(void *pUser); static void updateOutputControls(void *pUser);
void updateListItemLayer(unsigned int layerNumber); void updateListItemLayer(unsigned int layerNumber);
void updateListItemArray(MiniMax::ArrayInfoChange infoChange); void updateListItemArray(MiniMax::ArrayInfoChange infoChange);
void threadSolve(); void threadSolve();
void threadProcTestLayer(); void threadProcTestLayer();
public: public:
// Constructor / destructor // Constructor / destructor
MiniMaxWinCalcDb(wildWeasel::masterMind *ww, MiniMax *pMiniMax, wildWeasel::alignment &amCalculation, wildWeasel::font2D *font, wildWeasel::texture *textureLine); MiniMaxWinCalcDb(wildWeasel::masterMind *ww, MiniMax *pMiniMax, wildWeasel::alignment &amCalculation, wildWeasel::font2D *font, wildWeasel::texture *textureLine);
~MiniMaxWinCalcDb(); ~MiniMaxWinCalcDb();
// Generals Functions // Generals Functions
bool createControls(); bool createControls();
void resize(wildWeasel::alignment &amNewArea); void resize(wildWeasel::alignment &amNewArea);
bool showControls(bool visible); bool showControls(bool visible);
bool isCalculationOngoing(); bool isCalculationOngoing();
MiniMax *getMinimaxPointer() MiniMax *getMinimaxPointer()
{ {
return pMiniMax; return pMiniMax;

View File

@ -15,21 +15,23 @@
bool MiniMax::calcKnotValuesByAlphaBeta(unsigned int layerNumber) bool MiniMax::calcKnotValuesByAlphaBeta(unsigned int layerNumber)
{ {
// locals // 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); PRINT(1, this, "*** Calculate layer " << layerNumber << " by alpha-beta-algorithmn ***" << endl);
curCalculationActionId = MM_ACTION_PERFORM_ALPHA_BETA; curCalculationActionId = MM_ACTION_PERFORM_ALPHA_BETA;
// initialization // initialization
PRINT(2, this, " Bytes in memory: " << memoryUsed2 << endl); PRINT(2, this, " Bytes in memory: " << memoryUsed2 << endl);
if (!initAlphaBeta(alphaBetaVars)) { if (!initAlphaBeta(alphaBetaVars))
{
return false; return false;
} }
// run alpha-beta algorithmn // run alpha-beta algorithmn
PRINT(2, this, " Bytes in memory: " << memoryUsed2 << endl); PRINT(2, this, " Bytes in memory: " << memoryUsed2 << endl);
if (!runAlphaBeta(alphaBetaVars)) { if (!runAlphaBeta(alphaBetaVars))
{
return false; return false;
} }
@ -42,19 +44,22 @@ bool MiniMax::calcKnotValuesByAlphaBeta(unsigned int layerNumber)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: saveKnotValueInDatabase() // 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 // locals
unsigned int *symStateNumbers = nullptr; unsigned int *symStateNumbers = nullptr;
unsigned int numSymmetricStates; unsigned int numSymmetricStates;
unsigned int sysStateNumber; unsigned int sysStateNumber;
unsigned int i; unsigned int i;
// invert value ? // invert value ?
if (knotValue > SKV_VALUE_GAME_WON) while (true); if (knotValue > SKV_VALUE_GAME_WON)
if (invertValue) knotValue = skvPerspectiveMatrix[knotValue][PL_TO_MOVE_UNCHANGED]; while (true)
;
if (invertValue)
knotValue = skvPerspectiveMatrix[knotValue][PL_TO_MOVE_UNCHANGED];
// get numbers of symmetric states // get numbers of symmetric states
getSymStateNumWithDoubles(threadNo, &numSymmetricStates, &symStateNumbers); getSymStateNumWithDoubles(threadNo, &numSymmetricStates, &symStateNumbers);
@ -64,13 +69,15 @@ void MiniMax::alphaBetaSaveInDatabase(unsigned int threadNo, unsigned int layerN
savePlyInfoInDatabase(layerNumber, stateNumber, plyValue); savePlyInfoInDatabase(layerNumber, stateNumber, plyValue);
// save value for all symmetric states // save value for all symmetric states
for (i = 0; i < numSymmetricStates; i++) { for (i = 0; i < numSymmetricStates; i++)
{
// get state number // get state number
sysStateNumber = symStateNumbers[i]; sysStateNumber = symStateNumbers[i];
// don't save original state twice // don't save original state twice
if (sysStateNumber == stateNumber) continue; if (sysStateNumber == stateNumber)
continue;
// save // save
saveKnotValueInDatabase(layerNumber, sysStateNumber, knotValue); saveKnotValueInDatabase(layerNumber, sysStateNumber, knotValue);
@ -85,22 +92,25 @@ void MiniMax::alphaBetaSaveInDatabase(unsigned int threadNo, unsigned int layerN
bool MiniMax::initAlphaBeta(AlphaBetaGlobalVars &alphaBetaVars) bool MiniMax::initAlphaBeta(AlphaBetaGlobalVars &alphaBetaVars)
{ {
// locals // locals
BufferedFile *invalidArray; // BufferedFile *invalidArray; //
bool initAlreadyDone = false; // true if the initialization information is already available in a file bool initAlreadyDone = false; // true if the initialization information is already available in a file
stringstream ssInvArrayDirectory; // stringstream ssInvArrayDirectory; //
stringstream ssInvArrayFilePath; // stringstream ssInvArrayFilePath; //
// set current processed layer number // 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 ***"); PRINT(1, this, endl << " *** Signing of invalid states for layer " << alphaBetaVars.layerNumber << " (" << (getOutputInformation(alphaBetaVars.layerNumber)) << ") which has " << layerStats[alphaBetaVars.layerNumber].knotsInLayer << " knots ***");
// file names // file names
ssInvArrayDirectory.str(""); ssInvArrayDirectory << fileDirectory << (fileDirectory.size() ? "\\" : "") << "invalidStates"; ssInvArrayDirectory.str("");
ssInvArrayFilePath.str(""); ssInvArrayFilePath << fileDirectory << (fileDirectory.size() ? "\\" : "") << "invalidStates\\invalidStatesOfLayer" << alphaBetaVars.layerNumber << ".dat"; ssInvArrayDirectory << fileDirectory << (fileDirectory.size() ? "\\" : "") << "invalidStates";
ssInvArrayFilePath.str("");
ssInvArrayFilePath << fileDirectory << (fileDirectory.size() ? "\\" : "") << "invalidStates\\invalidStatesOfLayer" << alphaBetaVars.layerNumber << ".dat";
// does initialization file exist ? // does initialization file exist ?
CreateDirectoryA(ssInvArrayDirectory.str().c_str(), nullptr); CreateDirectoryA(ssInvArrayDirectory.str().c_str(), nullptr);
invalidArray = new BufferedFile(threadManager.getNumThreads(), FILE_BUFFER_SIZE, ssInvArrayFilePath.str().c_str()); 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()); PRINT(2, this, " Loading invalid states from file: " << ssInvArrayFilePath.str());
initAlreadyDone = true; initAlreadyDone = true;
} }
@ -114,7 +124,8 @@ bool MiniMax::initAlphaBeta(AlphaBetaGlobalVars &alphaBetaVars)
ThreadManager::ThreadVarsArray<InitAlphaBetaVars> tva(threadManager.getNumThreads(), InitAlphaBetaVars(this, &alphaBetaVars, alphaBetaVars.layerNumber, invalidArray, initAlreadyDone)); ThreadManager::ThreadVarsArray<InitAlphaBetaVars> tva(threadManager.getNumThreads(), InitAlphaBetaVars(this, &alphaBetaVars, alphaBetaVars.layerNumber, invalidArray, initAlreadyDone));
// process each state in the current layer // 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: case TM_RETURN_VALUE_OK:
break; break;
case TM_RETURN_VALUE_EXECUTION_CANCELLED: case TM_RETURN_VALUE_EXECUTION_CANCELLED:
@ -130,7 +141,8 @@ bool MiniMax::initAlphaBeta(AlphaBetaGlobalVars &alphaBetaVars)
// reduce and delete thread specific data // reduce and delete thread specific data
tva.reduce(); tva.reduce();
if (numStatesProcessed < layerStats[alphaBetaVars.layerNumber].knotsInLayer) { if (numStatesProcessed < layerStats[alphaBetaVars.layerNumber].knotsInLayer)
{
SAFE_DELETE(invalidArray); SAFE_DELETE(invalidArray);
return falseOrStop(); return falseOrStop();
} }
@ -158,44 +170,57 @@ DWORD MiniMax::initAlphaBetaThreadProc(void *pParameter, int index)
// locals // locals
InitAlphaBetaVars *iabVars = (InitAlphaBetaVars *)pParameter; InitAlphaBetaVars *iabVars = (InitAlphaBetaVars *)pParameter;
MiniMax *m = iabVars->pMiniMax; MiniMax *m = iabVars->pMiniMax;
float floatValue; // dummy variable for calls of getValueOfSituation() float floatValue; // dummy variable for calls of getValueOfSituation()
StateAdress curState; // current state counter for loops StateAdress curState; // current state counter for loops
TwoBit curStateValue = 0; // for calls of getValueOfSituation() TwoBit curStateValue = 0; // for calls of getValueOfSituation()
PlyInfoVarType plyInfo; // depends on the curStateValue PlyInfoVarType plyInfo; // depends on the curStateValue
curState.layerNumber = iabVars->layerNumber; curState.layerNumber = iabVars->layerNumber;
curState.stateNumber = index; curState.stateNumber = index;
iabVars->statesProcessed++; iabVars->statesProcessed++;
// print status // print status
if (iabVars->statesProcessed % OUTPUT_EVERY_N_STATES == 0) { if (iabVars->statesProcessed % OUTPUT_EVERY_N_STATES == 0)
{
m->numStatesProcessed += OUTPUT_EVERY_N_STATES; m->numStatesProcessed += OUTPUT_EVERY_N_STATES;
PRINT(2, m, "Already initialized " << m->numStatesProcessed << " of " << m->layerStats[curState.layerNumber].knotsInLayer << " 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 // layer initialization already done ? if so, then read from file
if (iabVars->initAlreadyDone) { if (iabVars->initAlreadyDone)
if (!iabVars->bufferedFile->readBytes(iabVars->curThreadNo, index * sizeof(TwoBit), sizeof(TwoBit), (unsigned char *)&curStateValue)) { {
if (!iabVars->bufferedFile->readBytes(iabVars->curThreadNo, index * sizeof(TwoBit), sizeof(TwoBit), (unsigned char *)&curStateValue))
{
PRINT(0, m, "ERROR: initArray->takeBytes() failed"); PRINT(0, m, "ERROR: initArray->takeBytes() failed");
return m->falseOrStop(); return m->falseOrStop();
} }
// initialization not done // initialization not done
} else { }
else
{
// set current selected situation // 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; curStateValue = SKV_VALUE_INVALID;
} else { }
else
{
// get value of current situation // get value of current situation
m->getValueOfSituation(iabVars->curThreadNo, floatValue, curStateValue); m->getValueOfSituation(iabVars->curThreadNo, floatValue, curStateValue);
} }
} }
// calc ply info // 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; plyInfo = 0;
} else if (curStateValue == SKV_VALUE_INVALID) { }
else if (curStateValue == SKV_VALUE_INVALID)
{
plyInfo = PLYINFO_VALUE_INVALID; plyInfo = PLYINFO_VALUE_INVALID;
} else { }
else
{
plyInfo = PLYINFO_VALUE_UNCALCULATED; plyInfo = PLYINFO_VALUE_UNCALCULATED;
} }
@ -204,8 +229,10 @@ DWORD MiniMax::initAlphaBetaThreadProc(void *pParameter, int index)
m->savePlyInfoInDatabase(curState.layerNumber, curState.stateNumber, plyInfo); m->savePlyInfoInDatabase(curState.layerNumber, curState.stateNumber, plyInfo);
// write data to file // write data to file
if (!iabVars->initAlreadyDone) { if (!iabVars->initAlreadyDone)
if (!iabVars->bufferedFile->writeBytes(iabVars->curThreadNo, index * sizeof(TwoBit), sizeof(TwoBit), (unsigned char *)&curStateValue)) { {
if (!iabVars->bufferedFile->writeBytes(iabVars->curThreadNo, index * sizeof(TwoBit), sizeof(TwoBit), (unsigned char *)&curStateValue))
{
PRINT(0, m, "ERROR: bufferedFile->writeBytes failed!"); PRINT(0, m, "ERROR: bufferedFile->writeBytes failed!");
return m->falseOrStop(); return m->falseOrStop();
} }
@ -217,7 +244,7 @@ DWORD MiniMax::initAlphaBetaThreadProc(void *pParameter, int index)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: runAlphaBeta() // Name: runAlphaBeta()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
bool MiniMax::runAlphaBeta(AlphaBetaGlobalVars &alphaBetaVars) bool MiniMax::runAlphaBeta(AlphaBetaGlobalVars &alphaBetaVars)
{ {
@ -234,7 +261,8 @@ bool MiniMax::runAlphaBeta(AlphaBetaGlobalVars &alphaBetaVars)
threadManager.setNumThreads(1); threadManager.setNumThreads(1);
// process each state in the current layer // 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: case TM_RETURN_VALUE_OK:
break; break;
case TM_RETURN_VALUE_EXECUTION_CANCELLED: case TM_RETURN_VALUE_EXECUTION_CANCELLED:
@ -249,7 +277,8 @@ bool MiniMax::runAlphaBeta(AlphaBetaGlobalVars &alphaBetaVars)
// reduce and delete thread specific data // reduce and delete thread specific data
tva.reduce(); tva.reduce();
if (numStatesProcessed < layerStats[alphaBetaVars.layerNumber].knotsInLayer) return falseOrStop(); if (numStatesProcessed < layerStats[alphaBetaVars.layerNumber].knotsInLayer)
return falseOrStop();
// show statistics // show statistics
PRINT(2, this, " won states: " << alphaBetaVars.statsValueCounter[SKV_VALUE_GAME_WON]); PRINT(2, this, " won states: " << alphaBetaVars.statsValueCounter[SKV_VALUE_GAME_WON]);
@ -262,38 +291,42 @@ bool MiniMax::runAlphaBeta(AlphaBetaGlobalVars &alphaBetaVars)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: runAlphaBetaThreadProc() // Name: runAlphaBetaThreadProc()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
DWORD MiniMax::runAlphaBetaThreadProc(void *pParameter, int index) DWORD MiniMax::runAlphaBetaThreadProc(void *pParameter, int index)
{ {
// locals // locals
RunAlphaBetaVars *rabVars = (RunAlphaBetaVars *)pParameter; RunAlphaBetaVars *rabVars = (RunAlphaBetaVars *)pParameter;
MiniMax *m = rabVars->pMiniMax; MiniMax *m = rabVars->pMiniMax;
StateAdress curState; // current state counter for loops StateAdress curState; // current state counter for loops
Node root; // Node root; //
PlyInfoVarType plyInfo; // depends on the curStateValue PlyInfoVarType plyInfo; // depends on the curStateValue
curState.layerNumber = rabVars->layerNumber; curState.layerNumber = rabVars->layerNumber;
curState.stateNumber = index; curState.stateNumber = index;
rabVars->statesProcessed++; rabVars->statesProcessed++;
// print status // print status
if (rabVars->statesProcessed % OUTPUT_EVERY_N_STATES == 0) { if (rabVars->statesProcessed % OUTPUT_EVERY_N_STATES == 0)
{
m->numStatesProcessed += OUTPUT_EVERY_N_STATES; m->numStatesProcessed += OUTPUT_EVERY_N_STATES;
PRINT(2, m, " Processed " << m->numStatesProcessed << " of " << m->layerStats[curState.layerNumber].knotsInLayer << " states"); PRINT(2, m, " Processed " << m->numStatesProcessed << " of " << m->layerStats[curState.layerNumber].knotsInLayer << " states");
} }
// Version 10: state already calculated? if so leave. // Version 10: state already calculated? if so leave.
m->readPlyInfoFromDatabase(curState.layerNumber, curState.stateNumber, plyInfo); 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 // 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 // calc value of situation
m->letTheTreeGrow(&root, rabVars, m->depthOfFullTree, SKV_VALUE_GAME_LOST, SKV_VALUE_GAME_WON); 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 // 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); 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() // Name: letTheTreeGrow()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void MiniMax::letTheTreeGrow(Node *knot, RunAlphaBetaVars *rabVars, unsigned int tilLevel, float alpha, float beta) void MiniMax::letTheTreeGrow(Node *knot, RunAlphaBetaVars *rabVars, unsigned int tilLevel, float alpha, float beta)
{ {
// Locals // Locals
void *pPossibilities; void *pPossibilities;
unsigned int *idPossibility; unsigned int *idPossibility;
unsigned int layerNumber = 0; // layer number of current state unsigned int layerNumber = 0; // layer number of current state
unsigned int stateNumber = 0; // state number of current state unsigned int stateNumber = 0; // state number of current state
unsigned int maxWonfreqValuesSubMoves = 0; unsigned int maxWonfreqValuesSubMoves = 0;
// standard values // standard values
knot->branches = &rabVars->branchArray[(depthOfFullTree - tilLevel) * maxNumBranches]; 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; knot->floatValue = (float)knot->shortValue;
// evaluate situation, musn't occur while calculating database // evaluate situation, musn't occur while calculating database
if (tilLevel == 0) { if (tilLevel == 0)
if (calcDatabase) { {
if (calcDatabase)
{
// if tilLevel is equal zero it means that memory is gone out, since each recursive step needs memory // if tilLevel is equal zero it means that memory is gone out, since each recursive step needs memory
PRINT(0, this, "ERROR: tilLevel == 0"); PRINT(0, this, "ERROR: tilLevel == 0");
knot->shortValue = SKV_VALUE_INVALID; knot->shortValue = SKV_VALUE_INVALID;
knot->plyInfo = PLYINFO_VALUE_INVALID; knot->plyInfo = PLYINFO_VALUE_INVALID;
knot->floatValue = (float)knot->shortValue; knot->floatValue = (float)knot->shortValue;
falseOrStop(); falseOrStop();
} else { }
else
{
getValueOfSituation(rabVars->curThreadNo, knot->floatValue, knot->shortValue); getValueOfSituation(rabVars->curThreadNo, knot->floatValue, knot->shortValue);
} }
// investigate branches // 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 // 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 // get number of possiblities
idPossibility = getPossibilities(rabVars->curThreadNo, &knot->numPossibilities, &knot->isOpponentLevel, &pPossibilities); idPossibility = getPossibilities(rabVars->curThreadNo, &knot->numPossibilities, &knot->isOpponentLevel, &pPossibilities);
// unable to move // unable to move
if (knot->numPossibilities == 0) { if (knot->numPossibilities == 0)
{
// if unable to move a final state is reached // if unable to move a final state is reached
knot->plyInfo = 0; knot->plyInfo = 0;
getValueOfSituation(rabVars->curThreadNo, knot->floatValue, knot->shortValue); 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 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->shortValue = SKV_VALUE_INVALID;
knot->plyInfo = PLYINFO_VALUE_INVALID; knot->plyInfo = PLYINFO_VALUE_INVALID;
knot->floatValue = (float)knot->shortValue; knot->floatValue = (float)knot->shortValue;
} }
// movement is possible // movement is possible
} else { }
else
{
// move, letTreeGroe, undo // move, letTreeGroe, undo
alphaBetaTryPossibilites(knot, rabVars, tilLevel, idPossibility, pPossibilities, maxWonfreqValuesSubMoves, alpha, beta); 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); alphaBetaChooseBestMove(knot, rabVars, tilLevel, idPossibility, maxWonfreqValuesSubMoves);
} }
// save value and best branch into database and set value as valid // 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); if (calcDatabase && hFileShortKnotValues && hFilePlyInfo)
alphaBetaSaveInDatabase(rabVars->curThreadNo, layerNumber, stateNumber, knot->shortValue, knot->plyInfo, knot->isOpponentLevel);
} }
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: alphaBetaTryDataBase() // Name: alphaBetaTryDataBase()
// Desc: // Desc:
// 1 - Determines layerNumber and stateNumber for the given game situation. // 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. // 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. // 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) bool MiniMax::alphaBetaTryDataBase(Node *knot, RunAlphaBetaVars *rabVars, unsigned int tilLevel, unsigned int &layerNumber, unsigned int &stateNumber)
{ {
// locals // locals
bool invalidLayerOrStateNumber; bool invalidLayerOrStateNumber;
bool subLayerInDatabaseAndCompleted; bool subLayerInDatabaseAndCompleted;
TwoBit shortKnotValue = SKV_VALUE_INVALID; TwoBit shortKnotValue = SKV_VALUE_INVALID;
PlyInfoVarType plyInfo = PLYINFO_VALUE_UNCALCULATED; PlyInfoVarType plyInfo = PLYINFO_VALUE_UNCALCULATED;
// use database ? // use database ?
if (hFilePlyInfo != nullptr && hFileShortKnotValues != nullptr && (calcDatabase || layerInDatabase)) { if (hFilePlyInfo != nullptr && hFileShortKnotValues != nullptr && (calcDatabase || layerInDatabase))
{
// situation already existend in database ? // situation already existend in database ?
readKnotValueFromDatabase(rabVars->curThreadNo, layerNumber, stateNumber, shortKnotValue, invalidLayerOrStateNumber, subLayerInDatabaseAndCompleted); 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(), // it was possible to achieve an invalid state using move(),
// so the original state was an invalid one // so the original state was an invalid one
if ((tilLevel < depthOfFullTree && invalidLayerOrStateNumber) if ((tilLevel < depthOfFullTree && invalidLayerOrStateNumber) || (tilLevel < depthOfFullTree && shortKnotValue == SKV_VALUE_INVALID && subLayerInDatabaseAndCompleted) || (tilLevel < depthOfFullTree && shortKnotValue == SKV_VALUE_INVALID && plyInfo != PLYINFO_VALUE_UNCALCULATED))
|| (tilLevel < depthOfFullTree && shortKnotValue == SKV_VALUE_INVALID && subLayerInDatabaseAndCompleted) { // version 22: replaced: curCalculatedLayer == layerNumber && knot->plyInfo != PLYINFO_VALUE_UNCALCULATED)) {
|| (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->shortValue = SKV_VALUE_INVALID;
knot->plyInfo = PLYINFO_VALUE_INVALID; knot->plyInfo = PLYINFO_VALUE_INVALID;
knot->floatValue = (float)knot->shortValue; 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 // 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); 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 // when knot value is valid then return best branch
if (calcDatabase && tilLevel < depthOfFullTree && shortKnotValue != SKV_VALUE_INVALID && plyInfo != PLYINFO_VALUE_UNCALCULATED if (calcDatabase && tilLevel < depthOfFullTree && shortKnotValue != SKV_VALUE_INVALID && plyInfo != PLYINFO_VALUE_UNCALCULATED || !calcDatabase && tilLevel < depthOfFullTree - 1 && shortKnotValue != SKV_VALUE_INVALID)
|| !calcDatabase && tilLevel < depthOfFullTree - 1 && shortKnotValue != SKV_VALUE_INVALID) { {
// switch if is not opponent level // switch if is not opponent level
if (knot->isOpponentLevel) knot->shortValue = skvPerspectiveMatrix[shortKnotValue][PL_TO_MOVE_UNCHANGED]; if (knot->isOpponentLevel)
else knot->shortValue = skvPerspectiveMatrix[shortKnotValue][PL_TO_MOVE_CHANGED]; knot->shortValue = skvPerspectiveMatrix[shortKnotValue][PL_TO_MOVE_UNCHANGED];
else
knot->shortValue = skvPerspectiveMatrix[shortKnotValue][PL_TO_MOVE_CHANGED];
knot->floatValue = (float)knot->shortValue; knot->floatValue = (float)knot->shortValue;
knot->plyInfo = plyInfo; knot->plyInfo = plyInfo;
return true; return true;
@ -435,18 +484,20 @@ bool MiniMax::alphaBetaTryDataBase(Node *knot, RunAlphaBetaVars *rabVars, unsign
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: alphaBetaTryPossibilites() // 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) void MiniMax::alphaBetaTryPossibilites(Node *knot, RunAlphaBetaVars *rabVars, unsigned int tilLevel, unsigned int *idPossibility, void *pPossibilities, unsigned int &maxWonfreqValuesSubMoves, float &alpha, float &beta)
{ {
// locals // locals
void *pBackup; void *pBackup;
unsigned int curPoss; unsigned int curPoss;
for (curPoss = 0; curPoss < knot->numPossibilities; curPoss++) { for (curPoss = 0; curPoss < knot->numPossibilities; curPoss++)
{
// output // output
if (tilLevel == depthOfFullTree && !calcDatabase) { if (tilLevel == depthOfFullTree && !calcDatabase)
{
printMoveInformation(rabVars->curThreadNo, idPossibility[curPoss], pPossibilities); printMoveInformation(rabVars->curThreadNo, idPossibility[curPoss], pPossibilities);
rabVars->freqValuesSubMoves[SKV_VALUE_INVALID] = 0; rabVars->freqValuesSubMoves[SKV_VALUE_INVALID] = 0;
rabVars->freqValuesSubMoves[SKV_VALUE_GAME_LOST] = 0; rabVars->freqValuesSubMoves[SKV_VALUE_GAME_LOST] = 0;
@ -463,76 +514,104 @@ void MiniMax::alphaBetaTryPossibilites(Node *knot, RunAlphaBetaVars *rabVars, un
// undo move // undo move
undo(rabVars->curThreadNo, idPossibility[curPoss], knot->isOpponentLevel, pBackup, pPossibilities); undo(rabVars->curThreadNo, idPossibility[curPoss], knot->isOpponentLevel, pBackup, pPossibilities);
// output // output
if (tilLevel == depthOfFullTree && !calcDatabase) { if (tilLevel == depthOfFullTree && !calcDatabase)
{
rabVars->freqValuesSubMovesBranchWon[curPoss] = rabVars->freqValuesSubMoves[SKV_VALUE_GAME_WON]; 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]; 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); 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); 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); 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]++; rabVars->freqValuesSubMoves[knot->branches[curPoss].shortValue]++;
} }
// don't use alpha beta if using database // don't use alpha beta if using database
if (hFileShortKnotValues != nullptr && calcDatabase) continue; if (hFileShortKnotValues != nullptr && calcDatabase)
if (hFileShortKnotValues != nullptr && tilLevel + 1 >= depthOfFullTree) continue; continue;
if (hFileShortKnotValues != nullptr && tilLevel + 1 >= depthOfFullTree)
continue;
// alpha beta algorithmn // alpha beta algorithmn
if (!knot->isOpponentLevel) { if (!knot->isOpponentLevel)
if (knot->branches[curPoss].floatValue >= beta) { {
if (knot->branches[curPoss].floatValue >= beta)
{
knot->numPossibilities = curPoss + 1; knot->numPossibilities = curPoss + 1;
break; break;
} else if (knot->branches[curPoss].floatValue > alpha) { }
else if (knot->branches[curPoss].floatValue > alpha)
{
alpha = knot->branches[curPoss].floatValue; alpha = knot->branches[curPoss].floatValue;
} }
} else { }
if (knot->branches[curPoss].floatValue <= alpha) { else
{
if (knot->branches[curPoss].floatValue <= alpha)
{
knot->numPossibilities = curPoss + 1; knot->numPossibilities = curPoss + 1;
break; break;
} else if (knot->branches[curPoss].floatValue < beta) { }
else if (knot->branches[curPoss].floatValue < beta)
{
beta = knot->branches[curPoss].floatValue; beta = knot->branches[curPoss].floatValue;
} }
} }
} }
// let delete pPossibilities // let delete pPossibilities
if (tilLevel < depthOfFullTree) { if (tilLevel < depthOfFullTree)
{
deletePossibilities(rabVars->curThreadNo, pPossibilities); deletePossibilities(rabVars->curThreadNo, pPossibilities);
} else { }
else
{
pRootPossibilities = pPossibilities; pRootPossibilities = pPossibilities;
} }
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: alphaBetaCalcKnotValue() // Name: alphaBetaCalcKnotValue()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void MiniMax::alphaBetaCalcKnotValue(Node *knot) void MiniMax::alphaBetaCalcKnotValue(Node *knot)
{ {
// locals // locals
float maxValue = knot->branches[0].floatValue; float maxValue = knot->branches[0].floatValue;
unsigned int maxBranch = 0; unsigned int maxBranch = 0;
unsigned int i; unsigned int i;
// opponent tries to minimize the value // opponent tries to minimize the value
if (knot->isOpponentLevel) { if (knot->isOpponentLevel)
for (i = 1; i < knot->numPossibilities; i++) { {
for (i = 1; i < knot->numPossibilities; i++)
{
// version 21: it should be impossible that knot->shortValue is equal SKV_VALUE_INVALID // 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; maxValue = knot->branches[i].floatValue;
maxBranch = i; maxBranch = i;
} }
} }
// maximize the value // maximize the value
} else { }
for (i = 1; i < knot->numPossibilities; i++) { else
if (/*knot->shortValue != SKV_VALUE_INVALID && */knot->branches[i].floatValue > maxValue) { {
for (i = 1; i < knot->numPossibilities; i++)
{
if (/*knot->shortValue != SKV_VALUE_INVALID && */ knot->branches[i].floatValue > maxValue)
{
maxValue = knot->branches[i].floatValue; maxValue = knot->branches[i].floatValue;
maxBranch = i; maxBranch = i;
} }
@ -546,22 +625,27 @@ void MiniMax::alphaBetaCalcKnotValue(Node *knot)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: alphaBetaCalcPlyInfo() // Name: alphaBetaCalcPlyInfo()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void MiniMax::alphaBetaCalcPlyInfo(Node *knot) void MiniMax::alphaBetaCalcPlyInfo(Node *knot)
{ {
// locals // locals
unsigned int i; unsigned int i;
unsigned int maxBranch; unsigned int maxBranch;
PlyInfoVarType maxPlyInfo; PlyInfoVarType maxPlyInfo;
TwoBit shortKnotValue; TwoBit shortKnotValue;
// //
if (knot->shortValue == SKV_VALUE_GAME_DRAWN) { if (knot->shortValue == SKV_VALUE_GAME_DRAWN)
{
knot->plyInfo = PLYINFO_VALUE_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; knot->plyInfo = PLYINFO_VALUE_INVALID;
} else { }
else
{
// calculate value of knot // calculate value of knot
shortKnotValue = (knot->isOpponentLevel) ? skvPerspectiveMatrix[knot->shortValue][PL_TO_MOVE_UNCHANGED] : knot->shortValue; shortKnotValue = (knot->isOpponentLevel) ? skvPerspectiveMatrix[knot->shortValue][PL_TO_MOVE_UNCHANGED] : knot->shortValue;
@ -569,9 +653,11 @@ void MiniMax::alphaBetaCalcPlyInfo(Node *knot)
maxBranch = 0; maxBranch = 0;
// when current knot is a won state // 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 // invert knot value if necessary
shortKnotValue = (knot->branches[i].isOpponentLevel) ? skvPerspectiveMatrix[knot->branches[i].shortValue][PL_TO_MOVE_UNCHANGED] : knot->branches[i].shortValue; 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) 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 // 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; maxPlyInfo = knot->branches[i].plyInfo;
maxBranch = i; maxBranch = i;
@ -588,9 +675,12 @@ void MiniMax::alphaBetaCalcPlyInfo(Node *knot)
} }
// current state is a lost state // 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 // invert knot value if necessary
shortKnotValue = (knot->branches[i].isOpponentLevel) ? skvPerspectiveMatrix[knot->branches[i].shortValue][PL_TO_MOVE_UNCHANGED] : knot->branches[i].shortValue; 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) 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 // 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; maxPlyInfo = knot->branches[i].plyInfo;
maxBranch = i; 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) void MiniMax::alphaBetaChooseBestMove(Node *knot, RunAlphaBetaVars *rabVars, unsigned int tilLevel, unsigned int *idPossibility, unsigned int maxWonfreqValuesSubMoves)
{ {
// locals // locals
float dif; float dif;
unsigned int numBestChoices = 0; unsigned int numBestChoices = 0;
unsigned int *bestBranches = new unsigned int[maxNumBranches]; unsigned int *bestBranches = new unsigned int[maxNumBranches];
unsigned int i; unsigned int i;
unsigned int maxBranch; unsigned int maxBranch;
// select randomly one of the best moves, if they are equivalent // select randomly one of the best moves, if they are equivalent
if (tilLevel == depthOfFullTree && !calcDatabase) { if (tilLevel == depthOfFullTree && !calcDatabase)
{
// check every possible move // 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 // use information in database
if (layerInDatabase && hFileShortKnotValues != nullptr) { if (layerInDatabase && hFileShortKnotValues != nullptr)
{
// selected move with equal knot value // 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 // best move lead to drawn state
if (knot->shortValue == SKV_VALUE_GAME_DRAWN) { if (knot->shortValue == SKV_VALUE_GAME_DRAWN)
if (maxWonfreqValuesSubMoves == rabVars->freqValuesSubMovesBranchWon[i]) { {
if (maxWonfreqValuesSubMoves == rabVars->freqValuesSubMovesBranchWon[i])
{
bestBranches[numBestChoices] = i; bestBranches[numBestChoices] = i;
numBestChoices++; numBestChoices++;
} }
// best move lead to lost or won state // 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; bestBranches[numBestChoices] = i;
numBestChoices++; numBestChoices++;
} }
} }
} }
// conventionell mini-max algorithm // conventionell mini-max algorithm
} else { }
else
{
dif = knot->branches[i].floatValue - knot->floatValue; dif = knot->branches[i].floatValue - knot->floatValue;
dif = (dif > 0) ? dif : -1.0f * dif; dif = (dif > 0) ? dif : -1.0f * dif;
if (dif < FPKV_THRESHOLD) { if (dif < FPKV_THRESHOLD)
{
bestBranches[numBestChoices] = i; bestBranches[numBestChoices] = i;
numBestChoices++; numBestChoices++;
} }

View File

@ -15,7 +15,8 @@
void MiniMax::closeDatabase() void MiniMax::closeDatabase()
{ {
// close database // close database
if (hFileShortKnotValues != nullptr) { if (hFileShortKnotValues != nullptr)
{
unloadAllLayers(); unloadAllLayers();
SAFE_DELETE_ARRAY(layerStats); SAFE_DELETE_ARRAY(layerStats);
CloseHandle(hFileShortKnotValues); CloseHandle(hFileShortKnotValues);
@ -23,7 +24,8 @@ void MiniMax::closeDatabase()
} }
// close ply information file // close ply information file
if (hFilePlyInfo != nullptr) { if (hFilePlyInfo != nullptr)
{
unloadAllPlyInfos(); unloadAllPlyInfos();
SAFE_DELETE_ARRAY(plyInfos); SAFE_DELETE_ARRAY(plyInfos);
CloseHandle(hFilePlyInfo); CloseHandle(hFilePlyInfo);
@ -33,7 +35,7 @@ void MiniMax::closeDatabase()
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: unloadPlyInfo() // Name: unloadPlyInfo()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void MiniMax::unloadPlyInfo(unsigned int layerNumber) void MiniMax::unloadPlyInfo(unsigned int layerNumber)
{ {
@ -46,7 +48,7 @@ void MiniMax::unloadPlyInfo(unsigned int layerNumber)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: unloadLayer() // Name: unloadLayer()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void MiniMax::unloadLayer(unsigned int layerNumber) void MiniMax::unloadLayer(unsigned int layerNumber)
{ {
@ -59,51 +61,61 @@ void MiniMax::unloadLayer(unsigned int layerNumber)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: unloadAllPlyInfos() // Name: unloadAllPlyInfos()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void MiniMax::unloadAllPlyInfos() void MiniMax::unloadAllPlyInfos()
{ {
for (unsigned int i = 0; i < plyInfoHeader.numLayers; i++) { for (unsigned int i = 0; i < plyInfoHeader.numLayers; i++)
{
unloadPlyInfo(i); unloadPlyInfo(i);
} }
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: unloadAllLayers() // Name: unloadAllLayers()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void MiniMax::unloadAllLayers() void MiniMax::unloadAllLayers()
{ {
for (unsigned int i = 0; i < skvfHeader.numLayers; i++) { for (unsigned int i = 0; i < skvfHeader.numLayers; i++)
{
unloadLayer(i); unloadLayer(i);
} }
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: saveBytesToFile() // Name: saveBytesToFile()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void MiniMax::saveBytesToFile(HANDLE hFile, long long offset, unsigned int numBytes, void *pBytes) void MiniMax::saveBytesToFile(HANDLE hFile, long long offset, unsigned int numBytes, void *pBytes)
{ {
DWORD dwBytesWritten; DWORD dwBytesWritten;
LARGE_INTEGER liDistanceToMove; LARGE_INTEGER liDistanceToMove;
unsigned int restingBytes = numBytes; unsigned int restingBytes = numBytes;
void *myPointer = pBytes; void *myPointer = pBytes;
bool errorPrint = false; bool errorPrint = false;
liDistanceToMove.QuadPart = offset; liDistanceToMove.QuadPart = offset;
while (errorPrint = !SetFilePointerEx(hFile, liDistanceToMove, nullptr, FILE_BEGIN)) { while (errorPrint = !SetFilePointerEx(hFile, liDistanceToMove, nullptr, FILE_BEGIN))
if (!errorPrint) PRINT(1, this, "ERROR: SetFilePointerEx failed!"); {
if (!errorPrint)
PRINT(1, this, "ERROR: SetFilePointerEx failed!");
} }
while (restingBytes > 0) { while (restingBytes > 0)
if (WriteFile(hFile, myPointer, restingBytes, &dwBytesWritten, nullptr) == TRUE) { {
if (WriteFile(hFile, myPointer, restingBytes, &dwBytesWritten, nullptr) == TRUE)
{
restingBytes -= dwBytesWritten; restingBytes -= dwBytesWritten;
myPointer = (void *)(((unsigned char *)myPointer) + dwBytesWritten); myPointer = (void *)(((unsigned char *)myPointer) + dwBytesWritten);
if (restingBytes > 0) PRINT(2, this, "Still " << restingBytes << " to write!"); if (restingBytes > 0)
} else { PRINT(2, this, "Still " << restingBytes << " to write!");
if (!errorPrint) PRINT(0, this, "ERROR: WriteFile Failed!"); }
else
{
if (!errorPrint)
PRINT(0, this, "ERROR: WriteFile Failed!");
errorPrint = true; errorPrint = true;
} }
} }
@ -111,31 +123,39 @@ void MiniMax::saveBytesToFile(HANDLE hFile, long long offset, unsigned int numBy
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: loadBytesFromFile() // Name: loadBytesFromFile()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void MiniMax::loadBytesFromFile(HANDLE hFile, long long offset, unsigned int numBytes, void *pBytes) void MiniMax::loadBytesFromFile(HANDLE hFile, long long offset, unsigned int numBytes, void *pBytes)
{ {
DWORD dwBytesRead; DWORD dwBytesRead;
LARGE_INTEGER liDistanceToMove; LARGE_INTEGER liDistanceToMove;
unsigned int restingBytes = numBytes; unsigned int restingBytes = numBytes;
void *myPointer = pBytes; void *myPointer = pBytes;
bool errorPrint = false; bool errorPrint = false;
liDistanceToMove.QuadPart = offset; liDistanceToMove.QuadPart = offset;
while (errorPrint = !SetFilePointerEx(hFile, liDistanceToMove, nullptr, FILE_BEGIN)) { while (errorPrint = !SetFilePointerEx(hFile, liDistanceToMove, nullptr, FILE_BEGIN))
if (!errorPrint) PRINT(0, this, "ERROR: SetFilePointerEx failed!"); {
if (!errorPrint)
PRINT(0, this, "ERROR: SetFilePointerEx failed!");
} }
while (restingBytes > 0) { while (restingBytes > 0)
if (ReadFile(hFile, pBytes, restingBytes, &dwBytesRead, nullptr) == TRUE) { {
if (ReadFile(hFile, pBytes, restingBytes, &dwBytesRead, nullptr) == TRUE)
{
restingBytes -= dwBytesRead; restingBytes -= dwBytesRead;
myPointer = (void *)(((unsigned char *)myPointer) + dwBytesRead); myPointer = (void *)(((unsigned char *)myPointer) + dwBytesRead);
if (restingBytes > 0) { if (restingBytes > 0)
{
PRINT(2, this, "Still " << restingBytes << " bytes to read!"); 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; errorPrint = true;
} }
} }
@ -143,15 +163,18 @@ void MiniMax::loadBytesFromFile(HANDLE hFile, long long offset, unsigned int num
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: isCurrentStateInDatabase() // Name: isCurrentStateInDatabase()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
bool MiniMax::isCurrentStateInDatabase(unsigned int threadNo) bool MiniMax::isCurrentStateInDatabase(unsigned int threadNo)
{ {
unsigned int layerNum, stateNumber; unsigned int layerNum, stateNumber;
if (hFileShortKnotValues == nullptr) { if (hFileShortKnotValues == nullptr)
{
return false; return false;
} else { }
else
{
getLayerAndStateNumber(threadNo, layerNum, stateNumber); getLayerAndStateNumber(threadNo, layerNum, stateNumber);
return layerStats[layerNum].layerIsCompletedAndInFile; return layerStats[layerNum].layerIsCompletedAndInFile;
} }
@ -159,7 +182,7 @@ bool MiniMax::isCurrentStateInDatabase(unsigned int threadNo)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: saveHeader() // Name: saveHeader()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void MiniMax::saveHeader(SkvFileHeader *dbH, LayerStats *lStats) void MiniMax::saveHeader(SkvFileHeader *dbH, LayerStats *lStats)
{ {
@ -171,7 +194,7 @@ void MiniMax::saveHeader(SkvFileHeader *dbH, LayerStats *lStats)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: saveHeader() // Name: saveHeader()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void MiniMax::saveHeader(PlyInfoFileHeader *piH, PlyInfo *pInfo) void MiniMax::saveHeader(PlyInfoFileHeader *piH, PlyInfo *pInfo)
{ {
@ -183,11 +206,12 @@ void MiniMax::saveHeader(PlyInfoFileHeader *piH, PlyInfo *pInfo)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: openDatabase() // Name: openDatabase()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
bool MiniMax::openDatabase(const char *directory, unsigned int maximumNumberOfBranches) 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!"); PRINT(0, this, "ERROR: Database path " << directory << " not valid!");
return falseOrStop(); return falseOrStop();
} }
@ -198,17 +222,18 @@ bool MiniMax::openDatabase(const char *directory, unsigned int maximumNumberOfBr
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: openSkvFile() // Name: openSkvFile()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void MiniMax::openSkvFile(const char *directory, unsigned int maximumNumberOfBranches) void MiniMax::openSkvFile(const char *directory, unsigned int maximumNumberOfBranches)
{ {
// locals // locals
stringstream ssDatabaseFile; stringstream ssDatabaseFile;
DWORD dwBytesRead; DWORD dwBytesRead;
unsigned int i; unsigned int i;
// don't open file twice // don't open file twice
if (hFileShortKnotValues != nullptr) return; if (hFileShortKnotValues != nullptr)
return;
// remember directory name // remember directory name
fileDirectory.assign(directory); 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); 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 // opened file succesfully
if (hFileShortKnotValues == INVALID_HANDLE_VALUE) { if (hFileShortKnotValues == INVALID_HANDLE_VALUE)
{
hFileShortKnotValues = nullptr; hFileShortKnotValues = nullptr;
return; return;
} }
@ -232,7 +258,8 @@ void MiniMax::openSkvFile(const char *directory, unsigned int maximumNumberOfBra
ReadFile(hFileShortKnotValues, &skvfHeader, sizeof(SkvFileHeader), &dwBytesRead, nullptr); ReadFile(hFileShortKnotValues, &skvfHeader, sizeof(SkvFileHeader), &dwBytesRead, nullptr);
// invalid file ? // 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 // create default header
skvfHeader.completed = false; skvfHeader.completed = false;
@ -242,7 +269,8 @@ void MiniMax::openSkvFile(const char *directory, unsigned int maximumNumberOfBra
layerStats = new LayerStats[skvfHeader.numLayers]; layerStats = new LayerStats[skvfHeader.numLayers];
layerStats[0].layerOffset = 0; 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]); getSuccLayers(i, &layerStats[i].numSuccLayers, &layerStats[i].succLayers[0]);
layerStats[i].partnerLayer = getPartnerLayer(i); layerStats[i].partnerLayer = getPartnerLayer(i);
layerStats[i].knotsInLayer = getNumberOfKnotsInLayer(i); layerStats[i].knotsInLayer = getNumberOfKnotsInLayer(i);
@ -257,7 +285,8 @@ void MiniMax::openSkvFile(const char *directory, unsigned int maximumNumberOfBra
layerStats[i].numInvalidStates = 0; 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; 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); saveHeader(&skvfHeader, layerStats);
// read layer stats // read layer stats
} else { }
else
{
layerStats = new LayerStats[skvfHeader.numLayers]; layerStats = new LayerStats[skvfHeader.numLayers];
ReadFile(hFileShortKnotValues, layerStats, sizeof(LayerStats) * skvfHeader.numLayers, &dwBytesRead, nullptr); 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].shortKnotValueByte = nullptr;
layerStats[i].skvCompressed = nullptr; layerStats[i].skvCompressed = nullptr;
} }
@ -277,27 +309,30 @@ void MiniMax::openSkvFile(const char *directory, unsigned int maximumNumberOfBra
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: openPlyInfoFile() // Name: openPlyInfoFile()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void MiniMax::openPlyInfoFile(const char *directory) void MiniMax::openPlyInfoFile(const char *directory)
{ {
// locals // locals
stringstream ssFile; stringstream ssFile;
DWORD dwBytesRead; DWORD dwBytesRead;
unsigned int i; unsigned int i;
// don't open file twice // don't open file twice
if (hFilePlyInfo != nullptr) return; if (hFilePlyInfo != nullptr)
return;
// remember directory name // remember directory name
ssFile << directory << (strlen(directory) ? "\\" : "") << "plyInfo.dat"; 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) // 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); 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 // opened file succesfully
if (hFilePlyInfo == INVALID_HANDLE_VALUE) { if (hFilePlyInfo == INVALID_HANDLE_VALUE)
{
hFilePlyInfo = nullptr; hFilePlyInfo = nullptr;
return; return;
} }
@ -309,7 +344,8 @@ void MiniMax::openPlyInfoFile(const char *directory)
ReadFile(hFilePlyInfo, &plyInfoHeader, sizeof(plyInfoHeader), &dwBytesRead, nullptr); ReadFile(hFilePlyInfo, &plyInfoHeader, sizeof(plyInfoHeader), &dwBytesRead, nullptr);
// invalid file ? // invalid file ?
if (dwBytesRead != sizeof(plyInfoHeader) || plyInfoHeader.headerCode != PLYINFO_HEADER_CODE) { if (dwBytesRead != sizeof(plyInfoHeader) || plyInfoHeader.headerCode != PLYINFO_HEADER_CODE)
{
// create default header // create default header
plyInfoHeader.plyInfoCompleted = false; plyInfoHeader.plyInfoCompleted = false;
@ -319,7 +355,8 @@ void MiniMax::openPlyInfoFile(const char *directory)
plyInfos = new PlyInfo[plyInfoHeader.numLayers]; plyInfos = new PlyInfo[plyInfoHeader.numLayers];
plyInfos[0].layerOffset = 0; 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].knotsInLayer = getNumberOfKnotsInLayer(i);
plyInfos[i].plyInfo = nullptr; plyInfos[i].plyInfo = nullptr;
plyInfos[i].plyInfoCompressed = nullptr; plyInfos[i].plyInfoCompressed = nullptr;
@ -328,7 +365,8 @@ void MiniMax::openPlyInfoFile(const char *directory)
plyInfos[i].sizeInBytes = plyInfos[i].knotsInLayer * sizeof(PlyInfoVarType); 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; plyInfos[i].layerOffset = plyInfos[i - 1].layerOffset + plyInfos[i - 1].sizeInBytes;
} }
@ -336,10 +374,13 @@ void MiniMax::openPlyInfoFile(const char *directory)
saveHeader(&plyInfoHeader, plyInfos); saveHeader(&plyInfoHeader, plyInfos);
// read layer stats // read layer stats
} else { }
else
{
plyInfos = new PlyInfo[plyInfoHeader.numLayers]; plyInfos = new PlyInfo[plyInfoHeader.numLayers];
ReadFile(hFilePlyInfo, plyInfos, sizeof(PlyInfo) * plyInfoHeader.numLayers, &dwBytesRead, nullptr); 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].plyInfo = nullptr;
plyInfos[i].plyInfoCompressed = nullptr; plyInfos[i].plyInfoCompressed = nullptr;
} }
@ -348,17 +389,19 @@ void MiniMax::openPlyInfoFile(const char *directory)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: saveLayerToFile() // Name: saveLayerToFile()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void MiniMax::saveLayerToFile(unsigned int layerNumber) void MiniMax::saveLayerToFile(unsigned int layerNumber)
{ {
// don't save layer and header when only preparing layers // don't save layer and header when only preparing layers
PlyInfo *myPis = &plyInfos[layerNumber]; PlyInfo *myPis = &plyInfos[layerNumber];
LayerStats *myLss = &layerStats[layerNumber]; LayerStats *myLss = &layerStats[layerNumber];
if (onlyPrepareLayer) return; if (onlyPrepareLayer)
return;
// save layer if there are any states // save layer if there are any states
if (myLss->sizeInBytes) { if (myLss->sizeInBytes)
{
// short knot values & ply info // short knot values & ply info
curCalculationActionId = MM_ACTION_SAVING_LAYER_TO_FILE; curCalculationActionId = MM_ACTION_SAVING_LAYER_TO_FILE;
@ -373,39 +416,44 @@ void MiniMax::saveLayerToFile(unsigned int layerNumber)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: measureIops() // Name: measureIops()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
inline void MiniMax::measureIops(long long &numOperations, LARGE_INTEGER &interval, LARGE_INTEGER &curTimeBefore, char text[]) inline void MiniMax::measureIops(long long &numOperations, LARGE_INTEGER &interval, LARGE_INTEGER &curTimeBefore, char text[])
{ {
// locals // locals
LARGE_INTEGER curTimeAfter; LARGE_INTEGER curTimeAfter;
if (!MEASURE_IOPS) return; if (!MEASURE_IOPS)
numOperations++; // ... not thread-safe !!! return;
numOperations++; // ... not thread-safe !!!
// only the time for the io-operation is considered and accumulated // only the time for the io-operation is considered and accumulated
if (MEASURE_ONLY_IO) { if (MEASURE_ONLY_IO)
{
QueryPerformanceCounter(&curTimeAfter); QueryPerformanceCounter(&curTimeAfter);
interval.QuadPart += curTimeAfter.QuadPart - curTimeBefore.QuadPart; // ... not thread-safe !!! interval.QuadPart += curTimeAfter.QuadPart - curTimeBefore.QuadPart; // ... not thread-safe !!!
double totalTimeGone = (double)interval.QuadPart / frequency.QuadPart; // ... not thread-safe !!! double totalTimeGone = (double)interval.QuadPart / frequency.QuadPart; // ... not thread-safe !!!
if (totalTimeGone >= 5.0) { if (totalTimeGone >= 5.0)
{
PRINT(0, this, text << "operations per second for last interval: " << (int)(numOperations / totalTimeGone)); PRINT(0, this, text << "operations per second for last interval: " << (int)(numOperations / totalTimeGone));
interval.QuadPart = 0; // ... not thread-safe !!! interval.QuadPart = 0; // ... not thread-safe !!!
numOperations = 0; // ... not thread-safe !!! numOperations = 0; // ... not thread-safe !!!
} }
// the whole time passed since the beginning of the interval is considered // 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); 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); PRINT(0, this, text << "operations per second for last interval: " << numOperations / totalTimeGone);
interval.QuadPart = curTimeAfter.QuadPart; // ... not thread-safe !!! interval.QuadPart = curTimeAfter.QuadPart; // ... not thread-safe !!!
numOperations = 0; // ... not thread-safe !!! numOperations = 0; // ... not thread-safe !!!
} }
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: readKnotValueFromDatabase() // Name: readKnotValueFromDatabase()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void MiniMax::readKnotValueFromDatabase(unsigned int threadNo, unsigned int &layerNumber, unsigned int &stateNumber, TwoBit &knotValue, bool &invalidLayerOrStateNumber, bool &layerInDatabaseAndCompleted) 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; layerInDatabaseAndCompleted = myLss->layerIsCompletedAndInFile;
// valid state and layer number ? // valid state and layer number ?
if (layerNumber > skvfHeader.numLayers || stateNumber > myLss->knotsInLayer) { if (layerNumber > skvfHeader.numLayers || stateNumber > myLss->knotsInLayer)
{
invalidLayerOrStateNumber = true; invalidLayerOrStateNumber = true;
} else { }
else
{
invalidLayerOrStateNumber = false; // checkStateIntegrity(); invalidLayerOrStateNumber = false; // checkStateIntegrity();
} }
if (invalidLayerOrStateNumber) { if (invalidLayerOrStateNumber)
{
knotValue = SKV_VALUE_INVALID; knotValue = SKV_VALUE_INVALID;
return; return;
} }
@ -434,40 +486,49 @@ void MiniMax::readKnotValueFromDatabase(unsigned int threadNo, unsigned int &lay
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: readKnotValueFromDatabase() // Name: readKnotValueFromDatabase()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void MiniMax::readKnotValueFromDatabase(unsigned int layerNumber, unsigned int stateNumber, TwoBit &knotValue) void MiniMax::readKnotValueFromDatabase(unsigned int layerNumber, unsigned int stateNumber, TwoBit &knotValue)
{ {
// locals // locals
TwoBit databaseByte; TwoBit databaseByte;
long long bytesAllocated; long long bytesAllocated;
TwoBit defValue = SKV_WHOLE_BYTE_IS_INVALID; TwoBit defValue = SKV_WHOLE_BYTE_IS_INVALID;
LayerStats *myLss = &layerStats[layerNumber]; LayerStats *myLss = &layerStats[layerNumber];
// valid state and layer number ? // 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()!"); PRINT(0, this, "ERROR: INVALID layerNumber OR stateNumber in readKnotValueFromDatabase()!");
knotValue = SKV_VALUE_INVALID; knotValue = SKV_VALUE_INVALID;
return; return;
} }
// if database is complete get whole byte from file // if database is complete get whole byte from file
if (skvfHeader.completed || layerInDatabase || myLss->layerIsCompletedAndInFile) { if (skvfHeader.completed || layerInDatabase || myLss->layerIsCompletedAndInFile)
{
EnterCriticalSection(&csDatabase); EnterCriticalSection(&csDatabase);
loadBytesFromFile(hFileShortKnotValues, skvfHeader.headerAndStatsSize + myLss->layerOffset + stateNumber / 4, 1, &databaseByte); loadBytesFromFile(hFileShortKnotValues, skvfHeader.headerAndStatsSize + myLss->layerOffset + stateNumber / 4, 1, &databaseByte);
LeaveCriticalSection(&csDatabase); LeaveCriticalSection(&csDatabase);
} else { }
else
{
// is layer already loaded // is layer already loaded
if (!myLss->layerIsLoaded) { if (!myLss->layerIsLoaded)
{
EnterCriticalSection(&csDatabase); 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 // 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]; myLss->shortKnotValueByte = new unsigned char[myLss->sizeInBytes];
if (myLss->layerIsCompletedAndInFile) { if (myLss->layerIsCompletedAndInFile)
{
loadBytesFromFile(hFileShortKnotValues, skvfHeader.headerAndStatsSize + myLss->layerOffset, myLss->sizeInBytes, myLss->shortKnotValueByte); loadBytesFromFile(hFileShortKnotValues, skvfHeader.headerAndStatsSize + myLss->layerOffset, myLss->sizeInBytes, myLss->shortKnotValueByte);
} else { }
else
{
memset(myLss->shortKnotValueByte, SKV_WHOLE_BYTE_IS_INVALID, myLss->sizeInBytes); memset(myLss->shortKnotValueByte, SKV_WHOLE_BYTE_IS_INVALID, myLss->sizeInBytes);
} }
bytesAllocated = myLss->sizeInBytes; bytesAllocated = myLss->sizeInBytes;
@ -483,7 +544,8 @@ void MiniMax::readKnotValueFromDatabase(unsigned int layerNumber, unsigned int s
// measure io-operations per second // measure io-operations per second
LARGE_INTEGER curTimeBefore; LARGE_INTEGER curTimeBefore;
if (MEASURE_IOPS && MEASURE_ONLY_IO) { if (MEASURE_IOPS && MEASURE_ONLY_IO)
{
QueryPerformanceCounter(&curTimeBefore); QueryPerformanceCounter(&curTimeBefore);
} }
@ -500,40 +562,50 @@ void MiniMax::readKnotValueFromDatabase(unsigned int layerNumber, unsigned int s
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: readPlyInfoFromDatabase() // Name: readPlyInfoFromDatabase()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void MiniMax::readPlyInfoFromDatabase(unsigned int layerNumber, unsigned int stateNumber, PlyInfoVarType &value) void MiniMax::readPlyInfoFromDatabase(unsigned int layerNumber, unsigned int stateNumber, PlyInfoVarType &value)
{ {
// locals // locals
unsigned int curKnot; unsigned int curKnot;
PlyInfoVarType defValue = PLYINFO_VALUE_UNCALCULATED; PlyInfoVarType defValue = PLYINFO_VALUE_UNCALCULATED;
long long bytesAllocated; long long bytesAllocated;
PlyInfo *myPis = &plyInfos[layerNumber]; PlyInfo *myPis = &plyInfos[layerNumber];
// valid state and layer number ? // 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()!"); PRINT(0, this, "ERROR: INVALID layerNumber OR stateNumber in readPlyInfoFromDatabase()!");
value = PLYINFO_VALUE_INVALID; value = PLYINFO_VALUE_INVALID;
return; return;
} }
// if database is complete get whole byte from file // if database is complete get whole byte from file
if (plyInfoHeader.plyInfoCompleted || layerInDatabase || myPis->plyInfoIsCompletedAndInFile) { if (plyInfoHeader.plyInfoCompleted || layerInDatabase || myPis->plyInfoIsCompletedAndInFile)
{
EnterCriticalSection(&csDatabase); EnterCriticalSection(&csDatabase);
loadBytesFromFile(hFilePlyInfo, plyInfoHeader.headerAndPlyInfosSize + myPis->layerOffset + sizeof(PlyInfoVarType) * stateNumber, sizeof(PlyInfoVarType), &value); loadBytesFromFile(hFilePlyInfo, plyInfoHeader.headerAndPlyInfosSize + myPis->layerOffset + sizeof(PlyInfoVarType) * stateNumber, sizeof(PlyInfoVarType), &value);
LeaveCriticalSection(&csDatabase); LeaveCriticalSection(&csDatabase);
} else { }
else
{
// is layer already in memory? // is layer already in memory?
if (!myPis->plyInfoIsLoaded) { if (!myPis->plyInfoIsLoaded)
{
EnterCriticalSection(&csDatabase); 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 // if layer is in database and completed, then load layer from file into memory; set default value otherwise
myPis->plyInfo = new PlyInfoVarType[myPis->knotsInLayer]; myPis->plyInfo = new PlyInfoVarType[myPis->knotsInLayer];
if (myPis->plyInfoIsCompletedAndInFile) { if (myPis->plyInfoIsCompletedAndInFile)
{
loadBytesFromFile(hFilePlyInfo, plyInfoHeader.headerAndPlyInfosSize + myPis->layerOffset, myPis->sizeInBytes, myPis->plyInfo); 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; myPis->plyInfo[curKnot] = defValue;
} }
} }
@ -548,7 +620,8 @@ void MiniMax::readPlyInfoFromDatabase(unsigned int layerNumber, unsigned int sta
// measure io-operations per second // measure io-operations per second
LARGE_INTEGER curTimeBefore; LARGE_INTEGER curTimeBefore;
if (MEASURE_IOPS && MEASURE_ONLY_IO) { if (MEASURE_IOPS && MEASURE_ONLY_IO)
{
QueryPerformanceCounter(&curTimeBefore); QueryPerformanceCounter(&curTimeBefore);
} }
@ -562,32 +635,36 @@ void MiniMax::readPlyInfoFromDatabase(unsigned int layerNumber, unsigned int sta
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: saveKnotValueInDatabase() // Name: saveKnotValueInDatabase()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void MiniMax::saveKnotValueInDatabase(unsigned int layerNumber, unsigned int stateNumber, TwoBit knotValue) void MiniMax::saveKnotValueInDatabase(unsigned int layerNumber, unsigned int stateNumber, TwoBit knotValue)
{ {
// locals // locals
long long bytesAllocated; long long bytesAllocated;
TwoBit defValue = SKV_WHOLE_BYTE_IS_INVALID; TwoBit defValue = SKV_WHOLE_BYTE_IS_INVALID;
LayerStats *myLss = &layerStats[layerNumber]; LayerStats *myLss = &layerStats[layerNumber];
// valid state and layer number ? // 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()!"); PRINT(0, this, "ERROR: INVALID layerNumber OR stateNumber in saveKnotValueInDatabase()!");
return; return;
} }
// is layer already completed ? // is layer already completed ?
if (myLss->layerIsCompletedAndInFile) { if (myLss->layerIsCompletedAndInFile)
{
PRINT(0, this, "ERROR: layer already completed and in file! function: saveKnotValueInDatabase()!"); PRINT(0, this, "ERROR: layer already completed and in file! function: saveKnotValueInDatabase()!");
return; return;
} }
// is layer already loaded? // is layer already loaded?
if (!myLss->layerIsLoaded) { if (!myLss->layerIsLoaded)
{
EnterCriticalSection(&csDatabase); EnterCriticalSection(&csDatabase);
if (!myLss->layerIsLoaded) { if (!myLss->layerIsLoaded)
{
// reserve memory for this layer & create array for ply info with default value // reserve memory for this layer & create array for ply info with default value
myLss->shortKnotValueByte = new TwoBit[myLss->sizeInBytes]; myLss->shortKnotValueByte = new TwoBit[myLss->sizeInBytes];
memset(myLss->shortKnotValueByte, SKV_WHOLE_BYTE_IS_INVALID, 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 // measure io-operations per second
LARGE_INTEGER curTimeBefore; LARGE_INTEGER curTimeBefore;
if (MEASURE_IOPS && MEASURE_ONLY_IO) { if (MEASURE_IOPS && MEASURE_ONLY_IO)
{
QueryPerformanceCounter(&curTimeBefore); QueryPerformanceCounter(&curTimeBefore);
} }
// set value // set value
long *pShortKnotValue = ((long *)myLss->shortKnotValueByte) + stateNumber / ((sizeof(long) * 8) / 2); long *pShortKnotValue = ((long *)myLss->shortKnotValueByte) + stateNumber / ((sizeof(long) * 8) / 2);
long numBitsToShift = 2 * (stateNumber % ((sizeof(long) * 8) / 2)); // little-endian byte-order long numBitsToShift = 2 * (stateNumber % ((sizeof(long) * 8) / 2)); // little-endian byte-order
long mask = 0x00000003 << numBitsToShift; long mask = 0x00000003 << numBitsToShift;
long curShortKnotValueLong, newShortKnotValueLong; long curShortKnotValueLong, newShortKnotValueLong;
do { do
{
curShortKnotValueLong = *pShortKnotValue; curShortKnotValueLong = *pShortKnotValue;
newShortKnotValueLong = (curShortKnotValueLong & (~mask)) + (knotValue << numBitsToShift); newShortKnotValueLong = (curShortKnotValueLong & (~mask)) + (knotValue << numBitsToShift);
} while (InterlockedCompareExchange(pShortKnotValue, newShortKnotValueLong, curShortKnotValueLong) != curShortKnotValueLong); } while (InterlockedCompareExchange(pShortKnotValue, newShortKnotValueLong, curShortKnotValueLong) != curShortKnotValueLong);
@ -625,36 +704,41 @@ void MiniMax::saveKnotValueInDatabase(unsigned int layerNumber, unsigned int sta
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: savePlyInfoInDatabase() // Name: savePlyInfoInDatabase()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void MiniMax::savePlyInfoInDatabase(unsigned int layerNumber, unsigned int stateNumber, PlyInfoVarType value) void MiniMax::savePlyInfoInDatabase(unsigned int layerNumber, unsigned int stateNumber, PlyInfoVarType value)
{ {
// locals // locals
unsigned int curKnot; unsigned int curKnot;
PlyInfoVarType defValue = PLYINFO_VALUE_UNCALCULATED; PlyInfoVarType defValue = PLYINFO_VALUE_UNCALCULATED;
long long bytesAllocated; long long bytesAllocated;
PlyInfo *myPis = &plyInfos[layerNumber]; PlyInfo *myPis = &plyInfos[layerNumber];
// valid state and layer number ? // 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()!"); PRINT(0, this, "ERROR: INVALID layerNumber OR stateNumber in savePlyInfoInDatabase()!");
return; return;
} }
// is layer already completed ? // is layer already completed ?
if (myPis->plyInfoIsCompletedAndInFile) { if (myPis->plyInfoIsCompletedAndInFile)
{
PRINT(0, this, "ERROR: layer already completed and in file! function: savePlyInfoInDatabase()!"); PRINT(0, this, "ERROR: layer already completed and in file! function: savePlyInfoInDatabase()!");
return; return;
} }
// is layer already loaded // is layer already loaded
if (!myPis->plyInfoIsLoaded) { if (!myPis->plyInfoIsLoaded)
{
EnterCriticalSection(&csDatabase); EnterCriticalSection(&csDatabase);
if (!myPis->plyInfoIsLoaded) { if (!myPis->plyInfoIsLoaded)
{
// reserve memory for this layer & create array for ply info with default value // reserve memory for this layer & create array for ply info with default value
myPis->plyInfo = new PlyInfoVarType[myPis->knotsInLayer]; myPis->plyInfo = new PlyInfoVarType[myPis->knotsInLayer];
for (curKnot = 0; curKnot < myPis->knotsInLayer; curKnot++) { for (curKnot = 0; curKnot < myPis->knotsInLayer; curKnot++)
{
myPis->plyInfo[curKnot] = defValue; myPis->plyInfo[curKnot] = defValue;
} }
bytesAllocated = myPis->sizeInBytes; bytesAllocated = myPis->sizeInBytes;
@ -668,7 +752,8 @@ void MiniMax::savePlyInfoInDatabase(unsigned int layerNumber, unsigned int state
// measure io-operations per second // measure io-operations per second
LARGE_INTEGER curTimeBefore; LARGE_INTEGER curTimeBefore;
if (MEASURE_IOPS && MEASURE_ONLY_IO) { if (MEASURE_IOPS && MEASURE_ONLY_IO)
{
QueryPerformanceCounter(&curTimeBefore); QueryPerformanceCounter(&curTimeBefore);
} }

View File

@ -10,7 +10,7 @@ s\*********************************************************************/
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: calcKnotValuesByRetroAnalysis() // 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, // 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, // 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. // 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<unsigned int> &layersToCalculate) bool MiniMax::calcKnotValuesByRetroAnalysis(vector<unsigned int> &layersToCalculate)
{ {
// locals // locals
bool abortCalculation = false; bool abortCalculation = false;
unsigned int curLayer = 0; // Counter variable unsigned int curLayer = 0; // Counter variable
unsigned int curSubLayer = 0; // Counter variable unsigned int curSubLayer = 0; // Counter variable
unsigned int plyCounter = 0; // Counter variable unsigned int plyCounter = 0; // Counter variable
unsigned int threadNo; unsigned int threadNo;
stringstream ssLayers; stringstream ssLayers;
retroAnalysisGlobalVars retroVars; retroAnalysisGlobalVars retroVars;
// init retro vars // init retro vars
retroVars.thread.resize(threadManager.getNumThreads()); 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].statesToProcess.resize(PLYINFO_EXP_VALUE, nullptr);
retroVars.thread[threadNo].numStatesToProcess = 0; retroVars.thread[threadNo].numStatesToProcess = 0;
retroVars.thread[threadNo].threadNo = threadNo; retroVars.thread[threadNo].threadNo = threadNo;
@ -39,65 +40,83 @@ bool MiniMax::calcKnotValuesByRetroAnalysis(vector<unsigned int> &layersToCalcul
retroVars.layerInitialized.resize(skvfHeader.numLayers, false); retroVars.layerInitialized.resize(skvfHeader.numLayers, false);
retroVars.layersToCalculate = layersToCalculate; retroVars.layersToCalculate = layersToCalculate;
retroVars.pMiniMax = this; 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.numKnotsToCalc += layerStats[layersToCalculate[curLayer]].knotsInLayer;
retroVars.totalNumKnots += layerStats[layersToCalculate[curLayer]].knotsInLayer; retroVars.totalNumKnots += layerStats[layersToCalculate[curLayer]].knotsInLayer;
retroVars.layerInitialized[layersToCalculate[curLayer]] = true; retroVars.layerInitialized[layersToCalculate[curLayer]] = true;
for (curSubLayer = 0; curSubLayer < layerStats[layersToCalculate[curLayer]].numSuccLayers; curSubLayer++) { 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; 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.totalNumKnots += layerStats[layerStats[layersToCalculate[curLayer]].succLayers[curSubLayer]].knotsInLayer;
} }
} }
retroVars.layerInitialized.assign(skvfHeader.numLayers, false); retroVars.layerInitialized.assign(skvfHeader.numLayers, false);
// output & filenames // 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 ***"); PRINT(0, this, "*** Calculate layers" << ssLayers.str() << " by retro analysis ***");
// initialization // initialization
PRINT(2, this, " Bytes in memory: " << memoryUsed2 << endl); PRINT(2, this, " Bytes in memory: " << memoryUsed2 << endl);
if (!initRetroAnalysis(retroVars)) { if (!initRetroAnalysis(retroVars))
abortCalculation = true; goto freeMem; {
abortCalculation = true;
goto freeMem;
} }
// prepare count arrays // prepare count arrays
PRINT(2, this, " Bytes in memory: " << memoryUsed2 << endl); PRINT(2, this, " Bytes in memory: " << memoryUsed2 << endl);
if (!prepareCountArrays(retroVars)) { if (!prepareCountArrays(retroVars))
abortCalculation = true; goto freeMem; {
abortCalculation = true;
goto freeMem;
} }
// stop here if only preparing layer // stop here if only preparing layer
if (onlyPrepareLayer) goto freeMem; if (onlyPrepareLayer)
goto freeMem;
// iteration // iteration
PRINT(2, this, " Bytes in memory: " << memoryUsed2 << endl); PRINT(2, this, " Bytes in memory: " << memoryUsed2 << endl);
if (!performRetroAnalysis(retroVars)) { if (!performRetroAnalysis(retroVars))
abortCalculation = true; goto freeMem; {
abortCalculation = true;
goto freeMem;
} }
// show output // show output
PRINT(2, this, " Bytes in memory: " << memoryUsed2); PRINT(2, this, " Bytes in memory: " << memoryUsed2);
for (curLayer = 0; curLayer < layersToCalculate.size(); curLayer++) { for (curLayer = 0; curLayer < layersToCalculate.size(); curLayer++)
{
showLayerStats(layersToCalculate[curLayer]); showLayerStats(layersToCalculate[curLayer]);
} }
PRINT(2, this, ""); PRINT(2, this, "");
// free memory // free memory
freeMem: freeMem:
for (threadNo = 0; threadNo < threadManager.getNumThreads(); threadNo++) { for (threadNo = 0; threadNo < threadManager.getNumThreads(); threadNo++)
for (plyCounter = 0; plyCounter < retroVars.thread[threadNo].statesToProcess.size(); plyCounter++) { {
for (plyCounter = 0; plyCounter < retroVars.thread[threadNo].statesToProcess.size(); plyCounter++)
{
SAFE_DELETE(retroVars.thread[threadNo].statesToProcess[plyCounter]); SAFE_DELETE(retroVars.thread[threadNo].statesToProcess[plyCounter]);
} }
} }
for (curLayer = 0; curLayer < layersToCalculate.size(); curLayer++) { for (curLayer = 0; curLayer < layersToCalculate.size(); curLayer++)
if (retroVars.countArrays[curLayer] != nullptr) { {
if (retroVars.countArrays[curLayer] != nullptr)
{
memoryUsed2 -= layerStats[layersToCalculate[curLayer]].knotsInLayer * sizeof(CountArrayVarType); memoryUsed2 -= layerStats[layersToCalculate[curLayer]].knotsInLayer * sizeof(CountArrayVarType);
arrayInfos.removeArray(layersToCalculate[curLayer], ArrayInfo::arrayType_countArray, layerStats[layersToCalculate[curLayer]].knotsInLayer * sizeof(CountArrayVarType), 0); arrayInfos.removeArray(layersToCalculate[curLayer], ArrayInfo::arrayType_countArray, layerStats[layersToCalculate[curLayer]].knotsInLayer * sizeof(CountArrayVarType), 0);
} }
SAFE_DELETE_ARRAY(retroVars.countArrays[curLayer]); 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; return !abortCalculation;
} }
@ -108,15 +127,16 @@ freeMem:
bool MiniMax::initRetroAnalysis(retroAnalysisGlobalVars &retroVars) bool MiniMax::initRetroAnalysis(retroAnalysisGlobalVars &retroVars)
{ {
// locals // locals
unsigned int curLayerId; // current processed layer within 'layersToCalculate' unsigned int curLayerId; // current processed layer within 'layersToCalculate'
unsigned int layerNumber; // layer number of the current process layer unsigned int layerNumber; // layer number of the current process layer
stringstream ssInitArrayPath; // path of the working directory stringstream ssInitArrayPath; // path of the working directory
stringstream ssInitArrayFilePath; // filename corresponding to a cyclic array file which is used for storage stringstream ssInitArrayFilePath; // filename corresponding to a cyclic array file which is used for storage
BufferedFile *initArray; // BufferedFile *initArray; //
bool initAlreadyDone = false; // true if the initialization information is already available in a file bool initAlreadyDone = false; // true if the initialization information is already available in a file
// process each layer // process each layer
for (curLayerId = 0; curLayerId < retroVars.layersToCalculate.size(); curLayerId++) { for (curLayerId = 0; curLayerId < retroVars.layersToCalculate.size(); curLayerId++)
{
// set current processed layer number // set current processed layer number
layerNumber = retroVars.layersToCalculate[curLayerId]; 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 ***"); PRINT(1, this, endl << " *** Initialization of layer " << layerNumber << " (" << (getOutputInformation(layerNumber)) << ") which has " << layerStats[layerNumber].knotsInLayer << " knots ***");
// file names // file names
ssInitArrayPath.str(""); ssInitArrayPath << fileDirectory << (fileDirectory.size() ? "\\" : "") << "initLayer"; ssInitArrayPath.str("");
ssInitArrayFilePath.str(""); ssInitArrayFilePath << fileDirectory << (fileDirectory.size() ? "\\" : "") << "initLayer\\initLayer" << layerNumber << ".dat"; ssInitArrayPath << fileDirectory << (fileDirectory.size() ? "\\" : "") << "initLayer";
ssInitArrayFilePath.str("");
ssInitArrayFilePath << fileDirectory << (fileDirectory.size() ? "\\" : "") << "initLayer\\initLayer" << layerNumber << ".dat";
// does initialization file exist ? // does initialization file exist ?
CreateDirectoryA(ssInitArrayPath.str().c_str(), nullptr); CreateDirectoryA(ssInitArrayPath.str().c_str(), nullptr);
initArray = new BufferedFile(threadManager.getNumThreads(), FILE_BUFFER_SIZE, ssInitArrayFilePath.str().c_str()); 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()); PRINT(2, this, " Loading init states from file: " << ssInitArrayFilePath.str());
initAlreadyDone = true; initAlreadyDone = true;
} }
// don't add layers twice // don't add layers twice
if (retroVars.layerInitialized[layerNumber]) continue; if (retroVars.layerInitialized[layerNumber])
else retroVars.layerInitialized[layerNumber] = true; continue;
else
retroVars.layerInitialized[layerNumber] = true;
// prepare parameters // prepare parameters
numStatesProcessed = 0; numStatesProcessed = 0;
@ -148,7 +173,8 @@ bool MiniMax::initRetroAnalysis(retroAnalysisGlobalVars &retroVars)
ThreadManager::ThreadVarsArray<InitRetroAnalysisVars> tva(threadManager.getNumThreads(), InitRetroAnalysisVars(this, &retroVars, layerNumber, initArray, initAlreadyDone)); ThreadManager::ThreadVarsArray<InitRetroAnalysisVars> tva(threadManager.getNumThreads(), InitRetroAnalysisVars(this, &retroVars, layerNumber, initArray, initAlreadyDone));
// process each state in the current layer // 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: case TM_RETURN_VALUE_OK:
break; break;
case TM_RETURN_VALUE_EXECUTION_CANCELLED: case TM_RETURN_VALUE_EXECUTION_CANCELLED:
@ -166,7 +192,8 @@ bool MiniMax::initRetroAnalysis(retroAnalysisGlobalVars &retroVars)
initAlreadyDone = false; initAlreadyDone = false;
initArray->flushBuffers(); initArray->flushBuffers();
SAFE_DELETE(initArray); 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 // when init file was created new then save it now
PRINT(2, this, " Saved initialized states to file: " << ssInitArrayFilePath.str()); PRINT(2, this, " Saved initialized states to file: " << ssInitArrayFilePath.str());
@ -182,54 +209,64 @@ bool MiniMax::initRetroAnalysis(retroAnalysisGlobalVars &retroVars)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: initRetroAnalysisParallelSub() // Name: initRetroAnalysisParallelSub()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
DWORD MiniMax::initRetroAnalysisThreadProc(void *pParameter, int index) DWORD MiniMax::initRetroAnalysisThreadProc(void *pParameter, int index)
{ {
// locals // locals
InitRetroAnalysisVars *iraVars = (InitRetroAnalysisVars *)pParameter; InitRetroAnalysisVars *iraVars = (InitRetroAnalysisVars *)pParameter;
MiniMax *m = iraVars->pMiniMax; MiniMax *m = iraVars->pMiniMax;
float floatValue; // dummy variable for calls of getValueOfSituation() float floatValue; // dummy variable for calls of getValueOfSituation()
StateAdress curState; // current state counter for loops StateAdress curState; // current state counter for loops
TwoBit curStateValue; // for calls of getValueOfSituation() TwoBit curStateValue; // for calls of getValueOfSituation()
curState.layerNumber = iraVars->layerNumber; curState.layerNumber = iraVars->layerNumber;
curState.stateNumber = index; curState.stateNumber = index;
iraVars->statesProcessed++; iraVars->statesProcessed++;
// print status // print status
if (iraVars->statesProcessed % OUTPUT_EVERY_N_STATES == 0) { if (iraVars->statesProcessed % OUTPUT_EVERY_N_STATES == 0)
{
m->numStatesProcessed += OUTPUT_EVERY_N_STATES; m->numStatesProcessed += OUTPUT_EVERY_N_STATES;
PRINT(2, m, "Already initialized " << m->numStatesProcessed << " of " << m->layerStats[curState.layerNumber].knotsInLayer << " 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 // layer initialization already done ? if so, then read from file
if (iraVars->initAlreadyDone) { if (iraVars->initAlreadyDone)
if (!iraVars->bufferedFile->readBytes(iraVars->curThreadNo, index * sizeof(TwoBit), sizeof(TwoBit), (unsigned char *)&curStateValue)) { {
if (!iraVars->bufferedFile->readBytes(iraVars->curThreadNo, index * sizeof(TwoBit), sizeof(TwoBit), (unsigned char *)&curStateValue))
{
PRINT(0, m, "ERROR: initArray->takeBytes() failed"); PRINT(0, m, "ERROR: initArray->takeBytes() failed");
return m->falseOrStop(); return m->falseOrStop();
} }
// initialization not done // initialization not done
} else { }
else
{
// set current selected situation // 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; curStateValue = SKV_VALUE_INVALID;
} else { }
else
{
// get value of current situation // get value of current situation
m->getValueOfSituation(iraVars->curThreadNo, floatValue, curStateValue); m->getValueOfSituation(iraVars->curThreadNo, floatValue, curStateValue);
} }
} }
// save init value // save init value
if (curStateValue != SKV_VALUE_INVALID) { if (curStateValue != SKV_VALUE_INVALID)
{
// save short knot value // save short knot value
m->saveKnotValueInDatabase(curState.layerNumber, curState.stateNumber, curStateValue); m->saveKnotValueInDatabase(curState.layerNumber, curState.stateNumber, curStateValue);
// put in list if state is final // 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 // ply info
m->savePlyInfoInDatabase(curState.layerNumber, curState.stateNumber, 0); m->savePlyInfoInDatabase(curState.layerNumber, curState.stateNumber, 0);
@ -240,9 +277,11 @@ DWORD MiniMax::initRetroAnalysisThreadProc(void *pParameter, int index)
} }
// write data to file // write data to file
if (!iraVars->initAlreadyDone) { if (!iraVars->initAlreadyDone)
{
// curStateValue sollte 2 sein bei index == 1329322 // 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!"); PRINT(0, m, "ERROR: bufferedFile->writeBytes failed!");
return m->falseOrStop(); return m->falseOrStop();
} }
@ -254,25 +293,26 @@ DWORD MiniMax::initRetroAnalysisThreadProc(void *pParameter, int index)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: prepareCountArrays() // Name: prepareCountArrays()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
bool MiniMax::prepareCountArrays(retroAnalysisGlobalVars &retroVars) bool MiniMax::prepareCountArrays(retroAnalysisGlobalVars &retroVars)
{ {
// locals // locals
unsigned int numKnotsInCurLayer; unsigned int numKnotsInCurLayer;
StateAdress curState; // current state counter for loops StateAdress curState; // current state counter for loops
unsigned int curLayer = 0; // Counter variable unsigned int curLayer = 0; // Counter variable
CountArrayVarType defValue = 0; // default counter array value CountArrayVarType defValue = 0; // default counter array value
DWORD dwWritten; DWORD dwWritten;
DWORD dwRead; DWORD dwRead;
LARGE_INTEGER fileSize; LARGE_INTEGER fileSize;
HANDLE hFileCountArray = nullptr; // file handle for loading and saving the arrays in 'countArrays' HANDLE hFileCountArray = nullptr; // file handle for loading and saving the arrays in 'countArrays'
stringstream ssCountArrayPath; stringstream ssCountArrayPath;
stringstream ssCountArrayFilePath; stringstream ssCountArrayFilePath;
stringstream ssLayers; stringstream ssLayers;
// output & filenames // 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"; ssCountArrayPath << fileDirectory << (fileDirectory.size() ? "\\" : "") << "countArray";
ssCountArrayFilePath << fileDirectory << (fileDirectory.size() ? "\\" : "") << "countArray\\countArray" << ssLayers.str() << ".dat"; ssCountArrayFilePath << fileDirectory << (fileDirectory.size() ? "\\" : "") << "countArray\\countArray" << ssLayers.str() << ".dat";
PRINT(2, this, " *** Prepare count arrays for layers " << ssLayers.str() << " ***" << endl); PRINT(2, this, " *** Prepare count arrays for layers " << ssLayers.str() << " ***" << endl);
@ -280,13 +320,15 @@ bool MiniMax::prepareCountArrays(retroAnalysisGlobalVars &retroVars)
// prepare count arrays // prepare count arrays
CreateDirectoryA(ssCountArrayPath.str().c_str(), nullptr); 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() << "!"); PRINT(0, this, "ERROR: Could not open File " << ssCountArrayFilePath.str() << "!");
return falseOrStop(); return falseOrStop();
} }
// allocate memory for count arrays // 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; numKnotsInCurLayer = layerStats[retroVars.layersToCalculate[curLayer]].knotsInLayer;
retroVars.countArrays[curLayer] = new CountArrayVarType[numKnotsInCurLayer]; retroVars.countArrays[curLayer] = new CountArrayVarType[numKnotsInCurLayer];
memoryUsed2 += numKnotsInCurLayer * sizeof(CountArrayVarType); memoryUsed2 += numKnotsInCurLayer * sizeof(CountArrayVarType);
@ -294,37 +336,49 @@ bool MiniMax::prepareCountArrays(retroAnalysisGlobalVars &retroVars)
} }
// load file if already existend // 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()); 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; numKnotsInCurLayer = layerStats[retroVars.layersToCalculate[curLayer]].knotsInLayer;
if (!ReadFile(hFileCountArray, retroVars.countArrays[curLayer], numKnotsInCurLayer * sizeof(CountArrayVarType), &dwRead, nullptr)) return falseOrStop(); if (!ReadFile(hFileCountArray, retroVars.countArrays[curLayer], numKnotsInCurLayer * sizeof(CountArrayVarType), &dwRead, nullptr))
if (dwRead != numKnotsInCurLayer * sizeof(CountArrayVarType)) return falseOrStop(); return falseOrStop();
if (dwRead != numKnotsInCurLayer * sizeof(CountArrayVarType))
return falseOrStop();
} }
// else calculate number of succedding states // else calculate number of succedding states
} else { }
else
{
// Set default value 0 // 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; 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; retroVars.countArrays[curLayer][curState.stateNumber] = defValue;
} }
} }
// calc values // calc values
if (!calcNumSuccedors(retroVars)) { if (!calcNumSuccedors(retroVars))
{
CloseHandle(hFileCountArray); CloseHandle(hFileCountArray);
return false; return false;
} }
// save to file // 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; numKnotsInCurLayer = layerStats[retroVars.layersToCalculate[curLayer]].knotsInLayer;
if (!WriteFile(hFileCountArray, retroVars.countArrays[curLayer], numKnotsInCurLayer * sizeof(CountArrayVarType), &dwWritten, nullptr)) return falseOrStop(); if (!WriteFile(hFileCountArray, retroVars.countArrays[curLayer], numKnotsInCurLayer * sizeof(CountArrayVarType), &dwWritten, nullptr))
if (dwWritten != numKnotsInCurLayer * sizeof(CountArrayVarType)) return falseOrStop(); return falseOrStop();
if (dwWritten != numKnotsInCurLayer * sizeof(CountArrayVarType))
return falseOrStop();
} }
PRINT(2, this, " Count array saved to file: " << ssCountArrayFilePath.str()); PRINT(2, this, " Count array saved to file: " << ssCountArrayFilePath.str());
} }
@ -336,26 +390,28 @@ bool MiniMax::prepareCountArrays(retroAnalysisGlobalVars &retroVars)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: calcNumSuccedors() // Name: calcNumSuccedors()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
bool MiniMax::calcNumSuccedors(retroAnalysisGlobalVars &retroVars) bool MiniMax::calcNumSuccedors(retroAnalysisGlobalVars &retroVars)
{ {
// locals // locals
unsigned int curLayerId; // current processed layer within 'layersToCalculate' unsigned int curLayerId; // current processed layer within 'layersToCalculate'
unsigned int layerNumber; // layer number of the current process layer unsigned int layerNumber; // layer number of the current process layer
StateAdress curState; // current state counter for loops StateAdress curState; // current state counter for loops
StateAdress succState; // current succeding state counter for loops StateAdress succState; // current succeding state counter for loops
vector<bool> succCalculated(skvfHeader.numLayers, false); // vector<bool> succCalculated(skvfHeader.numLayers, false); //
// process each layer // process each layer
for (curLayerId = 0; curLayerId < retroVars.layersToCalculate.size(); curLayerId++) { for (curLayerId = 0; curLayerId < retroVars.layersToCalculate.size(); curLayerId++)
{
// set current processed layer number // set current processed layer number
layerNumber = retroVars.layersToCalculate[curLayerId]; layerNumber = retroVars.layersToCalculate[curLayerId];
PRINT(0, this, " *** Calculate number of succeding states for each state of layer " << layerNumber << " ***"); PRINT(0, this, " *** Calculate number of succeding states for each state of layer " << layerNumber << " ***");
// process layer ... // process layer ...
if (!succCalculated[layerNumber]) { if (!succCalculated[layerNumber])
{
// prepare parameters for multithreading // prepare parameters for multithreading
succCalculated[layerNumber] = true; succCalculated[layerNumber] = true;
@ -363,7 +419,8 @@ bool MiniMax::calcNumSuccedors(retroAnalysisGlobalVars &retroVars)
ThreadManager::ThreadVarsArray<AddNumSuccedorsVars> tva(threadManager.getNumThreads(), AddNumSuccedorsVars(this, &retroVars, layerNumber)); ThreadManager::ThreadVarsArray<AddNumSuccedorsVars> tva(threadManager.getNumThreads(), AddNumSuccedorsVars(this, &retroVars, layerNumber));
// process each state in the current layer // 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: case TM_RETURN_VALUE_OK:
break; break;
case TM_RETURN_VALUE_EXECUTION_CANCELLED: case TM_RETURN_VALUE_EXECUTION_CANCELLED:
@ -377,25 +434,32 @@ bool MiniMax::calcNumSuccedors(retroAnalysisGlobalVars &retroVars)
// reduce and delete thread specific data // reduce and delete thread specific data
tva.reduce(); tva.reduce();
if (numStatesProcessed < layerStats[layerNumber].knotsInLayer) return falseOrStop(); if (numStatesProcessed < layerStats[layerNumber].knotsInLayer)
return falseOrStop();
// don't calc layers twice // don't calc layers twice
} else { }
else
{
return falseOrStop(); return falseOrStop();
} }
// ... and process succeding layers // ... 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 // get current pred. layer
succState.layerNumber = layerStats[layerNumber].succLayers[curState.layerNumber]; succState.layerNumber = layerStats[layerNumber].succLayers[curState.layerNumber];
// don't add layers twice // don't add layers twice
if (succCalculated[succState.layerNumber]) continue; if (succCalculated[succState.layerNumber])
else succCalculated[succState.layerNumber] = true; continue;
else
succCalculated[succState.layerNumber] = true;
// don't process layers without states // don't process layers without states
if (!layerStats[succState.layerNumber].knotsInLayer) continue; if (!layerStats[succState.layerNumber].knotsInLayer)
continue;
// check all states of pred. layer // check all states of pred. layer
PRINT(2, this, " - Do the same for the succeding layer " << (int)succState.layerNumber); PRINT(2, this, " - Do the same for the succeding layer " << (int)succState.layerNumber);
@ -405,7 +469,8 @@ bool MiniMax::calcNumSuccedors(retroAnalysisGlobalVars &retroVars)
ThreadManager::ThreadVarsArray<AddNumSuccedorsVars> tva(threadManager.getNumThreads(), AddNumSuccedorsVars(this, &retroVars, succState.layerNumber)); ThreadManager::ThreadVarsArray<AddNumSuccedorsVars> tva(threadManager.getNumThreads(), AddNumSuccedorsVars(this, &retroVars, succState.layerNumber));
// process each state in the current layer // 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: case TM_RETURN_VALUE_OK:
break; break;
case TM_RETURN_VALUE_EXECUTION_CANCELLED: case TM_RETURN_VALUE_EXECUTION_CANCELLED:
@ -419,7 +484,8 @@ bool MiniMax::calcNumSuccedors(retroAnalysisGlobalVars &retroVars)
// reduce and delete thread specific data // reduce and delete thread specific data
tva.reduce(); 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() // Name: addNumSuccedorsThreadProc()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
DWORD MiniMax::addNumSuccedorsThreadProc(void *pParameter, int index) DWORD MiniMax::addNumSuccedorsThreadProc(void *pParameter, int index)
{ {
// locals // locals
AddNumSuccedorsVars *ansVars = (AddNumSuccedorsVars *)pParameter; AddNumSuccedorsVars *ansVars = (AddNumSuccedorsVars *)pParameter;
MiniMax *m = ansVars->pMiniMax; MiniMax *m = ansVars->pMiniMax;
unsigned int numLayersToCalculate = (unsigned int)ansVars->retroVars->layersToCalculate.size(); unsigned int numLayersToCalculate = (unsigned int)ansVars->retroVars->layersToCalculate.size();
unsigned int curLayerId; // current processed layer within 'layersToCalculate' unsigned int curLayerId; // current processed layer within 'layersToCalculate'
unsigned int amountOfPred; unsigned int amountOfPred;
unsigned int curPred; unsigned int curPred;
CountArrayVarType countValue; CountArrayVarType countValue;
StateAdress predState; StateAdress predState;
StateAdress curState; StateAdress curState;
TwoBit curStateValue; TwoBit curStateValue;
PlyInfoVarType numPlies; // number of plies of the current considered succeding state PlyInfoVarType numPlies; // number of plies of the current considered succeding state
bool cuStateAddedToProcessQueue = false; bool cuStateAddedToProcessQueue = false;
curState.layerNumber = ansVars->layerNumber; curState.layerNumber = ansVars->layerNumber;
curState.stateNumber = (StateNumberVarType)index; curState.stateNumber = (StateNumberVarType)index;
// print status // print status
ansVars->statesProcessed++; ansVars->statesProcessed++;
if (ansVars->statesProcessed % OUTPUT_EVERY_N_STATES == 0) { if (ansVars->statesProcessed % OUTPUT_EVERY_N_STATES == 0)
{
m->numStatesProcessed += OUTPUT_EVERY_N_STATES; m->numStatesProcessed += OUTPUT_EVERY_N_STATES;
PRINT(2, m, " Already processed " << m->numStatesProcessed << " of " << m->layerStats[curState.layerNumber].knotsInLayer << " states"); PRINT(2, m, " Already processed " << m->numStatesProcessed << " of " << m->layerStats[curState.layerNumber].knotsInLayer << " states");
} }
// invalid state ? // invalid state ?
m->readKnotValueFromDatabase(curState.layerNumber, curState.stateNumber, curStateValue); 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 // 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!"); PRINT(0, m, "ERROR: setSituation() returned false!");
return TM_RETURN_VALUE_TERMINATE_ALL_THREADS; 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); m->getPredecessors(ansVars->curThreadNo, &amountOfPred, ansVars->predVars);
// iteration // iteration
for (curPred = 0; curPred < amountOfPred; curPred++) { for (curPred = 0; curPred < amountOfPred; curPred++)
{
// current predecessor // current predecessor
predState.layerNumber = ansVars->predVars[curPred].predLayerNumbers; predState.layerNumber = ansVars->predVars[curPred].predLayerNumbers;
predState.stateNumber = ansVars->predVars[curPred].predStateNumbers; predState.stateNumber = ansVars->predVars[curPred].predStateNumbers;
// don't calculate states from layers above yet // don't calculate states from layers above yet
for (curLayerId = 0; curLayerId < numLayersToCalculate; curLayerId++) { for (curLayerId = 0; curLayerId < numLayersToCalculate; curLayerId++)
if (ansVars->retroVars->layersToCalculate[curLayerId] == predState.layerNumber) break; {
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 // 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->readPlyInfoFromDatabase(curState.layerNumber, curState.stateNumber, numPlies);
m->addStateToProcessQueue(*ansVars->retroVars, ansVars->retroVars->thread[ansVars->curThreadNo], numPlies, &curState); m->addStateToProcessQueue(*ansVars->retroVars, ansVars->retroVars->thread[ansVars->curThreadNo], numPlies, &curState);
cuStateAddedToProcessQueue = true; cuStateAddedToProcessQueue = true;
@ -492,17 +566,21 @@ DWORD MiniMax::addNumSuccedorsThreadProc(void *pParameter, int index)
// add this state as possible move // add this state as possible move
long *pCountValue = ((long *)ansVars->retroVars->countArrays[curLayerId]) + predState.stateNumber / (sizeof(long) / sizeof(CountArrayVarType)); 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 numBitsToShift = sizeof(CountArrayVarType) * 8 * (predState.stateNumber % (sizeof(long) / sizeof(CountArrayVarType))); // little-endian byte-order
long mask = 0x000000ff << numBitsToShift; long mask = 0x000000ff << numBitsToShift;
long curCountLong, newCountLong; long curCountLong, newCountLong;
do { do
{
curCountLong = *pCountValue; curCountLong = *pCountValue;
countValue = (CountArrayVarType)((curCountLong & mask) >> numBitsToShift); countValue = (CountArrayVarType)((curCountLong & mask) >> numBitsToShift);
if (countValue == 255) { if (countValue == 255)
{
PRINT(0, m, "ERROR: maximum value for Count[] reached!"); PRINT(0, m, "ERROR: maximum value for Count[] reached!");
return TM_RETURN_VALUE_TERMINATE_ALL_THREADS; return TM_RETURN_VALUE_TERMINATE_ALL_THREADS;
} else { }
else
{
countValue++; countValue++;
newCountLong = (curCountLong & (~mask)) + (countValue << numBitsToShift); newCountLong = (curCountLong & (~mask)) + (countValue << numBitsToShift);
} }
@ -515,21 +593,22 @@ DWORD MiniMax::addNumSuccedorsThreadProc(void *pParameter, int index)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: performRetroAnalysis() // Name: performRetroAnalysis()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
bool MiniMax::performRetroAnalysis(retroAnalysisGlobalVars &retroVars) bool MiniMax::performRetroAnalysis(retroAnalysisGlobalVars &retroVars)
{ {
// locals // locals
StateAdress curState; // current state counter for loops StateAdress curState; // current state counter for loops
TwoBit curStateValue; // current state value TwoBit curStateValue; // current state value
unsigned int curLayerId; // current processed layer within 'layersToCalculate' unsigned int curLayerId; // current processed layer within 'layersToCalculate'
PRINT(2, this, " *** Begin Iteration ***"); PRINT(2, this, " *** Begin Iteration ***");
numStatesProcessed = 0; numStatesProcessed = 0;
curCalculationActionId = MM_ACTION_PERFORM_RETRO_ANAL; curCalculationActionId = MM_ACTION_PERFORM_RETRO_ANAL;
// process each state in the current layer // 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: case TM_RETURN_VALUE_OK:
break; break;
case TM_RETURN_VALUE_EXECUTION_CANCELLED: 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 // if there are still states to process, than something went wrong
for (unsigned int curThreadNo = 0; curThreadNo < threadManager.getNumThreads(); curThreadNo++) { for (unsigned int curThreadNo = 0; curThreadNo < threadManager.getNumThreads(); curThreadNo++)
if (retroVars.thread[curThreadNo].numStatesToProcess) { {
if (retroVars.thread[curThreadNo].numStatesToProcess)
{
PRINT(0, this, "ERROR: There are still states to process after performing retro analysis!"); PRINT(0, this, "ERROR: There are still states to process after performing retro analysis!");
return falseOrStop(); return falseOrStop();
} }
@ -551,11 +632,15 @@ bool MiniMax::performRetroAnalysis(retroAnalysisGlobalVars &retroVars)
// copy drawn and invalid states to ply info // copy drawn and invalid states to ply info
PRINT(2, this, " Copy drawn and invalid states to ply info database..."); PRINT(2, this, " Copy drawn and invalid states to ply info database...");
for (curLayerId = 0; curLayerId < retroVars.layersToCalculate.size(); curLayerId++) { 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 (curState.layerNumber = retroVars.layersToCalculate[curLayerId], curState.stateNumber = 0; curState.stateNumber < layerStats[curState.layerNumber].knotsInLayer; curState.stateNumber++)
{
readKnotValueFromDatabase(curState.layerNumber, curState.stateNumber, curStateValue); readKnotValueFromDatabase(curState.layerNumber, curState.stateNumber, curStateValue);
if (curStateValue == SKV_VALUE_GAME_DRAWN) savePlyInfoInDatabase(curState.layerNumber, curState.stateNumber, PLYINFO_VALUE_DRAWN); if (curStateValue == SKV_VALUE_GAME_DRAWN)
if (curStateValue == SKV_VALUE_INVALID) savePlyInfoInDatabase(curState.layerNumber, curState.stateNumber, PLYINFO_VALUE_INVALID); 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! ***"); PRINT(1, this, " *** Iteration finished! ***");
@ -566,48 +651,54 @@ bool MiniMax::performRetroAnalysis(retroAnalysisGlobalVars &retroVars)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: performRetroAnalysisThreadProc() // Name: performRetroAnalysisThreadProc()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
DWORD MiniMax::performRetroAnalysisThreadProc(void *pParameter) DWORD MiniMax::performRetroAnalysisThreadProc(void *pParameter)
{ {
// locals // locals
retroAnalysisGlobalVars *retroVars = (retroAnalysisGlobalVars *)pParameter; retroAnalysisGlobalVars *retroVars = (retroAnalysisGlobalVars *)pParameter;
MiniMax *m = retroVars->pMiniMax; MiniMax *m = retroVars->pMiniMax;
unsigned int threadNo = m->threadManager.getThreadNumber(); unsigned int threadNo = m->threadManager.getThreadNumber();
RetroAnalysisThreadVars *threadVars = &retroVars->thread[threadNo]; RetroAnalysisThreadVars *threadVars = &retroVars->thread[threadNo];
TwoBit predStateValue; TwoBit predStateValue;
unsigned int curLayerId; // current processed layer within 'layersToCalculate' unsigned int curLayerId; // current processed layer within 'layersToCalculate'
unsigned int amountOfPred; // total numbers of predecessors and current considered one unsigned int amountOfPred; // total numbers of predecessors and current considered one
unsigned int curPred; unsigned int curPred;
unsigned int threadCounter; unsigned int threadCounter;
long long numStatesProcessed; long long numStatesProcessed;
long long totalNumStatesToProcess; long long totalNumStatesToProcess;
PlyInfoVarType curNumPlies; PlyInfoVarType curNumPlies;
PlyInfoVarType numPliesTillCurState; PlyInfoVarType numPliesTillCurState;
PlyInfoVarType numPliesTillPredState; PlyInfoVarType numPliesTillPredState;
CountArrayVarType countValue; CountArrayVarType countValue;
StateAdress predState; StateAdress predState;
StateAdress curState; // current state counter for while-loop StateAdress curState; // current state counter for while-loop
TwoBit curStateValue; // current state value TwoBit curStateValue; // current state value
RetroAnalysisPredVars predVars[MAX_NUM_PREDECESSORS]; 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 // 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()); 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); 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? // 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"); PRINT(0, m, "\n****************************************\nSub-thread no. " << threadNo << ": Execution cancelled by user!\n****************************************\n");
return TM_RETURN_VALUE_EXECUTION_CANCELLED; return TM_RETURN_VALUE_EXECUTION_CANCELLED;
} }
@ -616,7 +707,8 @@ DWORD MiniMax::performRetroAnalysisThreadProc(void *pParameter)
m->readKnotValueFromDatabase(curState.layerNumber, curState.stateNumber, curStateValue); m->readKnotValueFromDatabase(curState.layerNumber, curState.stateNumber, curStateValue);
m->readPlyInfoFromDatabase(curState.layerNumber, curState.stateNumber, numPliesTillCurState); m->readPlyInfoFromDatabase(curState.layerNumber, curState.stateNumber, numPliesTillCurState);
if (numPliesTillCurState != curNumPlies) { if (numPliesTillCurState != curNumPlies)
{
PRINT(0, m, "ERROR: numPliesTillCurState != curNumPlies"); PRINT(0, m, "ERROR: numPliesTillCurState != curNumPlies");
return TM_RETURN_VALUE_TERMINATE_ALL_THREADS; return TM_RETURN_VALUE_TERMINATE_ALL_THREADS;
} }
@ -624,16 +716,19 @@ DWORD MiniMax::performRetroAnalysisThreadProc(void *pParameter)
// console output // console output
numStatesProcessed++; numStatesProcessed++;
threadVars->numStatesToProcess--; threadVars->numStatesToProcess--;
if (numStatesProcessed % OUTPUT_EVERY_N_STATES == 0) { if (numStatesProcessed % OUTPUT_EVERY_N_STATES == 0)
{
m->numStatesProcessed += OUTPUT_EVERY_N_STATES; 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; totalNumStatesToProcess += retroVars->thread[threadCounter].numStatesToProcess;
} }
PRINT(2, m, " states already processed: " << m->numStatesProcessed << " \t states still in list: " << totalNumStatesToProcess); PRINT(2, m, " states already processed: " << m->numStatesProcessed << " \t states still in list: " << totalNumStatesToProcess);
} }
// set current selected situation // 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!"); PRINT(0, m, "ERROR: setSituation() returned false!");
return TM_RETURN_VALUE_TERMINATE_ALL_THREADS; return TM_RETURN_VALUE_TERMINATE_ALL_THREADS;
} }
@ -642,48 +737,61 @@ DWORD MiniMax::performRetroAnalysisThreadProc(void *pParameter)
m->getPredecessors(threadNo, &amountOfPred, predVars); m->getPredecessors(threadNo, &amountOfPred, predVars);
// iteration // iteration
for (curPred = 0; curPred < amountOfPred; curPred++) { for (curPred = 0; curPred < amountOfPred; curPred++)
{
// current predecessor // current predecessor
predState.layerNumber = predVars[curPred].predLayerNumbers; predState.layerNumber = predVars[curPred].predLayerNumbers;
predState.stateNumber = predVars[curPred].predStateNumbers; predState.stateNumber = predVars[curPred].predStateNumbers;
// don't calculate states from layers above yet // don't calculate states from layers above yet
for (curLayerId = 0; curLayerId < retroVars->layersToCalculate.size(); curLayerId++) { for (curLayerId = 0; curLayerId < retroVars->layersToCalculate.size(); curLayerId++)
if (retroVars->layersToCalculate[curLayerId] == predState.layerNumber) break; {
if (retroVars->layersToCalculate[curLayerId] == predState.layerNumber)
break;
} }
if (curLayerId == retroVars->layersToCalculate.size()) continue; if (curLayerId == retroVars->layersToCalculate.size())
continue;
// get value of predecessor // get value of predecessor
m->readKnotValueFromDatabase(predState.layerNumber, predState.stateNumber, predStateValue); m->readKnotValueFromDatabase(predState.layerNumber, predState.stateNumber, predStateValue);
// only drawn states are relevant here, since the other are already calculated // 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 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->saveKnotValueInDatabase(predState.layerNumber, predState.stateNumber, SKV_VALUE_GAME_WON);
m->savePlyInfoInDatabase(predState.layerNumber, predState.stateNumber, numPliesTillCurState + 1); // (requirement: curNumPlies == numPliesTillCurState) m->savePlyInfoInDatabase(predState.layerNumber, predState.stateNumber, numPliesTillCurState + 1); // (requirement: curNumPlies == numPliesTillCurState)
if (numPliesTillCurState + 1 < curNumPlies) { if (numPliesTillCurState + 1 < curNumPlies)
{
PRINT(0, m, "ERROR: Current number of plies is bigger than numPliesTillCurState + 1!"); PRINT(0, m, "ERROR: Current number of plies is bigger than numPliesTillCurState + 1!");
return TM_RETURN_VALUE_TERMINATE_ALL_THREADS; return TM_RETURN_VALUE_TERMINATE_ALL_THREADS;
} }
m->addStateToProcessQueue(*retroVars, *threadVars, numPliesTillCurState + 1, &predState); 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 // 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 // reduce count value by one
long *pCountValue = ((long *)retroVars->countArrays[curLayerId]) + predState.stateNumber / (sizeof(long) / sizeof(CountArrayVarType)); 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 numBitsToShift = sizeof(CountArrayVarType) * 8 * (predState.stateNumber % (sizeof(long) / sizeof(CountArrayVarType))); // little-endian byte-order
long mask = 0x000000ff << numBitsToShift; long mask = 0x000000ff << numBitsToShift;
long curCountLong, newCountLong; long curCountLong, newCountLong;
do { do
{
curCountLong = *pCountValue; curCountLong = *pCountValue;
countValue = (CountArrayVarType)((curCountLong & mask) >> numBitsToShift); countValue = (CountArrayVarType)((curCountLong & mask) >> numBitsToShift);
if (countValue > 0) { if (countValue > 0)
{
countValue--; countValue--;
newCountLong = (curCountLong & (~mask)) + (countValue << numBitsToShift); newCountLong = (curCountLong & (~mask)) + (countValue << numBitsToShift);
} else { }
else
{
PRINT(0, m, "ERROR: Count is already zero!"); PRINT(0, m, "ERROR: Count is already zero!");
return TM_RETURN_VALUE_TERMINATE_ALL_THREADS; return TM_RETURN_VALUE_TERMINATE_ALL_THREADS;
} }
@ -691,14 +799,17 @@ DWORD MiniMax::performRetroAnalysisThreadProc(void *pParameter)
// ply info (requirement: curNumPlies == numPliesTillCurState) // ply info (requirement: curNumPlies == numPliesTillCurState)
m->readPlyInfoFromDatabase(predState.layerNumber, predState.stateNumber, numPliesTillPredState); 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); 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) // 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); 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!"); PRINT(0, m, "ERROR: Current number of plies is bigger than numPliesTillCurState + 1!");
return TM_RETURN_VALUE_TERMINATE_ALL_THREADS; return TM_RETURN_VALUE_TERMINATE_ALL_THREADS;
} }
@ -720,20 +831,22 @@ DWORD MiniMax::performRetroAnalysisThreadProc(void *pParameter)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: addStateToProcessQueue() // Name: addStateToProcessQueue()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
bool MiniMax::addStateToProcessQueue(retroAnalysisGlobalVars &retroVars, RetroAnalysisThreadVars &threadVars, unsigned int plyNumber, StateAdress *pState) bool MiniMax::addStateToProcessQueue(retroAnalysisGlobalVars &retroVars, RetroAnalysisThreadVars &threadVars, unsigned int plyNumber, StateAdress *pState)
{ {
// resize vector if too small // 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); threadVars.statesToProcess.resize(max(plyNumber + 1, 10 * threadVars.statesToProcess.size()), nullptr);
PRINT(4, this, " statesToProcess resized to " << threadVars.statesToProcess.size()); PRINT(4, this, " statesToProcess resized to " << threadVars.statesToProcess.size());
} }
// initialize cyclic array if necessary // initialize cyclic array if necessary
if (threadVars.statesToProcess[plyNumber] == nullptr) { if (threadVars.statesToProcess[plyNumber] == nullptr)
stringstream ssStatesToProcessFilePath; {
stringstream ssStatesToProcessPath; stringstream ssStatesToProcessFilePath;
stringstream ssStatesToProcessPath;
ssStatesToProcessPath << fileDirectory << (fileDirectory.size() ? "\\" : "") << "statesToProcess"; ssStatesToProcessPath << fileDirectory << (fileDirectory.size() ? "\\" : "") << "statesToProcess";
CreateDirectoryA(ssStatesToProcessPath.str().c_str(), nullptr); CreateDirectoryA(ssStatesToProcessPath.str().c_str(), nullptr);
ssStatesToProcessFilePath.str(""); ssStatesToProcessFilePath.str("");
@ -743,7 +856,8 @@ bool MiniMax::addStateToProcessQueue(retroAnalysisGlobalVars &retroVars, RetroAn
} }
// add state // 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); PRINT(0, this, "ERROR: Cyclic list to small! numStatesToProcess:" << threadVars.numStatesToProcess);
return falseOrStop(); return falseOrStop();
} }

View File

@ -8,64 +8,64 @@
struct RetroAnalysisQueueState struct RetroAnalysisQueueState
{ {
StateNumberVarType stateNumber; // state stored in the retro analysis queue. the queue is a buffer containing states to be passed to 'RetroAnalysisThreadVars::statesToProcess' 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 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<CyclicArray *> 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<CyclicArray *> 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<vector<RetroAnalysisQueueState>> 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. vector<vector<RetroAnalysisQueueState>> 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 long long numStatesToProcess; // Number of states in 'statesToProcess' which have to be processed
unsigned int threadNo; unsigned int threadNo;
}; };
struct RetroAnalysisVars // constant during calculation struct RetroAnalysisVars // constant during calculation
{ {
vector<CountArrayVarType *> countArrays; // One count array for each layer in 'layersToCalculate'. (For the nine men's morris game two layers have to considered at once.) vector<CountArrayVarType *> countArrays; // One count array for each layer in 'layersToCalculate'. (For the nine men's morris game two layers have to considered at once.)
vector<compressorClass::compressedArrayClass *> countArraysCompr; // '' but compressed vector<compressorClass::compressedArrayClass *> countArraysCompr; // '' but compressed
vector<bool> layerInitialized; // vector<bool> layerInitialized; //
vector<unsigned int> layersToCalculate; // layers which shall be calculated vector<unsigned int> layersToCalculate; // layers which shall be calculated
long long totalNumKnots; // total numbers of knots which have to be stored in memory 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 long long numKnotsToCalc; // number of knots of all layers to be calculated
vector<RetroAnalysisThreadVars> thread; vector<RetroAnalysisThreadVars> thread;
}; };
struct InitRetroAnalysisVars struct InitRetroAnalysisVars
{ {
MiniMax *pMiniMax; MiniMax *pMiniMax;
unsigned int curThreadNo; unsigned int curThreadNo;
unsigned int layerNumber; unsigned int layerNumber;
LONGLONG statesProcessed; LONGLONG statesProcessed;
unsigned int statsValueCounter[SKV_NUM_VALUES]; unsigned int statsValueCounter[SKV_NUM_VALUES];
BufferedFile *bufferedFile; BufferedFile *bufferedFile;
RetroAnalysisVars *retroVars; 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 struct addSuccLayersVars
{ {
MiniMax *pMiniMax; MiniMax *pMiniMax;
unsigned int curThreadNo; unsigned int curThreadNo;
unsigned int statsValueCounter[SKV_NUM_VALUES]; unsigned int statsValueCounter[SKV_NUM_VALUES];
unsigned int layerNumber; unsigned int layerNumber;
RetroAnalysisVars *retroVars; RetroAnalysisVars *retroVars;
}; };
struct RetroAnalysisPredVars struct RetroAnalysisPredVars
{ {
unsigned int predStateNumbers; unsigned int predStateNumbers;
unsigned int predLayerNumbers; unsigned int predLayerNumbers;
unsigned int predSymOperation; unsigned int predSymOperation;
bool playerToMoveChanged; bool playerToMoveChanged;
}; };
struct AddNumSuccedorsVars struct AddNumSuccedorsVars
{ {
MiniMax *pMiniMax; MiniMax *pMiniMax;
unsigned int curThreadNo; unsigned int curThreadNo;
unsigned int layerNumber; unsigned int layerNumber;
LONGLONG statesProcessed; LONGLONG statesProcessed;
RetroAnalysisVars *retroVars; RetroAnalysisVars *retroVars;
RetroAnalysisPredVars *predVars; RetroAnalysisPredVars *predVars;
}; };

View File

@ -10,16 +10,17 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: testLayer() // Name: testLayer()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
bool MiniMax::testLayer(unsigned int layerNumber) bool MiniMax::testLayer(unsigned int layerNumber)
{ {
// Locals // Locals
unsigned int curThreadNo; unsigned int curThreadNo;
unsigned int returnValue; unsigned int returnValue;
// database open? // database open?
if (hFileShortKnotValues == nullptr || hFilePlyInfo == nullptr) { if (hFileShortKnotValues == nullptr || hFilePlyInfo == nullptr)
{
PRINT(0, this, "ERROR: Database file not open!"); PRINT(0, this, "ERROR: Database file not open!");
return falseOrStop(); return falseOrStop();
} }
@ -35,7 +36,8 @@ bool MiniMax::testLayer(unsigned int layerNumber)
curCalculatedLayer = layerNumber; curCalculatedLayer = layerNumber;
curCalculationActionId = MM_ACTION_TESTING_LAYER; curCalculationActionId = MM_ACTION_TESTING_LAYER;
TestLayersVars *tlVars = new TestLayersVars[threadManager.getNumThreads()]; 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].curThreadNo = curThreadNo;
tlVars[curThreadNo].pMiniMax = this; tlVars[curThreadNo].pMiniMax = this;
tlVars[curThreadNo].layerNumber = layerNumber; tlVars[curThreadNo].layerNumber = layerNumber;
@ -47,21 +49,26 @@ bool MiniMax::testLayer(unsigned int layerNumber)
// process each state in the current layer // process each state in the current layer
returnValue = threadManager.executeParallelLoop(testLayerThreadProc, (void *)tlVars, sizeof(TestLayersVars), TM_SCHEDULE_STATIC, 0, layerStats[layerNumber].knotsInLayer - 1, 1); 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_OK:
case TM_RETURN_VALUE_EXECUTION_CANCELLED: case TM_RETURN_VALUE_EXECUTION_CANCELLED:
// reduce and delete thread specific data // 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; numStatesProcessed += tlVars[curThreadNo].statesProcessed;
SAFE_DELETE_ARRAY(tlVars[curThreadNo].subValueInDatabase); SAFE_DELETE_ARRAY(tlVars[curThreadNo].subValueInDatabase);
SAFE_DELETE_ARRAY(tlVars[curThreadNo].hasCurPlayerChanged); SAFE_DELETE_ARRAY(tlVars[curThreadNo].hasCurPlayerChanged);
SAFE_DELETE_ARRAY(tlVars[curThreadNo].subPlyInfos); SAFE_DELETE_ARRAY(tlVars[curThreadNo].subPlyInfos);
} }
SAFE_DELETE_ARRAY(tlVars); 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"); PRINT(0, this, "Main thread: Execution cancelled by user");
return false; // ... better would be to return a cancel-specific value return false; // ... better would be to return a cancel-specific value
} else { }
else
{
break; break;
} }
default: default:
@ -71,49 +78,54 @@ bool MiniMax::testLayer(unsigned int layerNumber)
} }
// layer is not ok // layer is not ok
if (numStatesProcessed < layerStats[layerNumber].knotsInLayer) { if (numStatesProcessed < layerStats[layerNumber].knotsInLayer)
{
PRINT(0, this, "DATABASE ERROR IN LAYER " << layerNumber); PRINT(0, this, "DATABASE ERROR IN LAYER " << layerNumber);
return falseOrStop(); return falseOrStop();
// layer is ok // layer is ok
} else { }
PRINT(1, this, " TEST PASSED !" << endl << endl); else
{
PRINT(1, this, " TEST PASSED !" << endl
<< endl);
return true; return true;
} }
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: testLayerThreadProc() // Name: testLayerThreadProc()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
DWORD MiniMax::testLayerThreadProc(void *pParameter, int index) DWORD MiniMax::testLayerThreadProc(void *pParameter, int index)
{ {
// locals // locals
TestLayersVars *tlVars = (TestLayersVars *)pParameter; TestLayersVars *tlVars = (TestLayersVars *)pParameter;
MiniMax *m = tlVars->pMiniMax; MiniMax *m = tlVars->pMiniMax;
unsigned int layerNumber = tlVars->layerNumber; unsigned int layerNumber = tlVars->layerNumber;
unsigned int stateNumber = index; unsigned int stateNumber = index;
unsigned int threadNo = tlVars->curThreadNo; unsigned int threadNo = tlVars->curThreadNo;
TwoBit *subValueInDatabase = tlVars->subValueInDatabase; TwoBit *subValueInDatabase = tlVars->subValueInDatabase;
PlyInfoVarType *subPlyInfos = tlVars->subPlyInfos; PlyInfoVarType *subPlyInfos = tlVars->subPlyInfos;
bool *hasCurPlayerChanged = tlVars->hasCurPlayerChanged; bool *hasCurPlayerChanged = tlVars->hasCurPlayerChanged;
TwoBit shortValueInDatabase; TwoBit shortValueInDatabase;
PlyInfoVarType numPliesTillCurState; PlyInfoVarType numPliesTillCurState;
TwoBit shortValueInGame; TwoBit shortValueInGame;
float floatValueInGame; float floatValueInGame;
PlyInfoVarType min, max; PlyInfoVarType min, max;
unsigned int numPossibilities; unsigned int numPossibilities;
unsigned int i, j; unsigned int i, j;
unsigned int tmpStateNumber, tmpLayerNumber; unsigned int tmpStateNumber, tmpLayerNumber;
unsigned int *idPossibility; unsigned int *idPossibility;
void *pPossibilities; void *pPossibilities;
void *pBackup; void *pBackup;
bool isOpponentLevel; bool isOpponentLevel;
bool invalidLayerOrStateNumber; bool invalidLayerOrStateNumber;
bool layerInDatabaseAndCompleted; bool layerInDatabaseAndCompleted;
// output // output
tlVars->statesProcessed++; tlVars->statesProcessed++;
if (tlVars->statesProcessed % OUTPUT_EVERY_N_STATES == 0) { if (tlVars->statesProcessed % OUTPUT_EVERY_N_STATES == 0)
{
m->numStatesProcessed += OUTPUT_EVERY_N_STATES; m->numStatesProcessed += OUTPUT_EVERY_N_STATES;
PRINT(0, m, m->numStatesProcessed << " states of " << m->layerStats[layerNumber].knotsInLayer << " tested"); 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); m->readPlyInfoFromDatabase(layerNumber, stateNumber, numPliesTillCurState);
// prepare the situation // 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 // 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."); PRINT(0, m, "ERROR: DATABASE ERROR IN LAYER " << layerNumber << " AND STATE " << stateNumber << ": Could not set situation, but value is not invalid.");
goto errorInDatabase; goto errorInDatabase;
} else { }
else
{
return TM_RETURN_VALUE_OK; return TM_RETURN_VALUE_OK;
} }
} }
// debug information // debug information
if (m->verbosity > 5) { if (m->verbosity > 5)
{
PRINT(5, m, "layer: " << layerNumber << " state: " << stateNumber); PRINT(5, m, "layer: " << layerNumber << " state: " << stateNumber);
m->printBoard(threadNo, shortValueInDatabase); m->printBoard(threadNo, shortValueInDatabase);
} }
@ -145,23 +162,30 @@ DWORD MiniMax::testLayerThreadProc(void *pParameter, int index)
idPossibility = m->getPossibilities(threadNo, &numPossibilities, &isOpponentLevel, &pPossibilities); idPossibility = m->getPossibilities(threadNo, &numPossibilities, &isOpponentLevel, &pPossibilities);
// unable to move // unable to move
if (numPossibilities == 0) { if (numPossibilities == 0)
{
// get ingame value // get ingame value
m->getValueOfSituation(threadNo, floatValueInGame, shortValueInGame); m->getValueOfSituation(threadNo, floatValueInGame, shortValueInGame);
// compare database with game // compare database with game
if (shortValueInDatabase != shortValueInGame || numPliesTillCurState != 0) { 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; {
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) { 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; {
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 // check each possible move
for (i = 0; i < numPossibilities; i++) { for (i = 0; i < numPossibilities; i++)
{
// move // move
m->move(threadNo, idPossibility[i], isOpponentLevel, &pBackup, pPossibilities); 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); hasCurPlayerChanged[i] = (m->getOpponentLevel(threadNo) == true);
// debug information // debug information
if (m->verbosity > 5) { if (m->verbosity > 5)
{
PRINT(5, m, "layer: " << tmpLayerNumber << " state: " << tmpStateNumber << " value: " << (int)subValueInDatabase[i]); PRINT(5, m, "layer: " << tmpLayerNumber << " state: " << tmpStateNumber << " value: " << (int)subValueInDatabase[i]);
m->printBoard(threadNo, subValueInDatabase[i]); m->printBoard(threadNo, subValueInDatabase[i]);
} }
// if layer or state number is invalid then value of testes state must be invalid // if layer or state number is invalid then value of testes state must be invalid
if (invalidLayerOrStateNumber && shortValueInDatabase != SKV_VALUE_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; {
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. // 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; } // 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? // value possible?
switch (shortValueInDatabase) { switch (shortValueInDatabase)
{
case SKV_VALUE_GAME_LOST: case SKV_VALUE_GAME_LOST:
// all possible moves must be lost for the current player or won for the opponent // all possible moves must be lost for the current player or won for the opponent
for (i = 0; i < numPossibilities; i++) { for (i = 0; i < numPossibilities; i++)
if (subValueInDatabase[i] != ((hasCurPlayerChanged[i]) ? SKV_VALUE_GAME_WON : SKV_VALUE_GAME_LOST) && subValueInDatabase[i] != SKV_VALUE_INVALID) { {
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"); 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; goto errorInDatabase;
} }
} }
// not all options can be invalid // not all options can be invalid
for (j = 0, i = 0; i < numPossibilities; i++) { for (j = 0, i = 0; i < numPossibilities; i++)
if (subValueInDatabase[i] == SKV_VALUE_INVALID) { {
if (subValueInDatabase[i] == SKV_VALUE_INVALID)
{
j++; j++;
} }
} }
if (j == numPossibilities) { if (j == numPossibilities)
{
PRINT(0, m, "DATABASE ERROR IN LAYER " << layerNumber << " AND STATE " << stateNumber << ". Not all options can be invalid"); PRINT(0, m, "DATABASE ERROR IN LAYER " << layerNumber << " AND STATE " << stateNumber << ". Not all options can be invalid");
} }
// ply info must be max(subPlyInfos[]+1) // ply info must be max(subPlyInfos[]+1)
max = 0; max = 0;
for (i = 0; i < numPossibilities; i++) { for (i = 0; i < numPossibilities; i++)
if (subValueInDatabase[i] == ((hasCurPlayerChanged[i]) ? SKV_VALUE_GAME_WON : SKV_VALUE_GAME_LOST)) { {
if (subPlyInfos[i] + 1 > max) { if (subValueInDatabase[i] == ((hasCurPlayerChanged[i]) ? SKV_VALUE_GAME_WON : SKV_VALUE_GAME_LOST))
{
if (subPlyInfos[i] + 1 > max)
{
max = subPlyInfos[i] + 1; 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."); 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; 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."); PRINT(0, m, "DATABASE ERROR IN LAYER " << layerNumber << " AND STATE " << stateNumber << ": Number of needed plies is not maximal for LOST state.");
goto errorInDatabase; goto errorInDatabase;
} }
@ -230,29 +268,37 @@ DWORD MiniMax::testLayerThreadProc(void *pParameter, int index)
case SKV_VALUE_GAME_WON: case SKV_VALUE_GAME_WON:
// at least one possible move must be lost for the opponent or won for the current player // 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] == 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."); 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; goto errorInDatabase;
} }
// ply info must be min(subPlyInfos[]+1) // ply info must be min(subPlyInfos[]+1)
min = PLYINFO_VALUE_DRAWN; min = PLYINFO_VALUE_DRAWN;
for (i = 0; i < numPossibilities; i++) { for (i = 0; i < numPossibilities; i++)
if (subValueInDatabase[i] == ((hasCurPlayerChanged[i]) ? SKV_VALUE_GAME_LOST : SKV_VALUE_GAME_WON)) { {
if (subPlyInfos[i] + 1 < min) { if (subValueInDatabase[i] == ((hasCurPlayerChanged[i]) ? SKV_VALUE_GAME_LOST : SKV_VALUE_GAME_WON))
{
if (subPlyInfos[i] + 1 < min)
{
min = subPlyInfos[i] + 1; 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."); 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; 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."); PRINT(0, m, "DATABASE ERROR IN LAYER " << layerNumber << " AND STATE " << stateNumber << ": Number of needed plies is not minimal for WON state.");
goto errorInDatabase; goto errorInDatabase;
} }
@ -261,38 +307,50 @@ DWORD MiniMax::testLayerThreadProc(void *pParameter, int index)
case SKV_VALUE_GAME_DRAWN: case SKV_VALUE_GAME_DRAWN:
// all possible moves must be won for the opponent, lost for the current player or 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] == 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) if (subValueInDatabase[i] != ((hasCurPlayerChanged[i]) ? SKV_VALUE_GAME_WON : SKV_VALUE_GAME_LOST) && subValueInDatabase[i] != SKV_VALUE_GAME_DRAWN && subValueInDatabase[i] != SKV_VALUE_INVALID)
&& 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.");
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; 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 // at least one succeding state must be drawn
if (j == 0) { if (j == 0)
PRINT(0, m, "DATABASE ERROR IN LAYER " << layerNumber << " AND STATE " << stateNumber << ": At least one succeding state must be drawn."); goto errorInDatabase; {
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 // ply info must also be drawn
if (numPliesTillCurState != PLYINFO_VALUE_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; {
PRINT(0, m, "DATABASE ERROR IN LAYER " << layerNumber << " AND STATE " << stateNumber << ": Knot value is drawn but ply info is not!");
goto errorInDatabase;
} }
break; break;
case SKV_VALUE_INVALID: case SKV_VALUE_INVALID:
// if setSituation() returned true but state value is invalid, then all following states must be invalid // if setSituation() returned true but state value is invalid, then all following states must be invalid
for (i = 0; i < numPossibilities; i++) { for (i = 0; i < numPossibilities; i++)
if (subValueInDatabase[i] != SKV_VALUE_INVALID) break; {
if (subValueInDatabase[i] != SKV_VALUE_INVALID)
break;
} }
if (i != numPossibilities) { 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; {
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 // ply info must also be invalid
if (numPliesTillCurState != PLYINFO_VALUE_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; {
PRINT(0, m, "DATABASE ERROR IN LAYER " << layerNumber << " AND STATE " << stateNumber << ": Knot value is invalid but ply info is not!");
goto errorInDatabase;
} }
break; break;
} }
@ -306,13 +364,13 @@ errorInDatabase:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: testState() // Name: testState()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
bool MiniMax::testState(unsigned int layerNumber, unsigned int stateNumber) bool MiniMax::testState(unsigned int layerNumber, unsigned int stateNumber)
{ {
// locals // locals
TestLayersVars tlVars; TestLayersVars tlVars;
bool result; bool result;
// prepare parameters for multithreading // prepare parameters for multithreading
tlVars.curThreadNo = 0; tlVars.curThreadNo = 0;
@ -323,7 +381,8 @@ bool MiniMax::testState(unsigned int layerNumber, unsigned int stateNumber)
tlVars.subPlyInfos = new PlyInfoVarType[maxNumBranches]; tlVars.subPlyInfos = new PlyInfoVarType[maxNumBranches];
tlVars.hasCurPlayerChanged = new bool[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.subValueInDatabase;
delete[] tlVars.subPlyInfos; delete[] tlVars.subPlyInfos;
@ -334,13 +393,13 @@ bool MiniMax::testState(unsigned int layerNumber, unsigned int stateNumber)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: testSetSituationAndGetPoss() // Name: testSetSituationAndGetPoss()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
bool MiniMax::testSetSituationAndGetPoss(unsigned int layerNumber) bool MiniMax::testSetSituationAndGetPoss(unsigned int layerNumber)
{ {
// Locals // Locals
unsigned int curThreadNo; unsigned int curThreadNo;
unsigned int returnValue; unsigned int returnValue;
// output // output
PRINT(1, this, endl << "*** Test each state in layer: " << layerNumber << " ***"); PRINT(1, this, endl << "*** Test each state in layer: " << layerNumber << " ***");
@ -350,7 +409,8 @@ bool MiniMax::testSetSituationAndGetPoss(unsigned int layerNumber)
numStatesProcessed = 0; numStatesProcessed = 0;
curCalculationActionId = MM_ACTION_TESTING_LAYER; curCalculationActionId = MM_ACTION_TESTING_LAYER;
TestLayersVars *tlVars = new TestLayersVars[threadManager.getNumThreads()]; 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].curThreadNo = curThreadNo;
tlVars[curThreadNo].pMiniMax = this; tlVars[curThreadNo].pMiniMax = this;
tlVars[curThreadNo].layerNumber = layerNumber; tlVars[curThreadNo].layerNumber = layerNumber;
@ -362,21 +422,26 @@ bool MiniMax::testSetSituationAndGetPoss(unsigned int layerNumber)
// process each state in the current layer // process each state in the current layer
returnValue = threadManager.executeParallelLoop(testSetSituationThreadProc, (void *)tlVars, sizeof(TestLayersVars), TM_SCHEDULE_STATIC, 0, layerStats[layerNumber].knotsInLayer - 1, 1); 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_OK:
case TM_RETURN_VALUE_EXECUTION_CANCELLED: case TM_RETURN_VALUE_EXECUTION_CANCELLED:
// reduce and delete thread specific data // 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; numStatesProcessed += tlVars[curThreadNo].statesProcessed;
SAFE_DELETE_ARRAY(tlVars[curThreadNo].subValueInDatabase); SAFE_DELETE_ARRAY(tlVars[curThreadNo].subValueInDatabase);
SAFE_DELETE_ARRAY(tlVars[curThreadNo].hasCurPlayerChanged); SAFE_DELETE_ARRAY(tlVars[curThreadNo].hasCurPlayerChanged);
SAFE_DELETE_ARRAY(tlVars[curThreadNo].subPlyInfos); SAFE_DELETE_ARRAY(tlVars[curThreadNo].subPlyInfos);
} }
SAFE_DELETE_ARRAY(tlVars); 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"); PRINT(0, this, "Main thread: Execution cancelled by user");
return false; // ... better would be to return a cancel-specific value return false; // ... better would be to return a cancel-specific value
} else { }
else
{
break; break;
} }
default: default:
@ -386,19 +451,23 @@ bool MiniMax::testSetSituationAndGetPoss(unsigned int layerNumber)
} }
// layer is not ok // layer is not ok
if (numStatesProcessed < layerStats[layerNumber].knotsInLayer) { if (numStatesProcessed < layerStats[layerNumber].knotsInLayer)
{
PRINT(0, this, "DATABASE ERROR IN LAYER " << layerNumber); PRINT(0, this, "DATABASE ERROR IN LAYER " << layerNumber);
return falseOrStop(); return falseOrStop();
// layer is ok // layer is ok
} else { }
PRINT(1, this, " TEST PASSED !" << endl << endl); else
{
PRINT(1, this, " TEST PASSED !" << endl
<< endl);
return true; return true;
} }
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: testSetSituationThreadProc() // Name: testSetSituationThreadProc()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
DWORD MiniMax::testSetSituationThreadProc(void *pParameter, int index) DWORD MiniMax::testSetSituationThreadProc(void *pParameter, int index)
{ {
@ -408,26 +477,30 @@ DWORD MiniMax::testSetSituationThreadProc(void *pParameter, int index)
unsigned int *idPossibility; unsigned int *idPossibility;
void *pPossibilities; void *pPossibilities;
void *pBackup; void *pBackup;
unsigned int curPoss; unsigned int curPoss;
float floatValue; float floatValue;
StateAdress curState; StateAdress curState;
StateAdress subState; StateAdress subState;
Node knot; Node knot;
TwoBit shortKnotValue = SKV_VALUE_GAME_DRAWN; TwoBit shortKnotValue = SKV_VALUE_GAME_DRAWN;
curState.layerNumber = tlVars->layerNumber; curState.layerNumber = tlVars->layerNumber;
curState.stateNumber = index; curState.stateNumber = index;
// output // output
tlVars->statesProcessed++; tlVars->statesProcessed++;
if (tlVars->statesProcessed % OUTPUT_EVERY_N_STATES == 0) { if (tlVars->statesProcessed % OUTPUT_EVERY_N_STATES == 0)
{
m->numStatesProcessed += OUTPUT_EVERY_N_STATES; m->numStatesProcessed += OUTPUT_EVERY_N_STATES;
PRINT(0, m, m->numStatesProcessed << " states of " << m->layerStats[curState.layerNumber].knotsInLayer << " tested"); PRINT(0, m, m->numStatesProcessed << " states of " << m->layerStats[curState.layerNumber].knotsInLayer << " tested");
} }
// set state // 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); m->getValueOfSituation(tlVars->curThreadNo, floatValue, shortKnotValue);
} else { }
else
{
shortKnotValue = SKV_VALUE_INVALID; 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); idPossibility = m->getPossibilities(tlVars->curThreadNo, &knot.numPossibilities, &knot.isOpponentLevel, &pPossibilities);
// unable to move // unable to move
if (knot.numPossibilities == 0) { if (knot.numPossibilities == 0)
if (shortKnotValue == SKV_VALUE_GAME_DRAWN) { {
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."); PRINT(0, m, "ERROR: Layer " << curState.layerNumber << " and state " << curState.stateNumber << ". setSituation() returned true, although getPossibilities() yields no possible moves.");
return m->falseOrStop(); return m->falseOrStop();
} }
// moving is possible // 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."); 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(); return m->falseOrStop();
} }
// check each possibility // check each possibility
for (curPoss = 0; curPoss < knot.numPossibilities; curPoss++) { for (curPoss = 0; curPoss < knot.numPossibilities; curPoss++)
{
// move // move
m->move(tlVars->curThreadNo, idPossibility[curPoss], knot.isOpponentLevel, &pBackup, pPossibilities); 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); m->undo(tlVars->curThreadNo, idPossibility[curPoss], knot.isOpponentLevel, pBackup, pPossibilities);
// state reached by move() must not be invalid // 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); 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(); return m->falseOrStop();
} }
@ -473,36 +553,38 @@ DWORD MiniMax::testSetSituationThreadProc(void *pParameter, int index)
return TM_RETURN_VALUE_OK; return TM_RETURN_VALUE_OK;
//errorInDatabase: //errorInDatabase:
// terminate all threads // terminate all threads
return TM_RETURN_VALUE_TERMINATE_ALL_THREADS; return TM_RETURN_VALUE_TERMINATE_ALL_THREADS;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: testIfSymStatesHaveSameValue() // Name: testIfSymStatesHaveSameValue()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
bool MiniMax::testIfSymStatesHaveSameValue(unsigned int layerNumber) bool MiniMax::testIfSymStatesHaveSameValue(unsigned int layerNumber)
{ {
// Locals // Locals
unsigned int threadNo = 0; unsigned int threadNo = 0;
TwoBit shortValueInDatabase; TwoBit shortValueInDatabase;
TwoBit shortValueOfSymState; TwoBit shortValueOfSymState;
PlyInfoVarType numPliesTillCurState; PlyInfoVarType numPliesTillCurState;
PlyInfoVarType numPliesTillSymState; PlyInfoVarType numPliesTillSymState;
unsigned int stateNumber = 0; unsigned int stateNumber = 0;
unsigned int *symStateNumbers = nullptr; unsigned int *symStateNumbers = nullptr;
unsigned int numSymmetricStates; unsigned int numSymmetricStates;
unsigned int i; unsigned int i;
// database open? // database open?
if (hFileShortKnotValues == nullptr || hFilePlyInfo == nullptr) { if (hFileShortKnotValues == nullptr || hFilePlyInfo == nullptr)
{
PRINT(0, this, "ERROR: Database files not open!"); PRINT(0, this, "ERROR: Database files not open!");
layerNumber = 0; layerNumber = 0;
goto errorInDatabase; goto errorInDatabase;
} }
// layer completed ? // layer completed ?
if (!layerStats[layerNumber].layerIsCompletedAndInFile) { if (!layerStats[layerNumber].layerIsCompletedAndInFile)
{
PRINT(0, this, "ERROR: Layer not in file!"); PRINT(0, this, "ERROR: Layer not in file!");
layerNumber = 0; layerNumber = 0;
goto errorInDatabase; goto errorInDatabase;
@ -513,33 +595,40 @@ bool MiniMax::testIfSymStatesHaveSameValue(unsigned int layerNumber)
PRINT(1, this, (getOutputInformation(layerNumber))); PRINT(1, this, (getOutputInformation(layerNumber)));
skvfHeader.completed = false; skvfHeader.completed = false;
for (layerInDatabase = false, stateNumber = 0; stateNumber < layerStats[layerNumber].knotsInLayer; stateNumber++) { for (layerInDatabase = false, stateNumber = 0; stateNumber < layerStats[layerNumber].knotsInLayer; stateNumber++)
{
// output // 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 ? // situation already existend in database ?
readKnotValueFromDatabase(layerNumber, stateNumber, shortValueInDatabase); readKnotValueFromDatabase(layerNumber, stateNumber, shortValueInDatabase);
readPlyInfoFromDatabase(layerNumber, stateNumber, numPliesTillCurState); readPlyInfoFromDatabase(layerNumber, stateNumber, numPliesTillCurState);
// prepare the situation // 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 // 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; if (shortValueInDatabase != SKV_VALUE_INVALID || numPliesTillCurState != PLYINFO_VALUE_INVALID)
else continue; goto errorInDatabase;
else
continue;
} }
// get numbers of symmetric states // get numbers of symmetric states
getSymStateNumWithDoubles(threadNo, &numSymmetricStates, &symStateNumbers); getSymStateNumWithDoubles(threadNo, &numSymmetricStates, &symStateNumbers);
// save value for all symmetric states // save value for all symmetric states
for (i = 0; i < numSymmetricStates; i++) { for (i = 0; i < numSymmetricStates; i++)
{
readKnotValueFromDatabase(layerNumber, symStateNumbers[i], shortValueOfSymState); readKnotValueFromDatabase(layerNumber, symStateNumbers[i], shortValueOfSymState);
readPlyInfoFromDatabase(layerNumber, symStateNumbers[i], numPliesTillSymState); 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); PRINT(2, this, "current tested state " << stateNumber << " has value " << (int)shortValueInDatabase);
setSituation(threadNo, layerNumber, stateNumber); setSituation(threadNo, layerNumber, stateNumber);
@ -562,6 +651,7 @@ bool MiniMax::testIfSymStatesHaveSameValue(unsigned int layerNumber)
errorInDatabase: errorInDatabase:
// layer is not ok // 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(); return falseOrStop();
} }

File diff suppressed because it is too large Load Diff

View File

@ -18,151 +18,150 @@
//using namespace std; //using namespace std;
// values of states/situations // values of states/situations
#define VALUE_GAME_LOST -1000.0f #define VALUE_GAME_LOST -1000.0f
#define VALUE_GAME_WON 1000.0f #define VALUE_GAME_WON 1000.0f
// since a state must be saved two times, // since a state must be saved two times,
// one time where no stone must be removed, // one time where no stone must be removed,
// one time where a 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 // 10 x 10 since each color can range from 0 to 9 stones
// x2 since there is the setting phase and the moving phase // x2 since there is the setting phase and the moving phase
#define NUM_LAYERS 200 #define NUM_LAYERS 200
#define MAX_NUM_SUB_LAYERS 100 #define MAX_NUM_SUB_LAYERS 100
#define LAYER_INDEX_SETTING_PHASE 1 #define LAYER_INDEX_SETTING_PHASE 1
#define LAYER_INDEX_MOVING_PHASE 0 #define LAYER_INDEX_MOVING_PHASE 0
#define NOT_INDEXED 4294967295 #define NOT_INDEXED 4294967295
#define MAX_DEPTH_OF_TREE 100 #define MAX_DEPTH_OF_TREE 100
#define NUM_STONES_PER_PLAYER 9 #define NUM_STONES_PER_PLAYER 9
#define NUM_STONES_PER_PLAYER_PLUS_ONE 10 #define NUM_STONES_PER_PLAYER_PLUS_ONE 10
// The Four Groups (the board position is divided in four groups A,B,C,D) // The Four Groups (the board position is divided in four groups A,B,C,D)
#define numSquaresGroupA 4 #define numSquaresGroupA 4
#define numSquaresGroupB 4 #define numSquaresGroupB 4
#define numSquaresGroupC 8 #define numSquaresGroupC 8
#define numSquaresGroupD 8 #define numSquaresGroupD 8
#define GROUP_A 0 #define GROUP_A 0
#define GROUP_B 1 #define GROUP_B 1
#define GROUP_C 2 #define GROUP_C 2
#define GROUP_D 3 #define GROUP_D 3
#define MAX_ANZ_STELLUNGEN_A 81 #define MAX_ANZ_STELLUNGEN_A 81
#define MAX_ANZ_STELLUNGEN_B 81 #define MAX_ANZ_STELLUNGEN_B 81
#define MAX_ANZ_STELLUNGEN_C (81*81) #define MAX_ANZ_STELLUNGEN_C (81 * 81)
#define MAX_ANZ_STELLUNGEN_D (81*81) #define MAX_ANZ_STELLUNGEN_D (81 * 81)
#define FREE_SQUARE 0 #define FREE_SQUARE 0
#define WHITE_STONE 1 #define WHITE_STONE 1
#define BLACK_STONE 2 #define BLACK_STONE 2
// Symmetry Operations // Symmetry Operations
#define SO_TURN_LEFT 0 #define SO_TURN_LEFT 0
#define SO_TURN_180 1 #define SO_TURN_180 1
#define SO_TURN_RIGHT 2 #define SO_TURN_RIGHT 2
#define SO_DO_NOTHING 3 #define SO_DO_NOTHING 3
#define SO_INVERT 4 #define SO_INVERT 4
#define SO_MIRROR_VERT 5 #define SO_MIRROR_VERT 5
#define SO_MIRROR_HORI 6 #define SO_MIRROR_HORI 6
#define SO_MIRROR_DIAG_1 7 #define SO_MIRROR_DIAG_1 7
#define SO_MIRROR_DIAG_2 8 #define SO_MIRROR_DIAG_2 8
#define SO_INV_LEFT 9 #define SO_INV_LEFT 9
#define SO_INV_RIGHT 10 #define SO_INV_RIGHT 10
#define SO_INV_180 11 #define SO_INV_180 11
#define SO_INV_MIR_VERT 12 #define SO_INV_MIR_VERT 12
#define SO_INV_MIR_HORI 13 #define SO_INV_MIR_HORI 13
#define SO_INV_MIR_DIAG_1 14 #define SO_INV_MIR_DIAG_1 14
#define SO_INV_MIR_DIAG_2 15 #define SO_INV_MIR_DIAG_2 15
#define NUM_SYM_OPERATIONS 16 #define NUM_SYM_OPERATIONS 16
/*** Klassen *********************************************************/ /*** Klassen *********************************************************/
class PerfectAI : public MillAI, public MiniMax class PerfectAI : public MillAI, public MiniMax
{ {
protected: protected:
// structs // structs
struct SubLayer struct SubLayer
{ {
unsigned int minIndex; unsigned int minIndex;
unsigned int maxIndex; unsigned int maxIndex;
unsigned int numWhiteStonesGroupCD, numBlackStonesGroupCD; unsigned int numWhiteStonesGroupCD, numBlackStonesGroupCD;
unsigned int numWhiteStonesGroupAB, numBlackStonesGroupAB; unsigned int numWhiteStonesGroupAB, numBlackStonesGroupAB;
}; };
struct Layer struct Layer
{ {
unsigned int numWhiteStones; unsigned int numWhiteStones;
unsigned int numBlackStones; unsigned int numBlackStones;
unsigned int numSubLayers; unsigned int numSubLayers;
unsigned int subLayerIndexAB[NUM_STONES_PER_PLAYER_PLUS_ONE][NUM_STONES_PER_PLAYER_PLUS_ONE]; 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]; unsigned int subLayerIndexCD[NUM_STONES_PER_PLAYER_PLUS_ONE][NUM_STONES_PER_PLAYER_PLUS_ONE];
SubLayer subLayer[MAX_NUM_SUB_LAYERS]; SubLayer subLayer[MAX_NUM_SUB_LAYERS];
}; };
struct Possibility struct Possibility
{ {
unsigned int from[MAX_NUM_POS_MOVES]; unsigned int from[MAX_NUM_POS_MOVES];
unsigned int to[MAX_NUM_POS_MOVES]; unsigned int to[MAX_NUM_POS_MOVES];
}; };
struct Backup struct Backup
{ {
float floatValue; float floatValue;
TwoBit shortValue; TwoBit shortValue;
bool gameHasFinished; bool gameHasFinished;
bool settingPhase; bool settingPhase;
int fieldFrom, fieldTo; // value of board int fieldFrom, fieldTo; // value of board
unsigned int from, to; // index of board unsigned int from, to; // index of board
unsigned int curNumStones, oppNumStones; unsigned int curNumStones, oppNumStones;
unsigned int curPosMoves, oppPosMoves; unsigned int curPosMoves, oppPosMoves;
unsigned int curMissStones, oppMissStones; unsigned int curMissStones, oppMissStones;
unsigned int stonesSet; unsigned int stonesSet;
unsigned int stoneMustBeRemoved; unsigned int stoneMustBeRemoved;
unsigned int stonePartOfMill[fieldStruct::size]; unsigned int stonePartOfMill[fieldStruct::size];
Player *curPlayer, *oppPlayer; Player *curPlayer, *oppPlayer;
}; };
// preCalcedVars.dat // preCalcedVars.dat
struct PreCalcedVarsFileHeader struct PreCalcedVarsFileHeader
{ {
unsigned int sizeInBytes; unsigned int sizeInBytes;
}; };
// constant variables for state addressing in the database // constant variables for state addressing in the database
Layer layer[NUM_LAYERS]; // the layers 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 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 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 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 indexAB[MAX_ANZ_STELLUNGEN_A * MAX_ANZ_STELLUNGEN_B];
unsigned int indexCD[MAX_ANZ_STELLUNGEN_C * MAX_ANZ_STELLUNGEN_D]; 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 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 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 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 *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 *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 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 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 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 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 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 incidencesValuesSubMoves[fieldStruct::size * fieldStruct::size][4]; // contains the number of ...
unsigned int symmetricStateNumberArray[NUM_SYM_OPERATIONS]; // array for state numbers unsigned int symmetricStateNumberArray[NUM_SYM_OPERATIONS]; // array for state numbers
string databaseDirectory; // directory containing the database files string databaseDirectory; // directory containing the database files
// Variables used individually by each single thread // Variables used individually by each single thread
class ThreadVars class ThreadVars
{ {
public: public:
fieldStruct *field; // pointer of the current board [changed by move()] fieldStruct *field; // pointer of the current board [changed by move()]
float floatValue; // value of current situation for board->currentPlayer float floatValue; // value of current situation for board->currentPlayer
TwoBit shortValue; // '' TwoBit shortValue; // ''
bool gameHasFinished; // someone has won or current board is full bool gameHasFinished; // someone has won or current board is full
int ownId; // id of the player who called the play()-function int ownId; // id of the player who called the play()-function
unsigned int curSearchDepth; // current level unsigned int curSearchDepth; // current level
unsigned int depthOfFullTree; // search depth where the whole tree is explored unsigned int depthOfFullTree; // search depth where the whole tree is explored
unsigned int *idPossibilities; // returned pointer of getPossibilities()-function unsigned int *idPossibilities; // returned pointer of getPossibilities()-function
Backup *oldStates; // for undo()-function Backup *oldStates; // for undo()-function
Possibility *possibilities; // for getPossNormalMove()-function Possibility *possibilities; // for getPossNormalMove()-function
PerfectAI *parent; // PerfectAI *parent; //
// constructor // constructor
ThreadVars(); ThreadVars();
@ -173,57 +172,57 @@ protected:
unsigned int *getPossStoneRemove(unsigned int *numPossibilities, void **pPossibilities); unsigned int *getPossStoneRemove(unsigned int *numPossibilities, void **pPossibilities);
// move functions // move functions
inline void updatePossibleMoves(unsigned int stone, Player *stoneOwner, bool stoneRemoved, unsigned int ignoreStone); inline void updatePossibleMoves(unsigned int stone, Player *stoneOwner, bool stoneRemoved, unsigned int ignoreStone);
inline void updateWarning(unsigned int firstStone, unsigned int secondStone); inline void updateWarning(unsigned int firstStone, unsigned int secondStone);
inline void setWarning(unsigned int stoneOne, unsigned int stoneTwo, unsigned int stoneThree); inline void setWarning(unsigned int stoneOne, unsigned int stoneTwo, unsigned int stoneThree);
inline void removeStone(unsigned int from, Backup *backup); inline void removeStone(unsigned int from, Backup *backup);
inline void setStone(unsigned int to, Backup *backup); inline void setStone(unsigned int to, Backup *backup);
inline void normalMove(unsigned int from, unsigned int to, Backup *backup); inline void normalMove(unsigned int from, unsigned int to, Backup *backup);
// database functions // database functions
unsigned int getLayerAndStateNumber(unsigned int &layerNum, unsigned int &stateNumber); unsigned int getLayerAndStateNumber(unsigned int &layerNum, unsigned int &stateNumber);
void setWarningAndMill(unsigned int stone, unsigned int firstNeighbour, unsigned int secondNeighbour); void setWarningAndMill(unsigned int stone, unsigned int firstNeighbour, unsigned int secondNeighbour);
bool fieldIntegrityOK(unsigned int numberOfMillsCurrentPlayer, unsigned int numberOfMillsOpponentPlayer, bool aStoneCanBeRemovedFromCurPlayer); bool fieldIntegrityOK(unsigned int numberOfMillsCurrentPlayer, unsigned int numberOfMillsOpponentPlayer, bool aStoneCanBeRemovedFromCurPlayer);
void calcPossibleMoves(Player *player); void calcPossibleMoves(Player *player);
void storePredecessor(unsigned int numberOfMillsCurrentPlayer, unsigned int numberOfMillsOpponentPlayer, unsigned int *amountOfPred, RetroAnalysisPredVars *predVars); void storePredecessor(unsigned int numberOfMillsCurrentPlayer, unsigned int numberOfMillsOpponentPlayer, unsigned int *amountOfPred, RetroAnalysisPredVars *predVars);
}; };
ThreadVars *threadVars; ThreadVars *threadVars;
// database functions // database functions
unsigned int getNumberOfLayers(); unsigned int getNumberOfLayers();
unsigned int getNumberOfKnotsInLayer(unsigned int layerNum); unsigned int getNumberOfKnotsInLayer(unsigned int layerNum);
long long mOverN_Function(unsigned int m, unsigned int n); long long mOverN_Function(unsigned int m, unsigned int n);
void applySymmetrieOperationOnField(unsigned char symmetryOperationNumber, unsigned int *sourceField, unsigned int *destField); void applySymmetrieOperationOnField(unsigned char symmetryOperationNumber, unsigned int *sourceField, unsigned int *destField);
bool isSymOperationInvariantOnGroupCD(unsigned int symmetryOperation, int *theField); bool isSymOperationInvariantOnGroupCD(unsigned int symmetryOperation, int *theField);
bool shallRetroAnalysisBeUsed(unsigned int layerNum); bool shallRetroAnalysisBeUsed(unsigned int layerNum);
void getSuccLayers(unsigned int layerNum, unsigned int *amountOfSuccLayers, unsigned int *succLayers); void getSuccLayers(unsigned int layerNum, unsigned int *amountOfSuccLayers, unsigned int *succLayers);
void getPredecessors(unsigned int threadNo, unsigned int *amountOfPred, RetroAnalysisPredVars *predVars); void getPredecessors(unsigned int threadNo, unsigned int *amountOfPred, RetroAnalysisPredVars *predVars);
bool setSituation(unsigned int threadNo, unsigned int layerNum, unsigned int stateNumber); bool setSituation(unsigned int threadNo, unsigned int layerNum, unsigned int stateNumber);
unsigned int getLayerNumber(unsigned int threadNo); unsigned int getLayerNumber(unsigned int threadNo);
unsigned int getLayerAndStateNumber(unsigned int threadNo, unsigned int &layerNum, unsigned int &stateNumber); unsigned int getLayerAndStateNumber(unsigned int threadNo, unsigned int &layerNum, unsigned int &stateNumber);
// integrity test functions // integrity test functions
bool checkMoveAndSetSituation(); bool checkMoveAndSetSituation();
bool checkGetPossThanGetPred(); bool checkGetPossThanGetPred();
bool checkGetPredThanGetPoss(); bool checkGetPredThanGetPoss();
// Virtual Functions // Virtual Functions
void prepareBestChoiceCalculation(); void prepareBestChoiceCalculation();
void getValueOfSituation(unsigned int threadNo, float &floatValue, TwoBit &shortValue); void getValueOfSituation(unsigned int threadNo, float &floatValue, TwoBit &shortValue);
void setOpponentLevel(unsigned int threadNo, bool isOpponentLevel); void setOpponentLevel(unsigned int threadNo, bool isOpponentLevel);
bool getOpponentLevel(unsigned int threadNo); bool getOpponentLevel(unsigned int threadNo);
void deletePossibilities(unsigned int threadNo, void *pPossibilities); void deletePossibilities(unsigned int threadNo, void *pPossibilities);
unsigned int *getPossibilities(unsigned int threadNo, unsigned int *numPossibilities, bool *opponentsMove, 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 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 move(unsigned int threadNo, unsigned int idPossibility, bool opponentsMove, void **pBackup, void *pPossibilities);
void printMoveInformation(unsigned int threadNo, unsigned int idPossibility, 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 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 getSymStateNumWithDoubles(unsigned int threadNo, unsigned int *numSymmetricStates, unsigned int **symStateNumbers);
void printBoard(unsigned int threadNo, unsigned char value); void printBoard(unsigned int threadNo, unsigned char value);
string getOutputInformation(unsigned int layerNum); string getOutputInformation(unsigned int layerNum);
unsigned int getPartnerLayer(unsigned int layerNum); unsigned int getPartnerLayer(unsigned int layerNum);
void prepareDatabaseCalculation(); void prepareDatabaseCalculation();
void wrapUpDatabaseCalculation(bool calculationAborted); void wrapUpDatabaseCalculation(bool calculationAborted);
public: public:
// Constructor / destructor // Constructor / destructor
@ -231,14 +230,14 @@ public:
~PerfectAI(); ~PerfectAI();
// Functions // Functions
bool setDatabasePath(const char *directory); bool setDatabasePath(const char *directory);
void play(fieldStruct *theField, unsigned int *pushFrom, unsigned int *pushTo); 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 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 getField(unsigned int layerNum, unsigned int stateNumber, fieldStruct *field, bool *gameHasFinished);
void getLayerAndStateNumber(unsigned int &layerNum, unsigned int &stateNumber); void getLayerAndStateNumber(unsigned int &layerNum, unsigned int &stateNumber);
// Testing functions // Testing functions
bool testLayers(unsigned int startTestFromLayer, unsigned int endTestAtLayer); bool testLayers(unsigned int startTestFromLayer, unsigned int endTestAtLayer);
}; };
#endif #endif

View File

@ -62,9 +62,12 @@ void Position::beginNewGame(MillAI *firstPlayerAI, MillAI *secondPlayerAI, int c
initialField.createBoard(); initialField.createBoard();
// calc beginning player // calc beginning player
if (currentPlayer == field.playerOne || currentPlayer == field.playerTwo) { if (currentPlayer == field.playerOne || currentPlayer == field.playerTwo)
{
beginningPlayer = currentPlayer; beginningPlayer = currentPlayer;
} else { }
else
{
beginningPlayer = (rand() % 2) ? field.playerOne : field.playerTwo; beginningPlayer = (rand() % 2) ? field.playerOne : field.playerTwo;
} }
field.curPlayer->id = beginningPlayer; field.curPlayer->id = beginningPlayer;
@ -83,7 +86,7 @@ void Position::beginNewGame(MillAI *firstPlayerAI, MillAI *secondPlayerAI, int c
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: startSettingPhase() // Name: startSettingPhase()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
bool Position::startSettingPhase(MillAI *firstPlayerAI, MillAI *secondPlayerAI, int currentPlayer, bool settingPhase) bool Position::startSettingPhase(MillAI *firstPlayerAI, MillAI *secondPlayerAI, int currentPlayer, bool settingPhase)
{ {
@ -103,8 +106,10 @@ void Position::setUpCalcPossibleMoves(Player *player)
// locals // locals
unsigned int i, j, k, movingDirection; unsigned int i, j, k, movingDirection;
for (player->numPossibleMoves = 0, i = 0; i < fieldStruct::size; i++) { for (player->numPossibleMoves = 0, i = 0; i < fieldStruct::size; i++)
for (j = 0; j < fieldStruct::size; j++) { {
for (j = 0; j < fieldStruct::size; j++)
{
// is stone from player ? // is stone from player ?
if (field.board[i] != player->id) if (field.board[i] != player->id)
@ -115,7 +120,8 @@ void Position::setUpCalcPossibleMoves(Player *player)
continue; continue;
// when current player has only 3 stones he is allowed to spring his stone // 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 // determine moving direction
for (k = 0, movingDirection = 4; k < 4; k++) for (k = 0, movingDirection = 4; k < 4; k++)
@ -135,7 +141,7 @@ void Position::setUpCalcPossibleMoves(Player *player)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: setUpSetWarningAndMill() // Name: setUpSetWarningAndMill()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void Position::setUpSetWarningAndMill(unsigned int stone, unsigned int firstNeighbour, unsigned int secondNeighbour) 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]; int rowOwner = field.board[stone];
// mill closed ? // 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[stone]++;
field.stonePartOfMill[firstNeighbour]++; 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; Player *myPlayer = (player == field.curPlayer->id) ? field.curPlayer : field.oppPlayer;
// check parameters // check parameters
if (player != fieldStruct::playerOne && player != fieldStruct::playerTwo) return false; if (player != fieldStruct::playerOne && player != fieldStruct::playerTwo)
if (pos >= fieldStruct::size) return false; return false;
if (field.board[pos] != field.squareIsFree) return false; if (pos >= fieldStruct::size)
return false;
if (field.board[pos] != field.squareIsFree)
return false;
// set stone // set stone
field.board[pos] = player; field.board[pos] = player;
@ -173,50 +183,63 @@ bool Position::put_piece(unsigned int pos, int player)
field.stonesSet++; field.stonesSet++;
// setting phase finished ? // setting phase finished ?
if (field.stonesSet == 18) field.settingPhase = false; if (field.stonesSet == 18)
field.settingPhase = false;
// calc possible moves // calc possible moves
setUpCalcPossibleMoves(field.curPlayer); setUpCalcPossibleMoves(field.curPlayer);
setUpCalcPossibleMoves(field.oppPlayer); setUpCalcPossibleMoves(field.oppPlayer);
// zero // 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 // 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][0][0], field.neighbour[i][0][1]);
setUpSetWarningAndMill(i, field.neighbour[i][1][0], field.neighbour[i][1][1]); setUpSetWarningAndMill(i, field.neighbour[i][1][0], field.neighbour[i][1][1]);
} }
// since every mill was detected 3 times // 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 // count completed mills
for (i = 0; i < fieldStruct::size; i++) { for (i = 0; i < fieldStruct::size; i++)
if (field.board[i] == field.curPlayer->id) numberOfMillsCurrentPlayer += field.stonePartOfMill[i]; {
else numberOfMillsOpponentPlayer += field.stonePartOfMill[i]; if (field.board[i] == field.curPlayer->id)
numberOfMillsCurrentPlayer += field.stonePartOfMill[i];
else
numberOfMillsOpponentPlayer += field.stonePartOfMill[i];
} }
numberOfMillsCurrentPlayer /= 3; numberOfMillsCurrentPlayer /= 3;
numberOfMillsOpponentPlayer /= 3; numberOfMillsOpponentPlayer /= 3;
// stonesSet & numStonesMissing // 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. // ... This calculation is not correct! It is possible that some mills did not cause a stone removal.
field.curPlayer->numStonesMissing = numberOfMillsOpponentPlayer; field.curPlayer->numStonesMissing = numberOfMillsOpponentPlayer;
field.oppPlayer->numStonesMissing = numberOfMillsCurrentPlayer - field.stoneMustBeRemoved; field.oppPlayer->numStonesMissing = numberOfMillsCurrentPlayer - field.stoneMustBeRemoved;
field.stonesSet = field.curPlayer->numStones + field.oppPlayer->numStones + field.curPlayer->numStonesMissing + field.oppPlayer->numStonesMissing; field.stonesSet = field.curPlayer->numStones + field.oppPlayer->numStones + field.curPlayer->numStonesMissing + field.oppPlayer->numStonesMissing;
} else { }
else
{
field.stonesSet = 18; field.stonesSet = 18;
field.curPlayer->numStonesMissing = 9 - field.curPlayer->numStones; field.curPlayer->numStonesMissing = 9 - field.curPlayer->numStones;
field.oppPlayer->numStonesMissing = 9 - field.oppPlayer->numStones; field.oppPlayer->numStonesMissing = 9 - field.oppPlayer->numStones;
} }
// when opponent is unable to move than current player has won // when opponent is unable to move than current player has won
if ((!field.curPlayer->numPossibleMoves) && (!field.settingPhase) if ((!field.curPlayer->numPossibleMoves) && (!field.settingPhase) && (!field.stoneMustBeRemoved) && (field.curPlayer->numStones > 3))
&& (!field.stoneMustBeRemoved) && (field.curPlayer->numStones > 3)) winner = field.oppPlayer->id; winner = field.oppPlayer->id;
else if ((field.curPlayer->numStones < 3) && (!field.settingPhase)) winner = field.oppPlayer->id; else if ((field.curPlayer->numStones < 3) && (!field.settingPhase))
else if ((field.oppPlayer->numStones < 3) && (!field.settingPhase)) winner = field.curPlayer->id; winner = field.oppPlayer->id;
else winner = 0; else if ((field.oppPlayer->numStones < 3) && (!field.settingPhase))
winner = field.curPlayer->id;
else
winner = 0;
// everything is ok // everything is ok
return true; return true;
@ -243,11 +266,15 @@ bool Position::getField(int *pField)
unsigned int index; unsigned int index;
// if no log is available than no game is in progress and board is invalid // 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++) { 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]; if (field.warnings[index] != field.noWarning)
pField[index] = (int)field.warnings[index];
else
pField[index] = field.board[index];
} }
return true; return true;
@ -263,7 +290,8 @@ void Position::getLog(unsigned int &numMovesDone, unsigned int *from, unsigned i
numMovesDone = movesDone; numMovesDone = movesDone;
for (index = 0; index < movesDone; index++) { for (index = 0; index < movesDone; index++)
{
from[index] = moveLogFrom[index]; from[index] = moveLogFrom[index];
to[index] = moveLogTo[index]; to[index] = moveLogTo[index];
} }
@ -288,8 +316,10 @@ void Position::setNextPlayer()
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
bool Position::isCurrentPlayerHuman() bool Position::isCurrentPlayerHuman()
{ {
if (field.curPlayer->id == field.playerOne) return (playerOneAI == nullptr) ? true : false; if (field.curPlayer->id == field.playerOne)
else return (playerTwoAI == nullptr) ? true : false; return (playerOneAI == nullptr) ? true : false;
else
return (playerTwoAI == nullptr) ? true : false;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -298,8 +328,10 @@ bool Position::isCurrentPlayerHuman()
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
bool Position::isOpponentPlayerHuman() bool Position::isOpponentPlayerHuman()
{ {
if (field.oppPlayer->id == field.playerOne) return (playerOneAI == nullptr) ? true : false; if (field.oppPlayer->id == field.playerOne)
else return (playerTwoAI == nullptr) ? true : false; 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) void Position::setAI(int player, MillAI *AI)
{ {
if (player == field.playerOne) { if (player == field.playerOne)
{
playerOneAI = AI; playerOneAI = AI;
} }
if (player == field.playerTwo) { if (player == field.playerTwo)
{
playerTwoAI = AI; playerTwoAI = AI;
} }
} }
@ -327,7 +361,8 @@ void Position::getChoiceOfSpecialAI(MillAI *AI, unsigned int *pushFrom, unsigned
*pushTo = field.size; *pushTo = field.size;
theField.createBoard(); theField.createBoard();
field.copyBoard(&theField); 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(); theField.deleteBoard();
} }
@ -343,11 +378,17 @@ void Position::getComputersChoice(unsigned int *pushFrom, unsigned int *pushTo)
theField.createBoard(); theField.createBoard();
field.copyBoard(&theField); field.copyBoard(&theField);
if ((field.settingPhase || field.curPlayer->numPossibleMoves > 0) && winner == 0) { if ((field.settingPhase || field.curPlayer->numPossibleMoves > 0) && winner == 0)
if (field.curPlayer->id == field.playerOne) { {
if (playerOneAI != nullptr) playerOneAI->play(&theField, pushFrom, pushTo); if (field.curPlayer->id == field.playerOne)
} else { {
if (playerTwoAI != nullptr) playerTwoAI->play(&theField, pushFrom, pushTo); 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; unsigned int movingDirection, i;
// parameter ok ? // parameter ok ?
if (from >= field.size) return false; if (from >= field.size)
if (to >= field.size) return false; return false;
if (to >= field.size)
return false;
// is stone from player ? // is stone from player ?
if (field.board[from] != player->id) return false; if (field.board[from] != player->id)
return false;
// is destination free ? // 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 // 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 // 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 ? // are both squares connected ?
if (movingDirection == 4) return false; if (movingDirection == 4)
return false;
} }
// everything is ok // everything is ok
@ -397,13 +446,18 @@ void Position::calcPossibleMoves(Player *player)
unsigned int i, j; unsigned int i, j;
// zero // zero
for (i = 0; i < MAX_NUM_POS_MOVES; i++) player->posTo[i] = field.size; for (i = 0; i < MAX_NUM_POS_MOVES; i++)
for (i = 0; i < MAX_NUM_POS_MOVES; i++) player->posFrom[i] = field.size; player->posTo[i] = field.size;
for (i = 0; i < MAX_NUM_POS_MOVES; i++)
player->posFrom[i] = field.size;
// calc // calc
for (player->numPossibleMoves = 0, i = 0; i < field.size; i++) { for (player->numPossibleMoves = 0, i = 0; i < field.size; i++)
for (j = 0; j < field.size; j++) { {
if (isNormalMovePossible(i, j, player)) { for (j = 0; j < field.size; j++)
{
if (isNormalMovePossible(i, j, player))
{
player->posFrom[player->numPossibleMoves] = i; player->posFrom[player->numPossibleMoves] = i;
player->posTo[player->numPossibleMoves] = j; player->posTo[player->numPossibleMoves] = j;
player->numPossibleMoves++; player->numPossibleMoves++;
@ -412,73 +466,88 @@ void Position::calcPossibleMoves(Player *player)
} }
// stoneMoveAble // stoneMoveAble
for (i = 0; i < field.size; i++) { 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); for (j = 0; j < 4; j++)
else field.stoneMoveAble[i][j] = false; {
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() // Name: setWarningAndMill()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void Position::setWarningAndMill(unsigned int stone, unsigned int firstNeighbour, unsigned int secondNeighbour, bool isNewStone) void Position::setWarningAndMill(unsigned int stone, unsigned int firstNeighbour, unsigned int secondNeighbour, bool isNewStone)
{ {
// locals // locals
int rowOwner = field.board[stone]; int rowOwner = field.board[stone];
unsigned int rowOwnerWarning = (rowOwner == field.playerOne) ? field.playerOneWarning : field.playerTwoWarning; unsigned int rowOwnerWarning = (rowOwner == field.playerOne) ? field.playerOneWarning : field.playerTwoWarning;
// mill closed ? // 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[stone]++;
field.stonePartOfMill[firstNeighbour]++; field.stonePartOfMill[firstNeighbour]++;
field.stonePartOfMill[secondNeighbour]++; field.stonePartOfMill[secondNeighbour]++;
if (isNewStone) field.stoneMustBeRemoved = 1; if (isNewStone)
field.stoneMustBeRemoved = 1;
} }
//warning ? //warning ?
if (rowOwner != field.squareIsFree && field.board[firstNeighbour] == field.squareIsFree && field.board[secondNeighbour] == rowOwner) field.warnings[firstNeighbour] |= rowOwnerWarning; if (rowOwner != field.squareIsFree && field.board[firstNeighbour] == field.squareIsFree && field.board[secondNeighbour] == rowOwner)
if (rowOwner != field.squareIsFree && field.board[secondNeighbour] == field.squareIsFree && field.board[firstNeighbour] == rowOwner) field.warnings[secondNeighbour] |= rowOwnerWarning; field.warnings[firstNeighbour] |= rowOwnerWarning;
if (rowOwner != field.squareIsFree && field.board[secondNeighbour] == field.squareIsFree && field.board[firstNeighbour] == rowOwner)
field.warnings[secondNeighbour] |= rowOwnerWarning;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: updateMillsAndWarnings() // Name: updateMillsAndWarnings()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void Position::updateMillsAndWarnings(unsigned int newStone) void Position::updateMillsAndWarnings(unsigned int newStone)
{ {
// locals // locals
unsigned int i; unsigned int i;
bool atLeastOneStoneRemoveAble; bool atLeastOneStoneRemoveAble;
// zero // zero
for (i = 0; i < field.size; i++) field.stonePartOfMill[i] = 0; for (i = 0; i < field.size; i++)
for (i = 0; i < field.size; i++) field.warnings[i] = field.noWarning; field.stonePartOfMill[i] = 0;
for (i = 0; i < field.size; i++)
field.warnings[i] = field.noWarning;
field.stoneMustBeRemoved = 0; field.stoneMustBeRemoved = 0;
// go in every direction // 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][0][0], field.neighbour[i][0][1], i == newStone);
setWarningAndMill(i, field.neighbour[i][1][0], field.neighbour[i][1][1], i == newStone); setWarningAndMill(i, field.neighbour[i][1][0], field.neighbour[i][1][1], i == newStone);
} }
// since every mill was detected 3 times // 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 // 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; for (atLeastOneStoneRemoveAble = false, i = 0; i < field.size; i++)
if (!atLeastOneStoneRemoveAble) field.stoneMustBeRemoved = 0; if (field.stonePartOfMill[i] == 0 && field.board[i] == field.oppPlayer->id)
atLeastOneStoneRemoveAble = true;
if (!atLeastOneStoneRemoveAble)
field.stoneMustBeRemoved = 0;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: do_move() // 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 // avoid index override
if (movesDone >= MAX_NUM_MOVES) if (movesDone >= MAX_NUM_MOVES)
@ -489,7 +558,8 @@ bool Position::do_move(unsigned int pushFrom, unsigned int pushTo)
return false; return false;
// handle the remove of a stone // handle the remove of a stone
if (field.stoneMustBeRemoved) { if (field.stoneMustBeRemoved)
{
// parameter ok ? // parameter ok ?
if (pushFrom >= field.size) if (pushFrom >= field.size)
@ -513,7 +583,8 @@ bool Position::do_move(unsigned int pushFrom, unsigned int pushTo)
movesDone++; movesDone++;
// is the game finished ? // 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 // update warnings & mills
updateMillsAndWarnings(field.size); updateMillsAndWarnings(field.size);
@ -523,16 +594,20 @@ bool Position::do_move(unsigned int pushFrom, unsigned int pushTo)
calcPossibleMoves(field.oppPlayer); calcPossibleMoves(field.oppPlayer);
// is opponent unable to move ? // 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 // next player
if (!field.stoneMustBeRemoved) setNextPlayer(); if (!field.stoneMustBeRemoved)
setNextPlayer();
// everything is ok // everything is ok
return true; return true;
// handle setting phase // handle setting phase
} else if (field.settingPhase) { }
else if (field.settingPhase)
{
// parameter ok ? // parameter ok ?
if (pushTo >= field.size) if (pushTo >= field.size)
@ -558,19 +633,24 @@ bool Position::do_move(unsigned int pushFrom, unsigned int pushTo)
calcPossibleMoves(field.oppPlayer); calcPossibleMoves(field.oppPlayer);
// setting phase finished ? // setting phase finished ?
if (field.stonesSet == 18) field.settingPhase = false; if (field.stonesSet == 18)
field.settingPhase = false;
// is opponent unable to move ? // 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 // next player
if (!field.stoneMustBeRemoved) setNextPlayer(); if (!field.stoneMustBeRemoved)
setNextPlayer();
// everything is ok // everything is ok
return true; return true;
// normal move // normal move
} else { }
else
{
// is move possible ? // is move possible ?
if (!isNormalMovePossible(pushFrom, pushTo, field.curPlayer)) if (!isNormalMovePossible(pushFrom, pushTo, field.curPlayer))
@ -591,10 +671,12 @@ bool Position::do_move(unsigned int pushFrom, unsigned int pushTo)
calcPossibleMoves(field.oppPlayer); calcPossibleMoves(field.oppPlayer);
// is opponent unable to move ? // 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 // next player
if (!field.stoneMustBeRemoved) setNextPlayer(); if (!field.stoneMustBeRemoved)
setNextPlayer();
// everything is ok // everything is ok
return true; return true;
@ -612,9 +694,12 @@ bool Position::setCurrentGameState(fieldStruct *curState)
winner = 0; winner = 0;
movesDone = 0; movesDone = 0;
if ((field.curPlayer->numStones < 3) && (!field.settingPhase)) winner = field.oppPlayer->id; if ((field.curPlayer->numStones < 3) && (!field.settingPhase))
if ((field.oppPlayer->numStones < 3) && (!field.settingPhase)) winner = field.curPlayer->id; winner = field.oppPlayer->id;
if ((field.curPlayer->numPossibleMoves == 0) && (!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; return true;
} }
@ -628,43 +713,65 @@ bool Position::compareWithField(fieldStruct *compareField)
unsigned int i, j; unsigned int i, j;
bool ret = true; bool ret = true;
if (!comparePlayers(field.curPlayer, compareField->curPlayer)) { if (!comparePlayers(field.curPlayer, compareField->curPlayer))
cout << "error - curPlayer differs!" << endl; ret = false; {
cout << "error - curPlayer differs!" << endl;
ret = false;
} }
if (!comparePlayers(field.oppPlayer, compareField->oppPlayer)) { if (!comparePlayers(field.oppPlayer, compareField->oppPlayer))
cout << "error - oppPlayer differs!" << endl; ret = false; {
cout << "error - oppPlayer differs!" << endl;
ret = false;
} }
if (field.stonesSet != compareField->stonesSet) { if (field.stonesSet != compareField->stonesSet)
cout << "error - stonesSet differs!" << endl; ret = false; {
cout << "error - stonesSet differs!" << endl;
ret = false;
} }
if (field.settingPhase != compareField->settingPhase) { if (field.settingPhase != compareField->settingPhase)
cout << "error - settingPhase differs!" << endl; ret = false; {
cout << "error - settingPhase differs!" << endl;
ret = false;
} }
if (field.stoneMustBeRemoved != compareField->stoneMustBeRemoved) { if (field.stoneMustBeRemoved != compareField->stoneMustBeRemoved)
cout << "error - stoneMustBeRemoved differs!" << endl; ret = false; {
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]) { if (field.board[i] != compareField->board[i])
cout << "error - board[] differs!" << endl; ret = false; {
cout << "error - board[] differs!" << endl;
ret = false;
} }
if (field.warnings[i] != compareField->warnings[i]) { if (field.warnings[i] != compareField->warnings[i])
cout << "error - warnings[] differs!" << endl; ret = false; {
cout << "error - warnings[] differs!" << endl;
ret = false;
} }
if (field.stonePartOfMill[i] != compareField->stonePartOfMill[i]) { if (field.stonePartOfMill[i] != compareField->stonePartOfMill[i])
cout << "error - stonePart[] differs!" << endl; ret = false; {
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]) { if (field.connectedSquare[i][j] != compareField->connectedSquare[i][j])
cout << "error - connectedSquare[] differs!" << endl; ret = false; {
cout << "error - connectedSquare[] differs!" << endl;
ret = false;
} }
// if (board.stoneMoveAble[i][j] != compareField->stoneMoveAble[i][j]) { cout << "error - stoneMoveAble 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]) { if (field.neighbour[i][j / 2][j % 2] != compareField->neighbour[i][j / 2][j % 2])
cout << "error - neighbour differs!" << endl; ret = false; {
cout << "error - neighbour differs!" << endl;
ret = false;
} }
} }
} }
@ -681,20 +788,30 @@ bool Position::comparePlayers(Player *playerA, Player *playerB)
// unsigned int i; // unsigned int i;
bool ret = true; bool ret = true;
if (playerA->numStonesMissing != playerB->numStonesMissing) { if (playerA->numStonesMissing != playerB->numStonesMissing)
cout << "error - numStonesMissing differs!" << endl; ret = false; {
cout << "error - numStonesMissing differs!" << endl;
ret = false;
} }
if (playerA->numStones != playerB->numStones) { if (playerA->numStones != playerB->numStones)
cout << "error - numStones differs!" << endl; ret = false; {
cout << "error - numStones differs!" << endl;
ret = false;
} }
if (playerA->id != playerB->id) { if (playerA->id != playerB->id)
cout << "error - id differs!" << endl; ret = false; {
cout << "error - id differs!" << endl;
ret = false;
} }
if (playerA->warning != playerB->warning) { if (playerA->warning != playerB->warning)
cout << "error - warning differs!" << endl; ret = false; {
cout << "error - warning differs!" << endl;
ret = false;
} }
if (playerA->numPossibleMoves != playerB->numPossibleMoves) { if (playerA->numPossibleMoves != playerB->numPossibleMoves)
cout << "error - numPossibleMoves differs!" << endl; ret = false; {
cout << "error - numPossibleMoves differs!" << endl;
ret = false;
} }
// for (i=0; i<MAX_NUM_POS_MOVES; i++) if (playerA->posFrom[i] = playerB->posFrom[i]) return false; // for (i=0; i<MAX_NUM_POS_MOVES; i++) if (playerA->posFrom[i] = playerB->posFrom[i]) return false;
@ -726,10 +843,12 @@ void Position::undo_move(void)
unsigned int i; unsigned int i;
// at least one move must be done // at least one move must be done
if (movesDone) { if (movesDone)
{
// make backup of log // make backup of log
for (i = 0; i < movesDone; i++) { for (i = 0; i < movesDone; i++)
{
moveLogFrom_bak[i] = moveLogFrom[i]; moveLogFrom_bak[i] = moveLogFrom[i];
moveLogTo_bak[i] = moveLogTo[i]; moveLogTo_bak[i] = moveLogTo[i];
} }
@ -740,7 +859,8 @@ void Position::undo_move(void)
movesDone = 0; movesDone = 0;
// and play again // 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]); do_move(moveLogFrom_bak[i], moveLogTo_bak[i]);
} }
} }
@ -752,14 +872,17 @@ void Position::undo_move(void)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: calcNumberOfRestingStones() // Name: calcNumberOfRestingStones()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void Position::calcNumberOfRestingStones(int &numWhiteStonesResting, int &numBlackStonesResting) void Position::calcNumberOfRestingStones(int &numWhiteStonesResting, int &numBlackStonesResting)
{ {
if (getCurrentPlayer() == fieldStruct::playerTwo) { if (getCurrentPlayer() == fieldStruct::playerTwo)
{
numWhiteStonesResting = fieldStruct::numStonesPerPlayer - field.curPlayer->numStonesMissing - field.curPlayer->numStones; numWhiteStonesResting = fieldStruct::numStonesPerPlayer - field.curPlayer->numStonesMissing - field.curPlayer->numStones;
numBlackStonesResting = fieldStruct::numStonesPerPlayer - field.oppPlayer->numStonesMissing - field.oppPlayer->numStones; numBlackStonesResting = fieldStruct::numStonesPerPlayer - field.oppPlayer->numStonesMissing - field.oppPlayer->numStones;
} else { }
else
{
numWhiteStonesResting = fieldStruct::numStonesPerPlayer - field.oppPlayer->numStonesMissing - field.oppPlayer->numStones; numWhiteStonesResting = fieldStruct::numStonesPerPlayer - field.oppPlayer->numStonesMissing - field.oppPlayer->numStones;
numBlackStonesResting = fieldStruct::numStonesPerPlayer - field.curPlayer->numStonesMissing - field.curPlayer->numStones; numBlackStonesResting = fieldStruct::numStonesPerPlayer - field.curPlayer->numStonesMissing - field.curPlayer->numStones;
} }

View File

@ -6,7 +6,6 @@
https://github.com/madweasel/madweasels-cpp https://github.com/madweasel/madweasels-cpp
\*********************************************************************/ \*********************************************************************/
#ifndef MUEHLE_H #ifndef MUEHLE_H
#define MUEHLE_H #define MUEHLE_H
@ -18,16 +17,28 @@
#include "types.h" #include "types.h"
using namespace std; using namespace std;
/*** Konstanten ******************************************************/ /*** Konstanten ******************************************************/
#define MAX_NUM_MOVES 10000 #define MAX_NUM_MOVES 10000
/*** Makros ******************************************************/ /*** Makros ******************************************************/
#define SAFE_DELETE(p) { if(p) { delete (p); (p)=nullptr; } } #define SAFE_DELETE(p) \
#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=nullptr; } } { \
if (p) \
{ \
delete (p); \
(p) = nullptr; \
} \
}
#define SAFE_DELETE_ARRAY(p) \
{ \
if (p) \
{ \
delete[](p); \
(p) = nullptr; \
} \
}
/*** Klassen *********************************************************/ /*** Klassen *********************************************************/
@ -35,21 +46,21 @@ class Position
{ {
private: private:
// Variables // Variables
unsigned int *moveLogFrom, *moveLogTo, movesDone; // array containing the history of moves done unsigned int *moveLogFrom, *moveLogTo, movesDone; // array containing the history of moves done
MillAI *playerOneAI; // class-pointer to the AI of player one MillAI *playerOneAI; // class-pointer to the AI of player one
MillAI *playerTwoAI; // class-pointer to the AI of player two MillAI *playerTwoAI; // class-pointer to the AI of player two
fieldStruct field; // current board 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 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 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 int beginningPlayer; // playerId of the player who makes the first move
// Functions // Functions
void exit(); void exit();
void setNextPlayer(); void setNextPlayer();
void calcPossibleMoves(Player *player); void calcPossibleMoves(Player *player);
void updateMillsAndWarnings(unsigned int newStone); void updateMillsAndWarnings(unsigned int newStone);
bool isNormalMovePossible(unsigned int from, unsigned int to, Player *player); bool isNormalMovePossible(unsigned int from, unsigned int to, Player *player);
void setWarningAndMill(unsigned int stone, unsigned int firstNeighbour, unsigned int secondNeighbour, bool isNewStone); void setWarningAndMill(unsigned int stone, unsigned int firstNeighbour, unsigned int secondNeighbour, bool isNewStone);
public: public:
// Constructor / destructor // Constructor / destructor
@ -57,73 +68,72 @@ public:
~Position(); ~Position();
// Functions // Functions
void undo_move(); void undo_move();
void beginNewGame(MillAI *firstPlayerAI, MillAI *secondPlayerAI, int currentPlayer); void beginNewGame(MillAI *firstPlayerAI, MillAI *secondPlayerAI, int currentPlayer);
void setAI(int player, MillAI *AI); void setAI(int player, MillAI *AI);
bool do_move(unsigned int pushFrom, unsigned int pushTo); bool do_move(unsigned int pushFrom, unsigned int pushTo);
void getComputersChoice(unsigned int *pushFrom, unsigned int *pushTo); void getComputersChoice(unsigned int *pushFrom, unsigned int *pushTo);
bool setCurrentGameState(fieldStruct *curState); bool setCurrentGameState(fieldStruct *curState);
bool compareWithField(fieldStruct *compareField); bool compareWithField(fieldStruct *compareField);
bool comparePlayers(Player *playerA, Player *playerB); bool comparePlayers(Player *playerA, Player *playerB);
void printBoard(); void printBoard();
bool startSettingPhase(MillAI *firstPlayerAI, MillAI *secondPlayerAI, int currentPlayer, bool settingPhase); bool startSettingPhase(MillAI *firstPlayerAI, MillAI *secondPlayerAI, int currentPlayer, bool settingPhase);
bool put_piece(unsigned int pos, int player); bool put_piece(unsigned int pos, int player);
bool settingPhaseHasFinished(); bool settingPhaseHasFinished();
void getChoiceOfSpecialAI(MillAI *AI, unsigned int *pushFrom, unsigned int *pushTo); void getChoiceOfSpecialAI(MillAI *AI, unsigned int *pushFrom, unsigned int *pushTo);
void setUpCalcPossibleMoves(Player *player); void setUpCalcPossibleMoves(Player *player);
void setUpSetWarningAndMill(unsigned int stone, unsigned int firstNeighbour, unsigned int secondNeighbour); void setUpSetWarningAndMill(unsigned int stone, unsigned int firstNeighbour, unsigned int secondNeighbour);
void calcNumberOfRestingStones(int &numWhiteStonesResting, int &numBlackStonesResting); void calcNumberOfRestingStones(int &numWhiteStonesResting, int &numBlackStonesResting);
// getter // getter
void getLog(unsigned int &numMovesDone, unsigned int *from, unsigned int *to); void getLog(unsigned int &numMovesDone, unsigned int *from, unsigned int *to);
bool getField(int *pField); bool getField(int *pField);
bool isCurrentPlayerHuman(); bool isCurrentPlayerHuman();
bool isOpponentPlayerHuman(); bool isOpponentPlayerHuman();
bool inSettingPhase() bool inSettingPhase()
{ {
return field.settingPhase; return field.settingPhase;
} }
unsigned int mustStoneBeRemoved() unsigned int mustStoneBeRemoved()
{ {
return field.stoneMustBeRemoved; return field.stoneMustBeRemoved;
} }
int getWinner() int getWinner()
{ {
return winner; return winner;
} }
int getCurrentPlayer() int getCurrentPlayer()
{ {
return field.curPlayer->id; return field.curPlayer->id;
} }
unsigned int getLastMoveFrom() unsigned int getLastMoveFrom()
{ {
return (movesDone ? moveLogFrom[movesDone - 1] : field.size); return (movesDone ? moveLogFrom[movesDone - 1] : field.size);
} }
unsigned int getLastMoveTo() unsigned int getLastMoveTo()
{ {
return (movesDone ? moveLogTo[movesDone - 1] : field.size); return (movesDone ? moveLogTo[movesDone - 1] : field.size);
} }
unsigned int getMovesDone() unsigned int getMovesDone()
{ {
return movesDone; return movesDone;
} }
unsigned int getNumStonesSet() unsigned int getNumStonesSet()
{ {
return field.stonesSet; return field.stonesSet;
} }
int getBeginningPlayer() int getBeginningPlayer()
{ {
return beginningPlayer; return beginningPlayer;
} }
unsigned int getNumStonOfCurPlayer() unsigned int getNumStonOfCurPlayer()
{ {
return field.curPlayer->numStones; return field.curPlayer->numStones;
} }
unsigned int getNumStonOfOppPlayer() unsigned int getNumStonOfOppPlayer()
{ {
return field.oppPlayer->numStones; return field.oppPlayer->numStones;
} }
}; };
#endif #endif

View File

@ -25,55 +25,68 @@ RandomAI::RandomAI()
RandomAI::~RandomAI() RandomAI::~RandomAI()
{ {
// Locals // Locals
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: play() // Name: play()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void RandomAI::play(fieldStruct *theField, unsigned int *pushFrom, unsigned int *pushTo) void RandomAI::play(fieldStruct *theField, unsigned int *pushFrom, unsigned int *pushTo)
{ {
// locals // locals
unsigned int from, to, direction; unsigned int from, to, direction;
bool allowedToSpring = (theField->curPlayer->numStones == 3) ? true : false; bool allowedToSpring = (theField->curPlayer->numStones == 3) ? true : false;
// must stone be removed ? // must stone be removed ?
if (theField->stoneMustBeRemoved) { if (theField->stoneMustBeRemoved)
{
// search a stone from the enemy // search a stone from the enemy
do { do
{
from = rand() % theField->size; from = rand() % theField->size;
to = theField->size; to = theField->size;
} while (theField->board[from] != theField->oppPlayer->id || theField->stonePartOfMill[from]); } while (theField->board[from] != theField->oppPlayer->id || theField->stonePartOfMill[from]);
// still in setting phase ? // still in setting phase ?
} else if (theField->settingPhase) { }
else if (theField->settingPhase)
{
// search a free square // search a free square
do { do
{
from = theField->size; from = theField->size;
to = rand() % theField->size; to = rand() % theField->size;
} while (theField->board[to] != theField->squareIsFree); } while (theField->board[to] != theField->squareIsFree);
// try to push randomly // try to push randomly
} else { }
else
{
do { do
{
// search an own stone // search an own stone
do { do
{
from = rand() % theField->size; from = rand() % theField->size;
} while (theField->board[from] != theField->curPlayer->id); } while (theField->board[from] != theField->curPlayer->id);
// select a free square // select a free square
if (allowedToSpring) { if (allowedToSpring)
do { {
do
{
to = rand() % theField->size; to = rand() % theField->size;
} while (theField->board[to] != theField->squareIsFree); } while (theField->board[to] != theField->squareIsFree);
// select a connected square // select a connected square
} else { }
do { else
{
do
{
direction = rand() % 4; direction = rand() % 4;
to = theField->connectedSquare[from][direction]; to = theField->connectedSquare[from][direction];
} while (to == theField->size); } while (to == theField->size);

View File

@ -10,7 +10,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: hibit() // Name: hibit()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
int MyString::hibit(unsigned int n) int MyString::hibit(unsigned int n)
{ {
@ -24,7 +24,7 @@ int MyString::hibit(unsigned int n)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: MyString() // Name: MyString()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
MyString::MyString() MyString::MyString()
{ {
@ -32,7 +32,7 @@ MyString::MyString()
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: MyString() // Name: MyString()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
MyString::MyString(const char *cStr) MyString::MyString(const char *cStr)
{ {
@ -41,7 +41,7 @@ MyString::MyString(const char *cStr)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: MyString() // Name: MyString()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
MyString::MyString(const WCHAR *cStr) MyString::MyString(const WCHAR *cStr)
{ {
@ -50,15 +50,19 @@ MyString::MyString(const WCHAR *cStr)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: MyString() // Name: MyString()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
MyString::~MyString() MyString::~MyString()
{ {
if (strA != nullptr) { if (strA != nullptr)
delete[] strA; strA = nullptr; {
delete[] strA;
strA = nullptr;
} }
if (strW != nullptr) { if (strW != nullptr)
delete[] strW; strW = nullptr; {
delete[] strW;
strW = nullptr;
} }
strW = nullptr; strW = nullptr;
strA = nullptr; strA = nullptr;
@ -68,7 +72,7 @@ MyString::~MyString()
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: c_strA() // Name: c_strA()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
const char *MyString::c_strA() const char *MyString::c_strA()
{ {
@ -77,7 +81,7 @@ const char *MyString::c_strA()
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: c_strW() // Name: c_strW()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
const WCHAR *MyString::c_strW() const WCHAR *MyString::c_strW()
{ {
@ -86,7 +90,7 @@ const WCHAR *MyString::c_strW()
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: assign() // Name: assign()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
MyString &MyString::assign(const char *cStr) MyString &MyString::assign(const char *cStr)
{ {
@ -95,9 +99,12 @@ MyString &MyString::assign(const char *cStr)
size_t newLength = strlen(cStr); size_t newLength = strlen(cStr);
size_t newReserved = (size_t)hibit((unsigned int)newLength) * 2; size_t newReserved = (size_t)hibit((unsigned int)newLength) * 2;
if (reserved < newReserved) this->~MyString(); if (reserved < newReserved)
if (strA == nullptr) strA = new char[newReserved]; this->~MyString();
if (strW == nullptr) strW = new WCHAR[newReserved]; if (strA == nullptr)
strA = new char[newReserved];
if (strW == nullptr)
strW = new WCHAR[newReserved];
reserved = newReserved; reserved = newReserved;
length = newLength; length = newLength;
@ -110,7 +117,7 @@ MyString &MyString::assign(const char *cStr)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: assign() // Name: assign()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
MyString &MyString::assign(const WCHAR *cStr) MyString &MyString::assign(const WCHAR *cStr)
{ {
@ -119,9 +126,12 @@ MyString &MyString::assign(const WCHAR *cStr)
size_t newLength = wcslen(cStr); size_t newLength = wcslen(cStr);
size_t newReserved = (size_t)hibit((unsigned int)newLength) * 2; size_t newReserved = (size_t)hibit((unsigned int)newLength) * 2;
if (reserved < newReserved) this->~MyString(); if (reserved < newReserved)
if (strA == nullptr) strA = new char[newReserved]; this->~MyString();
if (strW == nullptr) strW = new WCHAR[newReserved]; if (strA == nullptr)
strA = new char[newReserved];
if (strW == nullptr)
strW = new WCHAR[newReserved];
reserved = newReserved; reserved = newReserved;
length = newLength; 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) bool readAsciiData(HANDLE hFile, double *pData, unsigned int numValues, unsigned char decimalSeperator, unsigned char columnSeparator)
{ {
// constants // constants
const unsigned int maxValueLengthInBytes = 32; const unsigned int maxValueLengthInBytes = 32;
const unsigned int bufferSize = 1000; const unsigned int bufferSize = 1000;
// locals // locals
DWORD dwBytesRead; DWORD dwBytesRead;
unsigned char buffer[bufferSize]; unsigned char buffer[bufferSize];
unsigned char *curByte = &buffer[0]; unsigned char *curByte = &buffer[0];
unsigned int curReadValue = 0; unsigned int curReadValue = 0;
unsigned int actualBufferSize = 0; unsigned int actualBufferSize = 0;
unsigned int curBufferPos = bufferSize; unsigned int curBufferPos = bufferSize;
unsigned int decimalPos = 0; unsigned int decimalPos = 0;
int integralValue = 0; // ACHTUNG: Erlaubt nur 8 Vorkommastellen int integralValue = 0; // ACHTUNG: Erlaubt nur 8 Vorkommastellen
int fractionalValue = 0; // ACHTUNG: Erlaubt nur 8 Nachkommastellen int fractionalValue = 0; // ACHTUNG: Erlaubt nur 8 Nachkommastellen
int exponentialValue = 1; int exponentialValue = 1;
bool valIsNegativ = false; bool valIsNegativ = false;
bool expIsNegativ = false; bool expIsNegativ = false;
bool decimalPlace = false; bool decimalPlace = false;
bool exponent = false; bool exponent = false;
double fractionalFactor[] = { 0, double fractionalFactor[] = {0,
0.1, 0.1,
0.01, 0.01,
0.001, 0.001,
0.0001, 0.0001,
0.00001, 0.00001,
0.000001, 0.000001,
0.0000001, 0.0000001,
0.00000001, 0.00000001,
0.000000001, 0.000000001,
0.0000000001 }; 0.0000000001};
// read each value // read each value
do { do
{
// read from buffer if necessary // read from buffer if necessary
if (curBufferPos >= bufferSize - maxValueLengthInBytes) { if (curBufferPos >= bufferSize - maxValueLengthInBytes)
{
memcpy(&buffer[0], &buffer[curBufferPos], bufferSize - curBufferPos); memcpy(&buffer[0], &buffer[curBufferPos], bufferSize - curBufferPos);
ReadFile(hFile, &buffer[bufferSize - curBufferPos], curBufferPos, &dwBytesRead, nullptr); ReadFile(hFile, &buffer[bufferSize - curBufferPos], curBufferPos, &dwBytesRead, nullptr);
actualBufferSize = bufferSize - curBufferPos + dwBytesRead; actualBufferSize = bufferSize - curBufferPos + dwBytesRead;
@ -182,105 +194,233 @@ bool readAsciiData(HANDLE hFile, double *pData, unsigned int numValues, unsigned
} }
// process current byte // process current byte
switch (*curByte) { switch (*curByte)
case '-': if (exponent) { {
expIsNegativ = true; case '-':
} else { if (exponent)
valIsNegativ = true; {
} break; expIsNegativ = true;
case '+': /* ignore */ break; }
case 'e': case 'E': exponent = true; decimalPlace = false; break; else
case '0': if (decimalPlace) { {
fractionalValue *= 10; fractionalValue += 0; decimalPos++; valIsNegativ = true;
} else if (exponent) { }
exponentialValue *= 10; exponentialValue += 0; break;
} else { case '+': /* ignore */
integralValue *= 10; integralValue += 0; break;
} break; case 'e':
case '1': if (decimalPlace) { case 'E':
fractionalValue *= 10; fractionalValue += 1; decimalPos++; exponent = true;
} else if (exponent) { decimalPlace = false;
exponentialValue *= 10; exponentialValue += 1; break;
} else { case '0':
integralValue *= 10; integralValue += 1; if (decimalPlace)
} break; {
case '2': if (decimalPlace) { fractionalValue *= 10;
fractionalValue *= 10; fractionalValue += 2; decimalPos++; fractionalValue += 0;
} else if (exponent) { decimalPos++;
exponentialValue *= 10; exponentialValue += 2; }
} else { else if (exponent)
integralValue *= 10; integralValue += 2; {
} break; exponentialValue *= 10;
case '3': if (decimalPlace) { exponentialValue += 0;
fractionalValue *= 10; fractionalValue += 3; decimalPos++; }
} else if (exponent) { else
exponentialValue *= 10; exponentialValue += 3; {
} else { integralValue *= 10;
integralValue *= 10; integralValue += 3; integralValue += 0;
} break; }
case '4': if (decimalPlace) { break;
fractionalValue *= 10; fractionalValue += 4; decimalPos++; case '1':
} else if (exponent) { if (decimalPlace)
exponentialValue *= 10; exponentialValue += 4; {
} else { fractionalValue *= 10;
integralValue *= 10; integralValue += 4; fractionalValue += 1;
} break; decimalPos++;
case '5': if (decimalPlace) { }
fractionalValue *= 10; fractionalValue += 5; decimalPos++; else if (exponent)
} else if (exponent) { {
exponentialValue *= 10; exponentialValue += 5; exponentialValue *= 10;
} else { exponentialValue += 1;
integralValue *= 10; integralValue += 5; }
} break; else
case '6': if (decimalPlace) { {
fractionalValue *= 10; fractionalValue += 6; decimalPos++; integralValue *= 10;
} else if (exponent) { integralValue += 1;
exponentialValue *= 10; exponentialValue += 6; }
} else { break;
integralValue *= 10; integralValue += 6; case '2':
} break; if (decimalPlace)
case '7': if (decimalPlace) { {
fractionalValue *= 10; fractionalValue += 7; decimalPos++; fractionalValue *= 10;
} else if (exponent) { fractionalValue += 2;
exponentialValue *= 10; exponentialValue += 7; decimalPos++;
} else { }
integralValue *= 10; integralValue += 7; else if (exponent)
} break; {
case '8': if (decimalPlace) { exponentialValue *= 10;
fractionalValue *= 10; fractionalValue += 8; decimalPos++; exponentialValue += 2;
} else if (exponent) { }
exponentialValue *= 10; exponentialValue += 8; else
} else { {
integralValue *= 10; integralValue += 8; integralValue *= 10;
} break; integralValue += 2;
case '9': if (decimalPlace) { }
fractionalValue *= 10; fractionalValue += 9; decimalPos++; break;
} else if (exponent) { case '3':
exponentialValue *= 10; exponentialValue += 9; if (decimalPlace)
} else { {
integralValue *= 10; integralValue += 9; fractionalValue *= 10;
} break; 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: default:
if (*curByte == decimalSeperator) { if (*curByte == decimalSeperator)
{
decimalPlace = true; decimalPlace = true;
exponent = false; exponent = false;
} else if (*curByte == columnSeparator) { }
else if (*curByte == columnSeparator)
{
// everything ok? // everything ok?
if (decimalPos > 8) { if (decimalPos > 8)
{
cout << "ERROR in function readAsciiData(): Too many digits on decimal place. Maximum is 8 !" << endl; cout << "ERROR in function readAsciiData(): Too many digits on decimal place. Maximum is 8 !" << endl;
return false; return false;
} }
// calc final value // calc final value
(*pData) = integralValue; (*pData) = integralValue;
if (decimalPos) { if (decimalPos)
{
(*pData) += fractionalValue * fractionalFactor[decimalPos]; (*pData) += fractionalValue * fractionalFactor[decimalPos];
} }
if (valIsNegativ) { if (valIsNegativ)
{
(*pData) *= -1; (*pData) *= -1;
} }
if (exponent) { if (exponent)
{
(*pData) *= pow(10, expIsNegativ ? -1 * exponentialValue : 1); (*pData) *= pow(10, expIsNegativ ? -1 * exponentialValue : 1);
} }
@ -297,8 +437,9 @@ bool readAsciiData(HANDLE hFile, double *pData, unsigned int numValues, unsigned
// save value // save value
pData++; pData++;
curReadValue++; curReadValue++;
}
} else { else
{
// do nothing // do nothing
} }
break; break;
@ -309,7 +450,8 @@ bool readAsciiData(HANDLE hFile, double *pData, unsigned int numValues, unsigned
curByte++; curByte++;
// buffer overrun? // buffer overrun?
if (curBufferPos >= actualBufferSize) return false; if (curBufferPos >= actualBufferSize)
return false;
} while (curReadValue < numValues); } while (curReadValue < numValues);

View File

@ -24,17 +24,15 @@ bool readAsciiData(HANDLE hFile, double *pData, unsigned int numValues, unsigned
class MyString class MyString
{ {
private: private:
// variables // variables
WCHAR *strW = nullptr; WCHAR *strW = nullptr;
char *strA = nullptr; char *strA = nullptr;
size_t length = 0; size_t length = 0;
size_t reserved = 0; size_t reserved = 0;
// functions // functions
public: public:
// functions // functions
MyString(); MyString();
MyString(const char *cStr); MyString(const char *cStr);
@ -46,7 +44,7 @@ public:
MyString &assign(const char *cStr); MyString &assign(const char *cStr);
MyString &assign(const WCHAR *cStr); MyString &assign(const WCHAR *cStr);
static int hibit(unsigned int n); static int hibit(unsigned int n);
}; };
#endif #endif

View File

@ -15,8 +15,8 @@
ThreadManager::ThreadManager() ThreadManager::ThreadManager()
{ {
// locals // locals
unsigned int curThreadNo; unsigned int curThreadNo;
SYSTEM_INFO m_si = { 0 }; SYSTEM_INFO m_si = {0};
GetSystemInfo(&m_si); GetSystemInfo(&m_si);
@ -32,7 +32,8 @@ ThreadManager::ThreadManager()
InitializeCriticalSection(&csBarrier); InitializeCriticalSection(&csBarrier);
hEventBarrierPassedByEveryBody = CreateEvent(nullptr, true, false, nullptr); hEventBarrierPassedByEveryBody = CreateEvent(nullptr, true, false, nullptr);
for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) { for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++)
{
hThread[curThreadNo] = nullptr; hThread[curThreadNo] = nullptr;
threadId[curThreadNo] = 0; threadId[curThreadNo] = 0;
hBarrier[curThreadNo] = CreateEvent(nullptr, false, false, nullptr); hBarrier[curThreadNo] = CreateEvent(nullptr, false, false, nullptr);
@ -46,56 +47,66 @@ ThreadManager::ThreadManager()
ThreadManager::~ThreadManager() ThreadManager::~ThreadManager()
{ {
// locals // locals
unsigned int curThreadNo; unsigned int curThreadNo;
for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) { for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++)
{
CloseHandle(hBarrier[curThreadNo]); CloseHandle(hBarrier[curThreadNo]);
} }
DeleteCriticalSection(&csBarrier); DeleteCriticalSection(&csBarrier);
CloseHandle(hEventBarrierPassedByEveryBody); CloseHandle(hEventBarrierPassedByEveryBody);
if (hBarrier != nullptr) delete[] hBarrier; hBarrier = nullptr; if (hBarrier != nullptr)
if (hThread != nullptr) delete[] hThread; hThread = nullptr; delete[] hBarrier;
if (threadId != nullptr) delete[] threadId; threadId = nullptr; hBarrier = nullptr;
if (hThread != nullptr)
delete[] hThread;
hThread = nullptr;
if (threadId != nullptr)
delete[] threadId;
threadId = nullptr;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: waitForOtherThreads() // Name: waitForOtherThreads()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void ThreadManager::waitForOtherThreads(unsigned int threadNo) void ThreadManager::waitForOtherThreads(unsigned int threadNo)
{ {
// wait if other threads are still waiting at the barrier // wait if other threads are still waiting at the barrier
//cout << endl << "thread=" << threadNo << ", numThreadsPassedBarrier= " << numThreadsPassedBarrier << ": " << "while (numThreadsPassedBarrier>0)"; //cout << endl << "thread=" << threadNo << ", numThreadsPassedBarrier= " << numThreadsPassedBarrier << ": " << "while (numThreadsPassedBarrier>0)";
if (numThreadsPassedBarrier > 0) { if (numThreadsPassedBarrier > 0)
{
WaitForSingleObject(hEventBarrierPassedByEveryBody, INFINITE); WaitForSingleObject(hEventBarrierPassedByEveryBody, INFINITE);
} }
// a simple while (numThreadsPassedBarrier>0) {}; does not work, since the variable 'numThreadsPassedBarrier' is not updated, due to compiler optimizations // 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 // set signal that barrier is reached
//cout << endl << "thread=" << threadNo << ", numThreadsPassedBarrier= " << numThreadsPassedBarrier << ": " << "SetEvent()"; //cout << endl << "thread=" << threadNo << ", numThreadsPassedBarrier= " << numThreadsPassedBarrier << ": " << "SetEvent()";
SetEvent(hBarrier[threadNo]); SetEvent(hBarrier[threadNo]);
// enter the barrier one by one // enter the barrier one by one
//cout << endl << "thread=" << threadNo << ", numThreadsPassedBarrier= " << numThreadsPassedBarrier << ": " << "EnterCriticalSection()"; //cout << endl << "thread=" << threadNo << ", numThreadsPassedBarrier= " << numThreadsPassedBarrier << ": " << "EnterCriticalSection()";
EnterCriticalSection(&csBarrier); EnterCriticalSection(&csBarrier);
// if the first one which entered, then wait until other threads // if the first one which entered, then wait until other threads
if (numThreadsPassedBarrier == 0) { if (numThreadsPassedBarrier == 0)
{
//cout << endl << "thread=" << threadNo << ", numThreadsPassedBarrier= " << numThreadsPassedBarrier << ": " << "WaitForMultipleObjects()"; //cout << endl << "thread=" << threadNo << ", numThreadsPassedBarrier= " << numThreadsPassedBarrier << ": " << "WaitForMultipleObjects()";
WaitForMultipleObjects(numThreads, hBarrier, TRUE, INFINITE); WaitForMultipleObjects(numThreads, hBarrier, TRUE, INFINITE);
ResetEvent(hEventBarrierPassedByEveryBody); ResetEvent(hEventBarrierPassedByEveryBody);
} }
// count threads which passed the barrier // count threads which passed the barrier
//cout << endl << "thread=" << threadNo << ", numThreadsPassedBarrier= " << numThreadsPassedBarrier << ": " << "numThreadsPassedBarrier++"; //cout << endl << "thread=" << threadNo << ", numThreadsPassedBarrier= " << numThreadsPassedBarrier << ": " << "numThreadsPassedBarrier++";
numThreadsPassedBarrier++; numThreadsPassedBarrier++;
// the last one closes the door // the last one closes the door
//cout << endl << "thread=" << threadNo << ", numThreadsPassedBarrier= " << numThreadsPassedBarrier << ": " << "if (numThreadsPassedBarrier == numThreads) numThreadsPassedBarrier = 0"; //cout << endl << "thread=" << threadNo << ", numThreadsPassedBarrier= " << numThreadsPassedBarrier << ": " << "if (numThreadsPassedBarrier == numThreads) numThreadsPassedBarrier = 0";
if (numThreadsPassedBarrier == numThreads) { if (numThreadsPassedBarrier == numThreads)
{
numThreadsPassedBarrier = 0; numThreadsPassedBarrier = 0;
SetEvent(hEventBarrierPassedByEveryBody); SetEvent(hEventBarrierPassedByEveryBody);
} }
@ -106,7 +117,7 @@ void ThreadManager::waitForOtherThreads(unsigned int threadNo)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: getNumThreads() // Name: getNumThreads()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
unsigned int ThreadManager::getNumThreads() unsigned int ThreadManager::getNumThreads()
{ {
@ -115,20 +126,24 @@ unsigned int ThreadManager::getNumThreads()
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: setNumThreads() // Name: setNumThreads()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
bool ThreadManager::setNumThreads(unsigned int newNumThreads) bool ThreadManager::setNumThreads(unsigned int newNumThreads)
{ {
// cancel if any thread running // cancel if any thread running
EnterCriticalSection(&csBarrier); EnterCriticalSection(&csBarrier);
for (unsigned int curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) { for (unsigned int curThreadNo = 0; curThreadNo < numThreads; curThreadNo++)
if (hThread[curThreadNo]) return false; {
if (hThread[curThreadNo])
return false;
} }
for (unsigned int curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) { for (unsigned int curThreadNo = 0; curThreadNo < numThreads; curThreadNo++)
{
CloseHandle(hBarrier[curThreadNo]); CloseHandle(hBarrier[curThreadNo]);
} }
numThreads = newNumThreads; 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); hBarrier[curThreadNo] = CreateEvent(nullptr, false, false, nullptr);
} }
LeaveCriticalSection(&csBarrier); LeaveCriticalSection(&csBarrier);
@ -137,17 +152,21 @@ bool ThreadManager::setNumThreads(unsigned int newNumThreads)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: pauseExecution() // Name: pauseExecution()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void ThreadManager::pauseExecution() void ThreadManager::pauseExecution()
{ {
for (unsigned int curThread = 0; curThread < numThreads; curThread++) { for (unsigned int curThread = 0; curThread < numThreads; curThread++)
{
// unsuspend all threads // unsuspend all threads
if (!executionPaused) { if (!executionPaused)
{
SuspendThread(hThread[curThread]); SuspendThread(hThread[curThread]);
// suspend all threads // suspend all threads
} else { }
else
{
ResumeThread(hThread[curThread]); ResumeThread(hThread[curThread]);
} }
} }
@ -163,14 +182,15 @@ void ThreadManager::cancelExecution()
{ {
termineAllThreads = true; termineAllThreads = true;
executionCancelled = true; executionCancelled = true;
if (executionPaused) { if (executionPaused)
{
pauseExecution(); pauseExecution();
} }
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: uncancelExecution() // Name: uncancelExecution()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void ThreadManager::uncancelExecution() void ThreadManager::uncancelExecution()
{ {
@ -179,7 +199,7 @@ void ThreadManager::uncancelExecution()
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: wasExecutionCancelled() // Name: wasExecutionCancelled()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
bool ThreadManager::wasExecutionCancelled() bool ThreadManager::wasExecutionCancelled()
{ {
@ -193,11 +213,13 @@ bool ThreadManager::wasExecutionCancelled()
unsigned int ThreadManager::getThreadNumber() unsigned int ThreadManager::getThreadNumber()
{ {
// locals // locals
DWORD curThreadId = GetCurrentThreadId(); DWORD curThreadId = GetCurrentThreadId();
unsigned int curThreadNo; unsigned int curThreadNo;
for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) { for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++)
if (curThreadId == threadId[curThreadNo]) { {
if (curThreadId == threadId[curThreadNo])
{
return curThreadNo; return curThreadNo;
} }
} }
@ -208,26 +230,30 @@ unsigned int ThreadManager::getThreadNumber()
// Name: executeInParallel() // Name: executeInParallel()
// Desc: lpParameter is an array of size numThreads. // 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 // locals
unsigned int curThreadNo; unsigned int curThreadNo;
SIZE_T dwStackSize = 0; SIZE_T dwStackSize = 0;
// parameters ok? // parameters ok?
if (pParameter == nullptr) return TM_RETURN_VALUE_INVALID_PARAM; if (pParameter == nullptr)
return TM_RETURN_VALUE_INVALID_PARAM;
// globals // globals
termineAllThreads = false; termineAllThreads = false;
// create threads // 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]); 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); SetThreadPriority(hThread[curThreadNo], THREAD_PRIORITY_BELOW_NORMAL);
if (hThread[curThreadNo] == nullptr) { if (hThread[curThreadNo] == nullptr)
for (curThreadNo; curThreadNo > 0; curThreadNo--) { {
for (curThreadNo; curThreadNo > 0; curThreadNo--)
{
CloseHandle(hThread[curThreadNo - 1]); CloseHandle(hThread[curThreadNo - 1]);
hThread[curThreadNo - 1] = nullptr; hThread[curThreadNo - 1] = nullptr;
} }
@ -236,61 +262,73 @@ unsigned int ThreadManager::executeInParallel(DWORD threadProc(void *pParameter
} }
// start threads // start threads
for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) { for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++)
if (!executionPaused) ResumeThread(hThread[curThreadNo]); {
if (!executionPaused)
ResumeThread(hThread[curThreadNo]);
} }
// wait for every thread to end // wait for every thread to end
WaitForMultipleObjects(numThreads, hThread, TRUE, INFINITE); WaitForMultipleObjects(numThreads, hThread, TRUE, INFINITE);
// Close all thread handles upon completion. // Close all thread handles upon completion.
for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) { for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++)
{
CloseHandle(hThread[curThreadNo]); CloseHandle(hThread[curThreadNo]);
hThread[curThreadNo] = nullptr; hThread[curThreadNo] = nullptr;
threadId[curThreadNo] = 0; threadId[curThreadNo] = 0;
} }
// everything ok // everything ok
if (executionCancelled) { if (executionCancelled)
{
return TM_RETURN_VALUE_EXECUTION_CANCELLED; return TM_RETURN_VALUE_EXECUTION_CANCELLED;
} else { }
else
{
return TM_RETURN_VALUE_OK; return TM_RETURN_VALUE_OK;
} }
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: executeInParallel() // Name: executeInParallel()
// Desc: // Desc:
// lpParameter - an array of size numThreads // 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 // 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), unsigned int ThreadManager::executeParallelLoop(DWORD threadProc(void *pParameter, int index),
void *pParameter, void *pParameter,
unsigned int parameterStructSize, unsigned int parameterStructSize,
unsigned int scheduleType, unsigned int scheduleType,
int initialValue, int initialValue,
int finalValue, int finalValue,
int inkrement) int inkrement)
{ {
// parameters ok? // parameters ok?
if (executionCancelled == true) return TM_RETURN_VALUE_EXECUTION_CANCELLED; if (executionCancelled == true)
if (pParameter == nullptr) return TM_RETURN_VALUE_INVALID_PARAM; return TM_RETURN_VALUE_EXECUTION_CANCELLED;
if (scheduleType >= TM_SCHEDULE_NUM_TYPES) return TM_RETURN_VALUE_INVALID_PARAM; if (pParameter == nullptr)
if (inkrement == 0) return TM_RETURN_VALUE_INVALID_PARAM; return TM_RETURN_VALUE_INVALID_PARAM;
if (abs(finalValue - initialValue) == abs(inkrement)) 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 // locals
unsigned int curThreadNo; // the threads are enumerated from 0 to numThreads-1 unsigned int curThreadNo; // the threads are enumerated from 0 to numThreads-1
int numIterations = (finalValue - initialValue) / inkrement + 1; // total number of iterations int numIterations = (finalValue - initialValue) / inkrement + 1; // total number of iterations
int chunkSize = 0; // number of iterations per chunk int chunkSize = 0; // number of iterations per chunk
SIZE_T dwStackSize = 0; // initital stack size of each thread. 0 means default size ~1MB SIZE_T dwStackSize = 0; // initital stack size of each thread. 0 means default size ~1MB
ForLoop *forLoopParameters = new ForLoop[numThreads]; // ForLoop *forLoopParameters = new ForLoop[numThreads]; //
// globals // globals
termineAllThreads = false; termineAllThreads = false;
// create threads // 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].pParameter = (pParameter != nullptr ? (void *)(((char *)pParameter) + curThreadNo * parameterStructSize) : nullptr);
forLoopParameters[curThreadNo].threadManager = this; forLoopParameters[curThreadNo].threadManager = this;
@ -298,12 +336,16 @@ unsigned int ThreadManager::executeParallelLoop(DWORD threadProc(void *pParam
forLoopParameters[curThreadNo].inkrement = inkrement; forLoopParameters[curThreadNo].inkrement = inkrement;
forLoopParameters[curThreadNo].scheduleType = scheduleType; forLoopParameters[curThreadNo].scheduleType = scheduleType;
switch (scheduleType) { switch (scheduleType)
{
case TM_SCHEDULE_STATIC: case TM_SCHEDULE_STATIC:
chunkSize = numIterations / numThreads + (curThreadNo < numIterations %numThreads ? 1 : 0); chunkSize = numIterations / numThreads + (curThreadNo < numIterations % numThreads ? 1 : 0);
if (curThreadNo == 0) { if (curThreadNo == 0)
{
forLoopParameters[curThreadNo].initialValue = initialValue; forLoopParameters[curThreadNo].initialValue = initialValue;
} else { }
else
{
forLoopParameters[curThreadNo].initialValue = forLoopParameters[curThreadNo - 1].finalValue + 1; forLoopParameters[curThreadNo].initialValue = forLoopParameters[curThreadNo - 1].finalValue + 1;
} }
forLoopParameters[curThreadNo].finalValue = forLoopParameters[curThreadNo].initialValue + chunkSize - 1; forLoopParameters[curThreadNo].finalValue = forLoopParameters[curThreadNo].initialValue + chunkSize - 1;
@ -322,8 +364,10 @@ unsigned int ThreadManager::executeParallelLoop(DWORD threadProc(void *pParam
// create suspended thread // create suspended thread
hThread[curThreadNo] = CreateThread(nullptr, dwStackSize, threadForLoop, (LPVOID)(&forLoopParameters[curThreadNo]), CREATE_SUSPENDED, &threadId[curThreadNo]); hThread[curThreadNo] = CreateThread(nullptr, dwStackSize, threadForLoop, (LPVOID)(&forLoopParameters[curThreadNo]), CREATE_SUSPENDED, &threadId[curThreadNo]);
SetThreadPriority(hThread[curThreadNo], THREAD_PRIORITY_BELOW_NORMAL); SetThreadPriority(hThread[curThreadNo], THREAD_PRIORITY_BELOW_NORMAL);
if (hThread[curThreadNo] == nullptr) { if (hThread[curThreadNo] == nullptr)
for (curThreadNo; curThreadNo > 0; curThreadNo--) { {
for (curThreadNo; curThreadNo > 0; curThreadNo--)
{
CloseHandle(hThread[curThreadNo - 1]); CloseHandle(hThread[curThreadNo - 1]);
hThread[curThreadNo - 1] = nullptr; 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 // start threads, but don't resume if in pause mode
for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) { for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++)
if (!executionPaused) ResumeThread(hThread[curThreadNo]); {
if (!executionPaused)
ResumeThread(hThread[curThreadNo]);
} }
// wait for every thread to end // wait for every thread to end
WaitForMultipleObjects(numThreads, hThread, TRUE, INFINITE); WaitForMultipleObjects(numThreads, hThread, TRUE, INFINITE);
// Close all thread handles upon completion. // Close all thread handles upon completion.
for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) { for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++)
{
CloseHandle(hThread[curThreadNo]); CloseHandle(hThread[curThreadNo]);
hThread[curThreadNo] = nullptr; hThread[curThreadNo] = nullptr;
threadId[curThreadNo] = 0; threadId[curThreadNo] = 0;
@ -350,27 +397,33 @@ unsigned int ThreadManager::executeParallelLoop(DWORD threadProc(void *pParam
delete[] forLoopParameters; delete[] forLoopParameters;
// everything ok // everything ok
if (executionCancelled) { if (executionCancelled)
{
return TM_RETURN_VALUE_EXECUTION_CANCELLED; return TM_RETURN_VALUE_EXECUTION_CANCELLED;
} else { }
else
{
return TM_RETURN_VALUE_OK; return TM_RETURN_VALUE_OK;
} }
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Name: threadForLoop() // Name: threadForLoop()
// Desc: // Desc:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
DWORD WINAPI ThreadManager::threadForLoop(LPVOID lpParameter) DWORD WINAPI ThreadManager::threadForLoop(LPVOID lpParameter)
{ {
// locals // locals
ForLoop *forLoopParameters = (ForLoop *)lpParameter; ForLoop *forLoopParameters = (ForLoop *)lpParameter;
int index; int index;
switch (forLoopParameters->scheduleType) { switch (forLoopParameters->scheduleType)
{
case TM_SCHEDULE_STATIC: case TM_SCHEDULE_STATIC:
for (index = forLoopParameters->initialValue; (forLoopParameters->inkrement < 0) ? index >= forLoopParameters->finalValue : index <= forLoopParameters->finalValue; index += forLoopParameters->inkrement) { for (index = forLoopParameters->initialValue; (forLoopParameters->inkrement < 0) ? index >= forLoopParameters->finalValue : index <= forLoopParameters->finalValue; index += forLoopParameters->inkrement)
switch (forLoopParameters->threadProc(forLoopParameters->pParameter, index)) { {
switch (forLoopParameters->threadProc(forLoopParameters->pParameter, index))
{
case TM_RETURN_VALUE_OK: case TM_RETURN_VALUE_OK:
break; break;
case TM_RETURN_VALUE_TERMINATE_ALL_THREADS: case TM_RETURN_VALUE_TERMINATE_ALL_THREADS:
@ -379,7 +432,8 @@ DWORD WINAPI ThreadManager::threadForLoop(LPVOID lpParameter)
default: default:
break; break;
} }
if (forLoopParameters->threadManager->termineAllThreads) break; if (forLoopParameters->threadManager->termineAllThreads)
break;
} }
break; break;
case TM_SCHEDULE_DYNAMIC: case TM_SCHEDULE_DYNAMIC:
@ -397,6 +451,6 @@ DWORD WINAPI ThreadManager::threadForLoop(LPVOID lpParameter)
} }
/*** To Do's ******************************************************************************** /*** To Do's ********************************************************************************
- Beschränkung auf 'int' kann zu Überlauf hren, wenn mehr states in einer layer vorliegen. - Beschr<EFBFBD>nkung auf 'int' kann zu <EFBFBD>berlauf f<EFBFBD>hren, wenn mehr states in einer layer vorliegen.
==> Vielleicht mit class templates arbeiten ==> Vielleicht mit class templates arbeiten
*********************************************************************************************/ *********************************************************************************************/

View File

@ -14,21 +14,21 @@
#include <cstdio> #include <cstdio>
#include <iostream> #include <iostream>
using namespace std; // use standard library namespace using namespace std; // use standard library namespace
/*** Konstanten ******************************************************/ /*** Konstanten ******************************************************/
#define TM_SCHEDULE_USER_DEFINED 0 #define TM_SCHEDULE_USER_DEFINED 0
#define TM_SCHEDULE_STATIC 1 #define TM_SCHEDULE_STATIC 1
#define TM_SCHEDULE_DYNAMIC 2 #define TM_SCHEDULE_DYNAMIC 2
#define TM_SCHEDULE_GUIDED 3 #define TM_SCHEDULE_GUIDED 3
#define TM_SCHEDULE_RUNTIME 4 #define TM_SCHEDULE_RUNTIME 4
#define TM_SCHEDULE_NUM_TYPES 5 #define TM_SCHEDULE_NUM_TYPES 5
#define TM_RETURN_VALUE_OK 0 #define TM_RETURN_VALUE_OK 0
#define TM_RETURN_VALUE_TERMINATE_ALL_THREADS 1 #define TM_RETURN_VALUE_TERMINATE_ALL_THREADS 1
#define TM_RETURN_VALUE_EXECUTION_CANCELLED 2 #define TM_RETURN_VALUE_EXECUTION_CANCELLED 2
#define TM_RETURN_VALUE_INVALID_PARAM 3 #define TM_RETURN_VALUE_INVALID_PARAM 3
#define TM_RETURN_VALUE_UNEXPECTED_ERROR 4 #define TM_RETURN_VALUE_UNEXPECTED_ERROR 4
/*** Makros ******************************************************/ /*** Makros ******************************************************/
@ -39,58 +39,52 @@ using namespace std; // use standard library namespace
class ThreadManager class ThreadManager
{ {
private: private:
// structures // structures
struct ForLoop struct ForLoop
{ {
unsigned int scheduleType; unsigned int scheduleType;
int inkrement; int inkrement;
int initialValue; int initialValue;
int finalValue; int finalValue;
void *pParameter; 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; ThreadManager *threadManager;
}; };
// Variables // Variables
unsigned int numThreads; // number of threads unsigned int numThreads; // number of threads
HANDLE *hThread; // array of size 'numThreads' containing the thread handles HANDLE *hThread; // array of size 'numThreads' containing the thread handles
DWORD *threadId; // array of size 'numThreads' containing the thread ids DWORD *threadId; // array of size 'numThreads' containing the thread ids
bool termineAllThreads; bool termineAllThreads;
bool executionPaused; // switch for the bool executionPaused; // switch for the
bool executionCancelled; // true when cancelExecution() was called bool executionCancelled; // true when cancelExecution() was called
// barier stuff // barier stuff
HANDLE hEventBarrierPassedByEveryBody; HANDLE hEventBarrierPassedByEveryBody;
HANDLE *hBarrier; // array of size 'numThreads' containing the event handles for the barrier HANDLE *hBarrier; // array of size 'numThreads' containing the event handles for the barrier
unsigned int numThreadsPassedBarrier; unsigned int numThreadsPassedBarrier;
CRITICAL_SECTION csBarrier; CRITICAL_SECTION csBarrier;
// functions // functions
static DWORD WINAPI threadForLoop(LPVOID lpParameter); static DWORD WINAPI threadForLoop(LPVOID lpParameter);
public: public:
class ThreadVarsArrayItem class ThreadVarsArrayItem
{ {
public: public:
unsigned int curThreadNo; unsigned int curThreadNo;
virtual void initializeElement() virtual void initializeElement(){};
{ virtual void destroyElement(){};
}; virtual void reduce(){};
virtual void destroyElement()
{
};
virtual void reduce()
{
};
}; };
template <class varType> class ThreadVarsArray template <class varType>
class ThreadVarsArray
{ {
public: public:
unsigned int numberOfThreads; unsigned int numberOfThreads;
varType *item; varType *item;
ThreadVarsArray(unsigned int numberOfThreads, varType &master) ThreadVarsArray(unsigned int numberOfThreads, varType &master)
@ -98,16 +92,18 @@ public:
this->numberOfThreads = numberOfThreads; this->numberOfThreads = numberOfThreads;
this->item = new varType[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].curThreadNo = threadCounter;
item[threadCounter].initializeElement(master); 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() ~ThreadVarsArray()
{ {
for (unsigned int threadCounter = 0; threadCounter < numberOfThreads; threadCounter++) { for (unsigned int threadCounter = 0; threadCounter < numberOfThreads; threadCounter++)
{
item[threadCounter].destroyElement(); item[threadCounter].destroyElement();
} }
delete[] item; delete[] item;
@ -125,7 +121,8 @@ public:
void reduce() void reduce()
{ {
for (unsigned int threadCounter = 0; threadCounter < numberOfThreads; threadCounter++) { for (unsigned int threadCounter = 0; threadCounter < numberOfThreads; threadCounter++)
{
item[threadCounter].reduce(); item[threadCounter].reduce();
} }
}; };
@ -136,20 +133,20 @@ public:
~ThreadManager(); ~ThreadManager();
// Functions // Functions
unsigned int getThreadNumber(); unsigned int getThreadNumber();
unsigned int getNumThreads(); unsigned int getNumThreads();
bool setNumThreads(unsigned int newNumThreads); bool setNumThreads(unsigned int newNumThreads);
void waitForOtherThreads(unsigned int threadNo); void waitForOtherThreads(unsigned int threadNo);
void pauseExecution(); // un-/suspend all threads void pauseExecution(); // un-/suspend all threads
void cancelExecution(); // termineAllThreads auf true void cancelExecution(); // termineAllThreads auf true
bool wasExecutionCancelled(); bool wasExecutionCancelled();
void uncancelExecution(); // sets executionCancelled to false, otherwise executeParellelLoop returns immediatelly 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 //... 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 // execute
unsigned int executeInParallel(DWORD threadProc(void *pParameter), void *pParameter, unsigned int parameterStructSize); 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 executeParallelLoop(DWORD threadProc(void *pParameter, int index), void *pParameter, unsigned int parameterStructSize, unsigned int scheduleType, int initialValue, int finalValue, int inkrement);
}; };
#endif #endif