perfect: Format code with vscode
This commit is contained in:
parent
50b9574101
commit
5c71717a9c
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
@ -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
|
|
@ -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;
|
||||||
|
|
|
@ -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++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
|
@ -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
|
@ -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
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 fü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
|
||||||
*********************************************************************************************/
|
*********************************************************************************************/
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue