perfect: Format code with msvc
This commit is contained in:
parent
5c71717a9c
commit
f74762d2c7
|
@ -1,9 +1,9 @@
|
|||
/*********************************************************************
|
||||
bufferedFile.cpp
|
||||
Copyright (c) Thomas Weber. All rights reserved.
|
||||
Copyright (C) 2021 The Sanmill developers (see AUTHORS file)
|
||||
Licensed under the MIT License.
|
||||
https://github.com/madweasel/madweasels-cpp
|
||||
bufferedFile.cpp
|
||||
Copyright (c) Thomas Weber. All rights reserved.
|
||||
Copyright (C) 2021 The Sanmill developers (see AUTHORS file)
|
||||
Licensed under the MIT License.
|
||||
https://github.com/madweasel/madweasels-cpp
|
||||
\*********************************************************************/
|
||||
|
||||
#include "bufferedFile.h"
|
||||
|
@ -14,40 +14,38 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
BufferedFile::BufferedFile(unsigned int numberOfThreads, unsigned int bufferSizeInBytes, const char *fileName)
|
||||
{
|
||||
// locals
|
||||
unsigned int curThread;
|
||||
// locals
|
||||
unsigned int curThread;
|
||||
|
||||
// Init blocks
|
||||
bufferSize = bufferSizeInBytes;
|
||||
numThreads = numberOfThreads;
|
||||
readBuffer = new unsigned char[numThreads * bufferSize];
|
||||
writeBuffer = new unsigned char[numThreads * bufferSize];
|
||||
curWritingPointer = new long long[numThreads];
|
||||
curReadingPointer = new long long[numThreads];
|
||||
bytesInReadBuffer = new unsigned int[numThreads];
|
||||
bytesInWriteBuffer = new unsigned int[numThreads];
|
||||
// Init blocks
|
||||
bufferSize = bufferSizeInBytes;
|
||||
numThreads = numberOfThreads;
|
||||
readBuffer = new unsigned char[numThreads * bufferSize];
|
||||
writeBuffer = new unsigned char[numThreads * bufferSize];
|
||||
curWritingPointer = new long long[numThreads];
|
||||
curReadingPointer = new long long[numThreads];
|
||||
bytesInReadBuffer = new unsigned int[numThreads];
|
||||
bytesInWriteBuffer = new unsigned int[numThreads];
|
||||
|
||||
for (curThread = 0; curThread < numThreads; curThread++)
|
||||
{
|
||||
curReadingPointer[curThread] = 0;
|
||||
curWritingPointer[curThread] = 0;
|
||||
bytesInReadBuffer[curThread] = 0;
|
||||
bytesInWriteBuffer[curThread] = 0;
|
||||
}
|
||||
InitializeCriticalSection(&csIO);
|
||||
for (curThread = 0; curThread < numThreads; curThread++) {
|
||||
curReadingPointer[curThread] = 0;
|
||||
curWritingPointer[curThread] = 0;
|
||||
bytesInReadBuffer[curThread] = 0;
|
||||
bytesInWriteBuffer[curThread] = 0;
|
||||
}
|
||||
InitializeCriticalSection(&csIO);
|
||||
|
||||
// Open Database-File (FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_RANDOM_ACCESS)
|
||||
hFile = CreateFileA(fileName, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
// Open Database-File (FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_RANDOM_ACCESS)
|
||||
hFile = CreateFileA(fileName, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
|
||||
// opened file succesfully
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
hFile = nullptr;
|
||||
return;
|
||||
}
|
||||
// opened file succesfully
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
hFile = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
// update file size
|
||||
getFileSize();
|
||||
// update file size
|
||||
getFileSize();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -56,21 +54,21 @@ BufferedFile::BufferedFile(unsigned int numberOfThreads, unsigned int bufferSize
|
|||
//-----------------------------------------------------------------------------
|
||||
BufferedFile::~BufferedFile()
|
||||
{
|
||||
// flush buffers
|
||||
flushBuffers();
|
||||
DeleteCriticalSection(&csIO);
|
||||
// flush buffers
|
||||
flushBuffers();
|
||||
DeleteCriticalSection(&csIO);
|
||||
|
||||
// delete arrays
|
||||
delete[] readBuffer;
|
||||
delete[] writeBuffer;
|
||||
delete[] curReadingPointer;
|
||||
delete[] curWritingPointer;
|
||||
delete[] bytesInReadBuffer;
|
||||
delete[] bytesInWriteBuffer;
|
||||
// delete arrays
|
||||
delete[] readBuffer;
|
||||
delete[] writeBuffer;
|
||||
delete[] curReadingPointer;
|
||||
delete[] curWritingPointer;
|
||||
delete[] bytesInReadBuffer;
|
||||
delete[] bytesInWriteBuffer;
|
||||
|
||||
// close file
|
||||
if (hFile != nullptr)
|
||||
CloseHandle(hFile);
|
||||
// close file
|
||||
if (hFile != nullptr)
|
||||
CloseHandle(hFile);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -79,10 +77,10 @@ BufferedFile::~BufferedFile()
|
|||
//-----------------------------------------------------------------------------
|
||||
long long BufferedFile::getFileSize()
|
||||
{
|
||||
LARGE_INTEGER liFileSize;
|
||||
GetFileSizeEx(hFile, &liFileSize);
|
||||
fileSize = liFileSize.QuadPart;
|
||||
return fileSize;
|
||||
LARGE_INTEGER liFileSize;
|
||||
GetFileSizeEx(hFile, &liFileSize);
|
||||
fileSize = liFileSize.QuadPart;
|
||||
return fileSize;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -91,12 +89,11 @@ long long BufferedFile::getFileSize()
|
|||
//-----------------------------------------------------------------------------
|
||||
bool BufferedFile::flushBuffers()
|
||||
{
|
||||
for (unsigned int threadNo = 0; threadNo < numThreads; threadNo++)
|
||||
{
|
||||
writeDataToFile(hFile, curWritingPointer[threadNo] - bytesInWriteBuffer[threadNo], bytesInWriteBuffer[threadNo], &writeBuffer[threadNo * bufferSize + 0]);
|
||||
bytesInWriteBuffer[threadNo] = 0;
|
||||
}
|
||||
return true;
|
||||
for (unsigned int threadNo = 0; threadNo < numThreads; threadNo++) {
|
||||
writeDataToFile(hFile, curWritingPointer[threadNo] - bytesInWriteBuffer[threadNo], bytesInWriteBuffer[threadNo], &writeBuffer[threadNo * bufferSize + 0]);
|
||||
bytesInWriteBuffer[threadNo] = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -105,33 +102,29 @@ bool BufferedFile::flushBuffers()
|
|||
//-----------------------------------------------------------------------------
|
||||
void BufferedFile::writeDataToFile(HANDLE hFile, long long offset, unsigned int sizeInBytes, void *pData)
|
||||
{
|
||||
DWORD dwBytesWritten;
|
||||
LARGE_INTEGER liDistanceToMove;
|
||||
unsigned int restingBytes = sizeInBytes;
|
||||
DWORD dwBytesWritten;
|
||||
LARGE_INTEGER liDistanceToMove;
|
||||
unsigned int restingBytes = sizeInBytes;
|
||||
|
||||
liDistanceToMove.QuadPart = offset;
|
||||
liDistanceToMove.QuadPart = offset;
|
||||
|
||||
EnterCriticalSection(&csIO);
|
||||
while (!SetFilePointerEx(hFile, liDistanceToMove, nullptr, FILE_BEGIN))
|
||||
cout << endl
|
||||
<< "SetFilePointerEx failed!";
|
||||
while (restingBytes > 0)
|
||||
{
|
||||
if (WriteFile(hFile, pData, sizeInBytes, &dwBytesWritten, nullptr) == TRUE)
|
||||
{
|
||||
restingBytes -= dwBytesWritten;
|
||||
pData = (void *)(((unsigned char *)pData) + dwBytesWritten);
|
||||
if (restingBytes > 0)
|
||||
cout << endl
|
||||
<< "Still " << restingBytes << " to write!";
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << endl
|
||||
<< "WriteFile Failed!";
|
||||
}
|
||||
}
|
||||
LeaveCriticalSection(&csIO);
|
||||
EnterCriticalSection(&csIO);
|
||||
while (!SetFilePointerEx(hFile, liDistanceToMove, nullptr, FILE_BEGIN))
|
||||
cout << endl
|
||||
<< "SetFilePointerEx failed!";
|
||||
while (restingBytes > 0) {
|
||||
if (WriteFile(hFile, pData, sizeInBytes, &dwBytesWritten, nullptr) == TRUE) {
|
||||
restingBytes -= dwBytesWritten;
|
||||
pData = (void *)(((unsigned char *)pData) + dwBytesWritten);
|
||||
if (restingBytes > 0)
|
||||
cout << endl
|
||||
<< "Still " << restingBytes << " to write!";
|
||||
} else {
|
||||
cout << endl
|
||||
<< "WriteFile Failed!";
|
||||
}
|
||||
}
|
||||
LeaveCriticalSection(&csIO);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -140,33 +133,29 @@ void BufferedFile::writeDataToFile(HANDLE hFile, long long offset, unsigned int
|
|||
//-----------------------------------------------------------------------------
|
||||
void BufferedFile::readDataFromFile(HANDLE hFile, long long offset, unsigned int sizeInBytes, void *pData)
|
||||
{
|
||||
DWORD dwBytesRead;
|
||||
LARGE_INTEGER liDistanceToMove;
|
||||
unsigned int restingBytes = sizeInBytes;
|
||||
DWORD dwBytesRead;
|
||||
LARGE_INTEGER liDistanceToMove;
|
||||
unsigned int restingBytes = sizeInBytes;
|
||||
|
||||
liDistanceToMove.QuadPart = offset;
|
||||
liDistanceToMove.QuadPart = offset;
|
||||
|
||||
EnterCriticalSection(&csIO);
|
||||
while (!SetFilePointerEx(hFile, liDistanceToMove, nullptr, FILE_BEGIN))
|
||||
cout << endl
|
||||
<< "SetFilePointerEx failed!";
|
||||
while (restingBytes > 0)
|
||||
{
|
||||
if (ReadFile(hFile, pData, sizeInBytes, &dwBytesRead, nullptr) == TRUE)
|
||||
{
|
||||
restingBytes -= dwBytesRead;
|
||||
pData = (void *)(((unsigned char *)pData) + dwBytesRead);
|
||||
if (restingBytes > 0)
|
||||
cout << endl
|
||||
<< "Still " << restingBytes << " to read!";
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << endl
|
||||
<< "ReadFile Failed!";
|
||||
}
|
||||
}
|
||||
LeaveCriticalSection(&csIO);
|
||||
EnterCriticalSection(&csIO);
|
||||
while (!SetFilePointerEx(hFile, liDistanceToMove, nullptr, FILE_BEGIN))
|
||||
cout << endl
|
||||
<< "SetFilePointerEx failed!";
|
||||
while (restingBytes > 0) {
|
||||
if (ReadFile(hFile, pData, sizeInBytes, &dwBytesRead, nullptr) == TRUE) {
|
||||
restingBytes -= dwBytesRead;
|
||||
pData = (void *)(((unsigned char *)pData) + dwBytesRead);
|
||||
if (restingBytes > 0)
|
||||
cout << endl
|
||||
<< "Still " << restingBytes << " to read!";
|
||||
} else {
|
||||
cout << endl
|
||||
<< "ReadFile Failed!";
|
||||
}
|
||||
}
|
||||
LeaveCriticalSection(&csIO);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -175,7 +164,7 @@ void BufferedFile::readDataFromFile(HANDLE hFile, long long offset, unsigned int
|
|||
//-----------------------------------------------------------------------------
|
||||
bool BufferedFile::writeBytes(unsigned int numBytes, unsigned char *pData)
|
||||
{
|
||||
return writeBytes(0, curWritingPointer[0], numBytes, pData);
|
||||
return writeBytes(0, curWritingPointer[0], numBytes, pData);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -184,29 +173,28 @@ bool BufferedFile::writeBytes(unsigned int numBytes, unsigned char *pData)
|
|||
//-----------------------------------------------------------------------------
|
||||
bool BufferedFile::writeBytes(unsigned int threadNo, long long positionInFile, unsigned int numBytes, unsigned char *pData)
|
||||
{
|
||||
// parameters ok?
|
||||
if (threadNo >= numThreads)
|
||||
return false;
|
||||
if (pData == nullptr)
|
||||
return false;
|
||||
// parameters ok?
|
||||
if (threadNo >= numThreads)
|
||||
return false;
|
||||
if (pData == nullptr)
|
||||
return false;
|
||||
|
||||
// locals
|
||||
// locals
|
||||
|
||||
// if buffer full or not sequential write operation write buffer to file
|
||||
if (bytesInWriteBuffer[threadNo] && (positionInFile != curWritingPointer[threadNo] || bytesInWriteBuffer[threadNo] + numBytes >= bufferSize))
|
||||
{
|
||||
// if buffer full or not sequential write operation write buffer to file
|
||||
if (bytesInWriteBuffer[threadNo] && (positionInFile != curWritingPointer[threadNo] || bytesInWriteBuffer[threadNo] + numBytes >= bufferSize)) {
|
||||
|
||||
writeDataToFile(hFile, curWritingPointer[threadNo] - bytesInWriteBuffer[threadNo], bytesInWriteBuffer[threadNo], &writeBuffer[threadNo * bufferSize + 0]);
|
||||
bytesInWriteBuffer[threadNo] = 0;
|
||||
}
|
||||
writeDataToFile(hFile, curWritingPointer[threadNo] - bytesInWriteBuffer[threadNo], bytesInWriteBuffer[threadNo], &writeBuffer[threadNo * bufferSize + 0]);
|
||||
bytesInWriteBuffer[threadNo] = 0;
|
||||
}
|
||||
|
||||
// copy data into buffer
|
||||
memcpy(&writeBuffer[threadNo * bufferSize + bytesInWriteBuffer[threadNo]], pData, numBytes);
|
||||
bytesInWriteBuffer[threadNo] += numBytes;
|
||||
curWritingPointer[threadNo] = positionInFile + numBytes;
|
||||
// copy data into buffer
|
||||
memcpy(&writeBuffer[threadNo * bufferSize + bytesInWriteBuffer[threadNo]], pData, numBytes);
|
||||
bytesInWriteBuffer[threadNo] += numBytes;
|
||||
curWritingPointer[threadNo] = positionInFile + numBytes;
|
||||
|
||||
// everything ok
|
||||
return true;
|
||||
// everything ok
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -215,7 +203,7 @@ bool BufferedFile::writeBytes(unsigned int threadNo, long long positionInFile, u
|
|||
//-----------------------------------------------------------------------------
|
||||
bool BufferedFile::readBytes(unsigned int numBytes, unsigned char *pData)
|
||||
{
|
||||
return readBytes(0, curReadingPointer[0], numBytes, pData);
|
||||
return readBytes(0, curReadingPointer[0], numBytes, pData);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -224,24 +212,23 @@ bool BufferedFile::readBytes(unsigned int numBytes, unsigned char *pData)
|
|||
//-----------------------------------------------------------------------------
|
||||
bool BufferedFile::readBytes(unsigned int threadNo, long long positionInFile, unsigned int numBytes, unsigned char *pData)
|
||||
{
|
||||
// parameters ok?
|
||||
if (threadNo >= numThreads)
|
||||
return false;
|
||||
if (pData == nullptr)
|
||||
return false;
|
||||
// parameters ok?
|
||||
if (threadNo >= numThreads)
|
||||
return false;
|
||||
if (pData == nullptr)
|
||||
return false;
|
||||
|
||||
// read from file into buffer if not enough data in buffer or if it is not an sequential reading operation?
|
||||
if (positionInFile != curReadingPointer[threadNo] || bytesInReadBuffer[threadNo] < numBytes)
|
||||
{
|
||||
bytesInReadBuffer[threadNo] = ((positionInFile + bufferSize <= fileSize) ? bufferSize : (unsigned int)(fileSize - positionInFile));
|
||||
if (bytesInReadBuffer[threadNo] < numBytes)
|
||||
return false;
|
||||
readDataFromFile(hFile, positionInFile, bytesInReadBuffer[threadNo], &readBuffer[threadNo * bufferSize + bufferSize - bytesInReadBuffer[threadNo]]);
|
||||
}
|
||||
memcpy(pData, &readBuffer[threadNo * bufferSize + bufferSize - bytesInReadBuffer[threadNo]], numBytes);
|
||||
bytesInReadBuffer[threadNo] -= numBytes;
|
||||
curReadingPointer[threadNo] = positionInFile + numBytes;
|
||||
// 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) {
|
||||
bytesInReadBuffer[threadNo] = ((positionInFile + bufferSize <= fileSize) ? bufferSize : (unsigned int)(fileSize - positionInFile));
|
||||
if (bytesInReadBuffer[threadNo] < numBytes)
|
||||
return false;
|
||||
readDataFromFile(hFile, positionInFile, bytesInReadBuffer[threadNo], &readBuffer[threadNo * bufferSize + bufferSize - bytesInReadBuffer[threadNo]]);
|
||||
}
|
||||
memcpy(pData, &readBuffer[threadNo * bufferSize + bufferSize - bytesInReadBuffer[threadNo]], numBytes);
|
||||
bytesInReadBuffer[threadNo] -= numBytes;
|
||||
curReadingPointer[threadNo] = positionInFile + numBytes;
|
||||
|
||||
// everything ok
|
||||
return true;
|
||||
// everything ok
|
||||
return true;
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
/*********************************************************************\
|
||||
bufferedFile.h
|
||||
Copyright (c) Thomas Weber. All rights reserved.
|
||||
Copyright (C) 2021 The Sanmill developers (see AUTHORS file)
|
||||
Licensed under the MIT License.
|
||||
https://github.com/madweasel/madweasels-cpp
|
||||
bufferedFile.h
|
||||
Copyright (c) Thomas Weber. All rights reserved.
|
||||
Copyright (C) 2021 The Sanmill developers (see AUTHORS file)
|
||||
Licensed under the MIT License.
|
||||
https://github.com/madweasel/madweasels-cpp
|
||||
\*********************************************************************/
|
||||
|
||||
#ifndef BUFFERED_FILE_H
|
||||
|
@ -20,35 +20,35 @@ using namespace std;
|
|||
class BufferedFile
|
||||
{
|
||||
private:
|
||||
// Variables
|
||||
HANDLE hFile; // Handle of the file
|
||||
unsigned int numThreads; // number of threads
|
||||
unsigned char *readBuffer; // Array of size [numThreads*blockSize] containing the data of the block, where reading is taking place
|
||||
unsigned char *writeBuffer; // '' - access by [threadNo*bufferSize+position]
|
||||
long long *curReadingPointer; // array of size [numThreads] with pointers to the byte which is currently read
|
||||
long long *curWritingPointer; // ''
|
||||
unsigned int *bytesInReadBuffer; //
|
||||
unsigned int *bytesInWriteBuffer; //
|
||||
unsigned int bufferSize; // size in bytes of a buffer
|
||||
long long fileSize; // size in bytes
|
||||
CRITICAL_SECTION csIO;
|
||||
// Variables
|
||||
HANDLE hFile; // Handle of the file
|
||||
unsigned int numThreads; // number of threads
|
||||
unsigned char *readBuffer; // Array of size [numThreads*blockSize] containing the data of the block, where reading is taking place
|
||||
unsigned char *writeBuffer; // '' - access by [threadNo*bufferSize+position]
|
||||
long long *curReadingPointer; // array of size [numThreads] with pointers to the byte which is currently read
|
||||
long long *curWritingPointer; // ''
|
||||
unsigned int *bytesInReadBuffer; //
|
||||
unsigned int *bytesInWriteBuffer; //
|
||||
unsigned int bufferSize; // size in bytes of a buffer
|
||||
long long fileSize; // size in bytes
|
||||
CRITICAL_SECTION csIO;
|
||||
|
||||
// Functions
|
||||
void writeDataToFile(HANDLE hFile, long long offset, unsigned int sizeInBytes, void *pData);
|
||||
void readDataFromFile(HANDLE hFile, long long offset, unsigned int sizeInBytes, void *pData);
|
||||
// Functions
|
||||
void writeDataToFile(HANDLE hFile, long long offset, unsigned int sizeInBytes, void *pData);
|
||||
void readDataFromFile(HANDLE hFile, long long offset, unsigned int sizeInBytes, void *pData);
|
||||
|
||||
public:
|
||||
// Constructor / destructor
|
||||
BufferedFile(unsigned int numThreads, unsigned int bufferSizeInBytes, const char *fileName);
|
||||
~BufferedFile();
|
||||
// Constructor / destructor
|
||||
BufferedFile(unsigned int numThreads, unsigned int bufferSizeInBytes, const char *fileName);
|
||||
~BufferedFile();
|
||||
|
||||
// Functions
|
||||
bool flushBuffers();
|
||||
bool writeBytes(unsigned int numBytes, unsigned char *pData);
|
||||
bool readBytes(unsigned int numBytes, unsigned char *pData);
|
||||
bool writeBytes(unsigned int threadNo, long long positionInFile, unsigned int numBytes, unsigned char *pData);
|
||||
bool readBytes(unsigned int threadNo, long long positionInFile, unsigned int numBytes, unsigned char *pData);
|
||||
long long getFileSize();
|
||||
// Functions
|
||||
bool flushBuffers();
|
||||
bool writeBytes(unsigned int numBytes, unsigned char *pData);
|
||||
bool readBytes(unsigned int numBytes, unsigned char *pData);
|
||||
bool writeBytes(unsigned int threadNo, long long positionInFile, unsigned int numBytes, unsigned char *pData);
|
||||
bool readBytes(unsigned int threadNo, long long positionInFile, unsigned int numBytes, unsigned char *pData);
|
||||
long long getFileSize();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
/*********************************************************************\
|
||||
config.h
|
||||
Copyright (c) Thomas Weber. All rights reserved.
|
||||
Copyright (C) 2021 The Sanmill developers (see AUTHORS file)
|
||||
Licensed under the MIT License.
|
||||
https://github.com/madweasel/madweasels-cpp
|
||||
config.h
|
||||
Copyright (c) Thomas Weber. All rights reserved.
|
||||
Copyright (C) 2021 The Sanmill developers (see AUTHORS file)
|
||||
Licensed under the MIT License.
|
||||
https://github.com/madweasel/madweasels-cpp
|
||||
\*********************************************************************/
|
||||
|
||||
#ifndef CONFIG_H
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
/*********************************************************************
|
||||
CyclicArray.cpp
|
||||
Copyright (c) Thomas Weber. All rights reserved.
|
||||
Copyright (C) 2021 The Sanmill developers (see AUTHORS file)
|
||||
Licensed under the MIT License.
|
||||
https://github.com/madweasel/madweasels-cpp
|
||||
CyclicArray.cpp
|
||||
Copyright (c) Thomas Weber. All rights reserved.
|
||||
Copyright (C) 2021 The Sanmill developers (see AUTHORS file)
|
||||
Licensed under the MIT License.
|
||||
https://github.com/madweasel/madweasels-cpp
|
||||
\*********************************************************************/
|
||||
|
||||
#include "cyclicArray.h"
|
||||
|
@ -14,26 +14,25 @@
|
|||
//-----------------------------F------------------------------------------------
|
||||
CyclicArray::CyclicArray(unsigned int blockSizeInBytes, unsigned int numberOfBlocks, const char *fileName)
|
||||
{
|
||||
// Init blocks
|
||||
blockSize = blockSizeInBytes;
|
||||
numBlocks = numberOfBlocks;
|
||||
readingBlock = new unsigned char[blockSize];
|
||||
writingBlock = new unsigned char[blockSize];
|
||||
curReadingPointer = writingBlock;
|
||||
curWritingPointer = writingBlock;
|
||||
readWriteInSameRound = true;
|
||||
curReadingBlock = 0;
|
||||
curWritingBlock = 0;
|
||||
// Init blocks
|
||||
blockSize = blockSizeInBytes;
|
||||
numBlocks = numberOfBlocks;
|
||||
readingBlock = new unsigned char[blockSize];
|
||||
writingBlock = new unsigned char[blockSize];
|
||||
curReadingPointer = writingBlock;
|
||||
curWritingPointer = writingBlock;
|
||||
readWriteInSameRound = true;
|
||||
curReadingBlock = 0;
|
||||
curWritingBlock = 0;
|
||||
|
||||
// Open Database-File (FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_RANDOM_ACCESS)
|
||||
hFile = CreateFileA(fileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
// Open Database-File (FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_RANDOM_ACCESS)
|
||||
hFile = CreateFileA(fileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
|
||||
// opened file succesfully
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
hFile = nullptr;
|
||||
return;
|
||||
}
|
||||
// opened file succesfully
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
hFile = nullptr;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -42,13 +41,13 @@ CyclicArray::CyclicArray(unsigned int blockSizeInBytes, unsigned int numberOfBlo
|
|||
//-----------------------------------------------------------------------------
|
||||
CyclicArray::~CyclicArray()
|
||||
{
|
||||
// delete arrays
|
||||
delete[] readingBlock;
|
||||
delete[] writingBlock;
|
||||
// delete arrays
|
||||
delete[] readingBlock;
|
||||
delete[] writingBlock;
|
||||
|
||||
// close file
|
||||
if (hFile != nullptr)
|
||||
CloseHandle(hFile);
|
||||
// close file
|
||||
if (hFile != nullptr)
|
||||
CloseHandle(hFile);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -57,32 +56,28 @@ CyclicArray::~CyclicArray()
|
|||
//-----------------------------------------------------------------------------
|
||||
void CyclicArray::writeDataToFile(HANDLE hFile, long long offset, unsigned int sizeInBytes, void *pData)
|
||||
{
|
||||
DWORD dwBytesWritten;
|
||||
LARGE_INTEGER liDistanceToMove;
|
||||
unsigned int restingBytes = sizeInBytes;
|
||||
DWORD dwBytesWritten;
|
||||
LARGE_INTEGER liDistanceToMove;
|
||||
unsigned int restingBytes = sizeInBytes;
|
||||
|
||||
liDistanceToMove.QuadPart = offset;
|
||||
liDistanceToMove.QuadPart = offset;
|
||||
|
||||
while (!SetFilePointerEx(hFile, liDistanceToMove, nullptr, FILE_BEGIN))
|
||||
cout << endl
|
||||
<< "SetFilePointerEx failed!";
|
||||
while (!SetFilePointerEx(hFile, liDistanceToMove, nullptr, FILE_BEGIN))
|
||||
cout << endl
|
||||
<< "SetFilePointerEx failed!";
|
||||
|
||||
while (restingBytes > 0)
|
||||
{
|
||||
if (WriteFile(hFile, pData, sizeInBytes, &dwBytesWritten, nullptr) == TRUE)
|
||||
{
|
||||
restingBytes -= dwBytesWritten;
|
||||
pData = (void *)(((unsigned char *)pData) + dwBytesWritten);
|
||||
if (restingBytes > 0)
|
||||
cout << endl
|
||||
<< "Still " << restingBytes << " to write!";
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << endl
|
||||
<< "WriteFile Failed!";
|
||||
}
|
||||
}
|
||||
while (restingBytes > 0) {
|
||||
if (WriteFile(hFile, pData, sizeInBytes, &dwBytesWritten, nullptr) == TRUE) {
|
||||
restingBytes -= dwBytesWritten;
|
||||
pData = (void *)(((unsigned char *)pData) + dwBytesWritten);
|
||||
if (restingBytes > 0)
|
||||
cout << endl
|
||||
<< "Still " << restingBytes << " to write!";
|
||||
} else {
|
||||
cout << endl
|
||||
<< "WriteFile Failed!";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -91,32 +86,28 @@ void CyclicArray::writeDataToFile(HANDLE hFile, long long offset, unsigned int s
|
|||
//-----------------------------------------------------------------------------
|
||||
void CyclicArray::readDataFromFile(HANDLE hFile, long long offset, unsigned int sizeInBytes, void *pData)
|
||||
{
|
||||
DWORD dwBytesRead;
|
||||
LARGE_INTEGER liDistanceToMove;
|
||||
unsigned int restingBytes = sizeInBytes;
|
||||
DWORD dwBytesRead;
|
||||
LARGE_INTEGER liDistanceToMove;
|
||||
unsigned int restingBytes = sizeInBytes;
|
||||
|
||||
liDistanceToMove.QuadPart = offset;
|
||||
liDistanceToMove.QuadPart = offset;
|
||||
|
||||
while (!SetFilePointerEx(hFile, liDistanceToMove, nullptr, FILE_BEGIN))
|
||||
cout << endl
|
||||
<< "SetFilePointerEx failed!";
|
||||
while (!SetFilePointerEx(hFile, liDistanceToMove, nullptr, FILE_BEGIN))
|
||||
cout << endl
|
||||
<< "SetFilePointerEx failed!";
|
||||
|
||||
while (restingBytes > 0)
|
||||
{
|
||||
if (ReadFile(hFile, pData, sizeInBytes, &dwBytesRead, nullptr) == TRUE)
|
||||
{
|
||||
restingBytes -= dwBytesRead;
|
||||
pData = (void *)(((unsigned char *)pData) + dwBytesRead);
|
||||
if (restingBytes > 0)
|
||||
cout << endl
|
||||
<< "Still " << restingBytes << " to read!";
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << endl
|
||||
<< "ReadFile Failed!";
|
||||
}
|
||||
}
|
||||
while (restingBytes > 0) {
|
||||
if (ReadFile(hFile, pData, sizeInBytes, &dwBytesRead, nullptr) == TRUE) {
|
||||
restingBytes -= dwBytesRead;
|
||||
pData = (void *)(((unsigned char *)pData) + dwBytesRead);
|
||||
if (restingBytes > 0)
|
||||
cout << endl
|
||||
<< "Still " << restingBytes << " to read!";
|
||||
} else {
|
||||
cout << endl
|
||||
<< "ReadFile Failed!";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -126,47 +117,44 @@ void CyclicArray::readDataFromFile(HANDLE hFile, long long offset, unsigned int
|
|||
//-----------------------------------------------------------------------------
|
||||
bool CyclicArray::addBytes(unsigned int numBytes, unsigned char *pData)
|
||||
{
|
||||
// locals
|
||||
unsigned int bytesWritten = 0;
|
||||
// locals
|
||||
unsigned int bytesWritten = 0;
|
||||
|
||||
// write each byte
|
||||
while (bytesWritten < numBytes)
|
||||
{
|
||||
// write each byte
|
||||
while (bytesWritten < numBytes) {
|
||||
|
||||
// store byte in current reading block
|
||||
*curWritingPointer = *pData;
|
||||
curWritingPointer++;
|
||||
bytesWritten++;
|
||||
pData++;
|
||||
// store byte in current reading block
|
||||
*curWritingPointer = *pData;
|
||||
curWritingPointer++;
|
||||
bytesWritten++;
|
||||
pData++;
|
||||
|
||||
// when block is full then save current one to file and begin new one
|
||||
if (curWritingPointer == writingBlock + blockSize)
|
||||
{
|
||||
// when block is full then save current one to file and begin new one
|
||||
if (curWritingPointer == writingBlock + blockSize) {
|
||||
|
||||
// copy data into reading block?
|
||||
if (curReadingBlock == curWritingBlock)
|
||||
{
|
||||
memcpy(readingBlock, writingBlock, blockSize);
|
||||
curReadingPointer = readingBlock + (curReadingPointer - writingBlock);
|
||||
}
|
||||
// copy data into reading block?
|
||||
if (curReadingBlock == curWritingBlock) {
|
||||
memcpy(readingBlock, writingBlock, blockSize);
|
||||
curReadingPointer = readingBlock + (curReadingPointer - writingBlock);
|
||||
}
|
||||
|
||||
// will reading block be overwritten?
|
||||
if (curReadingBlock == curWritingBlock && !readWriteInSameRound)
|
||||
return false;
|
||||
// will reading block be overwritten?
|
||||
if (curReadingBlock == curWritingBlock && !readWriteInSameRound)
|
||||
return false;
|
||||
|
||||
// store bock in file
|
||||
writeDataToFile(hFile, ((long long)blockSize) * ((long long)curWritingBlock), blockSize, writingBlock);
|
||||
// store bock in file
|
||||
writeDataToFile(hFile, ((long long)blockSize) * ((long long)curWritingBlock), blockSize, writingBlock);
|
||||
|
||||
// set pointer to beginnig of writing block
|
||||
curWritingPointer = writingBlock;
|
||||
curWritingBlock = (curWritingBlock + 1) % numBlocks;
|
||||
if (curWritingBlock == 0)
|
||||
readWriteInSameRound = false;
|
||||
}
|
||||
}
|
||||
// set pointer to beginnig of writing block
|
||||
curWritingPointer = writingBlock;
|
||||
curWritingBlock = (curWritingBlock + 1) % numBlocks;
|
||||
if (curWritingBlock == 0)
|
||||
readWriteInSameRound = false;
|
||||
}
|
||||
}
|
||||
|
||||
// everything ok
|
||||
return true;
|
||||
// everything ok
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -175,10 +163,10 @@ bool CyclicArray::addBytes(unsigned int numBytes, unsigned char *pData)
|
|||
//-----------------------------------------------------------------------------
|
||||
bool CyclicArray::bytesAvailable()
|
||||
{
|
||||
if (curReadingBlock == curWritingBlock && curReadingPointer == curWritingPointer && readWriteInSameRound)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
if (curReadingBlock == curWritingBlock && curReadingPointer == curWritingPointer && readWriteInSameRound)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -188,51 +176,46 @@ bool CyclicArray::bytesAvailable()
|
|||
//-----------------------------------------------------------------------------
|
||||
bool CyclicArray::takeBytes(unsigned int numBytes, unsigned char *pData)
|
||||
{
|
||||
// locals
|
||||
unsigned int bytesRead = 0;
|
||||
// locals
|
||||
unsigned int bytesRead = 0;
|
||||
|
||||
// read each byte
|
||||
while (bytesRead < numBytes)
|
||||
{
|
||||
// read each byte
|
||||
while (bytesRead < numBytes) {
|
||||
|
||||
// was current reading byte already written ?
|
||||
if (curReadingBlock == curWritingBlock && curReadingPointer == curWritingPointer && readWriteInSameRound)
|
||||
return false;
|
||||
// was current reading byte already written ?
|
||||
if (curReadingBlock == curWritingBlock && curReadingPointer == curWritingPointer && readWriteInSameRound)
|
||||
return false;
|
||||
|
||||
// read current byte
|
||||
*pData = *curReadingPointer;
|
||||
curReadingPointer++;
|
||||
bytesRead++;
|
||||
pData++;
|
||||
// read current byte
|
||||
*pData = *curReadingPointer;
|
||||
curReadingPointer++;
|
||||
bytesRead++;
|
||||
pData++;
|
||||
|
||||
// load next block?
|
||||
if (curReadingPointer == readingBlock + blockSize)
|
||||
{
|
||||
// load next block?
|
||||
if (curReadingPointer == readingBlock + blockSize) {
|
||||
|
||||
// go to next block
|
||||
curReadingBlock = (curReadingBlock + 1) % numBlocks;
|
||||
if (curReadingBlock == 0)
|
||||
readWriteInSameRound = true;
|
||||
// go to next block
|
||||
curReadingBlock = (curReadingBlock + 1) % numBlocks;
|
||||
if (curReadingBlock == 0)
|
||||
readWriteInSameRound = true;
|
||||
|
||||
// writing block reached ?
|
||||
if (curReadingBlock == curWritingBlock)
|
||||
{
|
||||
curReadingPointer = writingBlock;
|
||||
}
|
||||
else
|
||||
{
|
||||
// writing block reached ?
|
||||
if (curReadingBlock == curWritingBlock) {
|
||||
curReadingPointer = writingBlock;
|
||||
} else {
|
||||
|
||||
// set pointer to beginnig of reading block
|
||||
curReadingPointer = readingBlock;
|
||||
// set pointer to beginnig of reading block
|
||||
curReadingPointer = readingBlock;
|
||||
|
||||
// read whole block from file
|
||||
readDataFromFile(hFile, ((long long)blockSize) * ((long long)curReadingBlock), blockSize, readingBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
// read whole block from file
|
||||
readDataFromFile(hFile, ((long long)blockSize) * ((long long)curReadingBlock), blockSize, readingBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// everything ok
|
||||
return true;
|
||||
// everything ok
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -242,71 +225,68 @@ bool CyclicArray::takeBytes(unsigned int numBytes, unsigned char *pData)
|
|||
//-----------------------------------------------------------------------------
|
||||
bool CyclicArray::loadFile(const char *fileName, LONGLONG &numBytesLoaded)
|
||||
{
|
||||
// locals
|
||||
HANDLE hLoadFile;
|
||||
unsigned char *dataInFile;
|
||||
LARGE_INTEGER largeInt;
|
||||
LONGLONG maxFileSize = ((LONGLONG)blockSize) * ((LONGLONG)numBlocks);
|
||||
LONGLONG curOffset = 0;
|
||||
unsigned int numBlocksInFile;
|
||||
unsigned int curBlock;
|
||||
unsigned int numBytesInLastBlock;
|
||||
numBytesLoaded = 0;
|
||||
// locals
|
||||
HANDLE hLoadFile;
|
||||
unsigned char *dataInFile;
|
||||
LARGE_INTEGER largeInt;
|
||||
LONGLONG maxFileSize = ((LONGLONG)blockSize) * ((LONGLONG)numBlocks);
|
||||
LONGLONG curOffset = 0;
|
||||
unsigned int numBlocksInFile;
|
||||
unsigned int curBlock;
|
||||
unsigned int numBytesInLastBlock;
|
||||
numBytesLoaded = 0;
|
||||
|
||||
// cyclic array file must be open
|
||||
if (hFile == nullptr)
|
||||
return false;
|
||||
// cyclic array file must be open
|
||||
if (hFile == nullptr)
|
||||
return false;
|
||||
|
||||
// Open Database-File (FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_RANDOM_ACCESS)
|
||||
hLoadFile = CreateFileA(fileName, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
// Open Database-File (FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_RANDOM_ACCESS)
|
||||
hLoadFile = CreateFileA(fileName, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
|
||||
// opened file succesfully
|
||||
if (hLoadFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// opened file succesfully
|
||||
if (hLoadFile == INVALID_HANDLE_VALUE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// does data of file fit into cyclic array ?
|
||||
GetFileSizeEx(hLoadFile, &largeInt);
|
||||
// does data of file fit into cyclic array ?
|
||||
GetFileSizeEx(hLoadFile, &largeInt);
|
||||
|
||||
if (maxFileSize < largeInt.QuadPart)
|
||||
{
|
||||
CloseHandle(hLoadFile);
|
||||
return false;
|
||||
}
|
||||
if (maxFileSize < largeInt.QuadPart) {
|
||||
CloseHandle(hLoadFile);
|
||||
return false;
|
||||
}
|
||||
|
||||
// reset
|
||||
curReadingPointer = writingBlock;
|
||||
curWritingPointer = writingBlock;
|
||||
readWriteInSameRound = true;
|
||||
curReadingBlock = 0;
|
||||
curWritingBlock = 0;
|
||||
// reset
|
||||
curReadingPointer = writingBlock;
|
||||
curWritingPointer = writingBlock;
|
||||
readWriteInSameRound = true;
|
||||
curReadingBlock = 0;
|
||||
curWritingBlock = 0;
|
||||
|
||||
numBlocksInFile = (unsigned int)(largeInt.QuadPart / ((LONGLONG)blockSize)) + 1;
|
||||
numBytesInLastBlock = (unsigned int)(largeInt.QuadPart % ((LONGLONG)blockSize));
|
||||
dataInFile = new unsigned char[blockSize];
|
||||
numBlocksInFile = (unsigned int)(largeInt.QuadPart / ((LONGLONG)blockSize)) + 1;
|
||||
numBytesInLastBlock = (unsigned int)(largeInt.QuadPart % ((LONGLONG)blockSize));
|
||||
dataInFile = new unsigned char[blockSize];
|
||||
|
||||
//
|
||||
for (curBlock = 0; curBlock < numBlocksInFile - 1; curBlock++, curOffset += blockSize)
|
||||
{
|
||||
//
|
||||
for (curBlock = 0; curBlock < numBlocksInFile - 1; curBlock++, curOffset += blockSize) {
|
||||
|
||||
// load data from file
|
||||
readDataFromFile(hLoadFile, curOffset, blockSize, dataInFile);
|
||||
// load data from file
|
||||
readDataFromFile(hLoadFile, curOffset, blockSize, dataInFile);
|
||||
|
||||
// put block in cyclic array
|
||||
addBytes(blockSize, dataInFile);
|
||||
}
|
||||
// put block in cyclic array
|
||||
addBytes(blockSize, dataInFile);
|
||||
}
|
||||
|
||||
// last block
|
||||
readDataFromFile(hLoadFile, curOffset, numBytesInLastBlock, dataInFile);
|
||||
addBytes(numBytesInLastBlock, dataInFile);
|
||||
curOffset += numBytesInLastBlock;
|
||||
numBytesLoaded = curOffset;
|
||||
// last block
|
||||
readDataFromFile(hLoadFile, curOffset, numBytesInLastBlock, dataInFile);
|
||||
addBytes(numBytesInLastBlock, dataInFile);
|
||||
curOffset += numBytesInLastBlock;
|
||||
numBytesLoaded = curOffset;
|
||||
|
||||
// everything ok
|
||||
delete[] dataInFile;
|
||||
CloseHandle(hLoadFile);
|
||||
return true;
|
||||
// everything ok
|
||||
delete[] dataInFile;
|
||||
CloseHandle(hLoadFile);
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -316,74 +296,64 @@ bool CyclicArray::loadFile(const char *fileName, LONGLONG &numBytesLoaded)
|
|||
//-----------------------------------------------------------------------------
|
||||
bool CyclicArray::saveFile(const char *fileName)
|
||||
{
|
||||
// locals
|
||||
unsigned char *dataInFile;
|
||||
HANDLE hSaveFile;
|
||||
LONGLONG curOffset;
|
||||
unsigned int curBlock;
|
||||
unsigned int bytesToWrite;
|
||||
void *pointer;
|
||||
// locals
|
||||
unsigned char *dataInFile;
|
||||
HANDLE hSaveFile;
|
||||
LONGLONG curOffset;
|
||||
unsigned int curBlock;
|
||||
unsigned int bytesToWrite;
|
||||
void *pointer;
|
||||
|
||||
// cyclic array file must be open
|
||||
if (hFile == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// cyclic array file must be open
|
||||
if (hFile == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Open Database-File (FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_RANDOM_ACCESS)
|
||||
hSaveFile = CreateFileA(fileName, GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
// Open Database-File (FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_RANDOM_ACCESS)
|
||||
hSaveFile = CreateFileA(fileName, GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
|
||||
// opened file succesfully
|
||||
if (hSaveFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// opened file succesfully
|
||||
if (hSaveFile == INVALID_HANDLE_VALUE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// alloc mem
|
||||
curOffset = 0;
|
||||
curBlock = curReadingBlock;
|
||||
dataInFile = new unsigned char[blockSize];
|
||||
// alloc mem
|
||||
curOffset = 0;
|
||||
curBlock = curReadingBlock;
|
||||
dataInFile = new unsigned char[blockSize];
|
||||
|
||||
do
|
||||
{
|
||||
do {
|
||||
|
||||
// copy current block
|
||||
if (curBlock == curWritingBlock && curBlock == curReadingBlock)
|
||||
{
|
||||
pointer = curReadingPointer;
|
||||
bytesToWrite = (unsigned int)(curWritingPointer - curReadingPointer);
|
||||
}
|
||||
else if (curBlock == curWritingBlock)
|
||||
{
|
||||
pointer = writingBlock;
|
||||
bytesToWrite = (unsigned int)(curWritingPointer - writingBlock);
|
||||
}
|
||||
else if (curBlock == curReadingBlock)
|
||||
{
|
||||
pointer = curReadingPointer;
|
||||
bytesToWrite = blockSize - (unsigned int)(curReadingPointer - readingBlock);
|
||||
}
|
||||
else
|
||||
{
|
||||
readDataFromFile(hFile, ((long long)curBlock) * ((long long)blockSize), blockSize, dataInFile);
|
||||
pointer = dataInFile;
|
||||
bytesToWrite = blockSize;
|
||||
}
|
||||
// copy current block
|
||||
if (curBlock == curWritingBlock && curBlock == curReadingBlock) {
|
||||
pointer = curReadingPointer;
|
||||
bytesToWrite = (unsigned int)(curWritingPointer - curReadingPointer);
|
||||
} else if (curBlock == curWritingBlock) {
|
||||
pointer = writingBlock;
|
||||
bytesToWrite = (unsigned int)(curWritingPointer - writingBlock);
|
||||
} else if (curBlock == curReadingBlock) {
|
||||
pointer = curReadingPointer;
|
||||
bytesToWrite = blockSize - (unsigned int)(curReadingPointer - readingBlock);
|
||||
} else {
|
||||
readDataFromFile(hFile, ((long long)curBlock) * ((long long)blockSize), blockSize, dataInFile);
|
||||
pointer = dataInFile;
|
||||
bytesToWrite = blockSize;
|
||||
}
|
||||
|
||||
// save data to file
|
||||
writeDataToFile(hSaveFile, curOffset, bytesToWrite, pointer);
|
||||
curOffset += bytesToWrite;
|
||||
// save data to file
|
||||
writeDataToFile(hSaveFile, curOffset, bytesToWrite, pointer);
|
||||
curOffset += bytesToWrite;
|
||||
|
||||
// exit?
|
||||
if (curBlock == curWritingBlock)
|
||||
break;
|
||||
else
|
||||
curBlock = (curBlock + 1) % numBlocks;
|
||||
// exit?
|
||||
if (curBlock == curWritingBlock)
|
||||
break;
|
||||
else
|
||||
curBlock = (curBlock + 1) % numBlocks;
|
||||
|
||||
} while (true);
|
||||
} while (true);
|
||||
|
||||
// everything ok
|
||||
delete[] dataInFile;
|
||||
CloseHandle(hSaveFile);
|
||||
return true;
|
||||
// everything ok
|
||||
delete[] dataInFile;
|
||||
CloseHandle(hSaveFile);
|
||||
return true;
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
/*********************************************************************\
|
||||
CyclicArray.h
|
||||
Copyright (c) Thomas Weber. All rights reserved.
|
||||
Copyright (C) 2021 The Sanmill developers (see AUTHORS file)
|
||||
Licensed under the MIT License.
|
||||
https://github.com/madweasel/madweasels-cpp
|
||||
CyclicArray.h
|
||||
Copyright (c) Thomas Weber. All rights reserved.
|
||||
Copyright (C) 2021 The Sanmill developers (see AUTHORS file)
|
||||
Licensed under the MIT License.
|
||||
https://github.com/madweasel/madweasels-cpp
|
||||
\*********************************************************************/
|
||||
|
||||
#ifndef CYLCIC_ARRAY_H
|
||||
|
@ -20,33 +20,33 @@ using namespace std;
|
|||
class CyclicArray
|
||||
{
|
||||
private:
|
||||
// Variables
|
||||
HANDLE hFile; // Handle of the file
|
||||
unsigned char *readingBlock; // Array of size [blockSize] containing the data of the block, where reading is taking place
|
||||
unsigned char *writingBlock; // ''
|
||||
unsigned char *curReadingPointer; // pointer to the byte which is currently read
|
||||
unsigned char *curWritingPointer; // ''
|
||||
unsigned int blockSize; // size in bytes of a block
|
||||
unsigned int curReadingBlock; // index of the block, where reading is taking place
|
||||
unsigned int curWritingBlock; // index of the block, where writing is taking place
|
||||
unsigned int numBlocks; // amount of blocks
|
||||
bool readWriteInSameRound; // true if curReadingBlock > curWritingBlock, false otherwise
|
||||
// Variables
|
||||
HANDLE hFile; // Handle of the file
|
||||
unsigned char *readingBlock; // Array of size [blockSize] containing the data of the block, where reading is taking place
|
||||
unsigned char *writingBlock; // ''
|
||||
unsigned char *curReadingPointer; // pointer to the byte which is currently read
|
||||
unsigned char *curWritingPointer; // ''
|
||||
unsigned int blockSize; // size in bytes of a block
|
||||
unsigned int curReadingBlock; // index of the block, where reading is taking place
|
||||
unsigned int curWritingBlock; // index of the block, where writing is taking place
|
||||
unsigned int numBlocks; // amount of blocks
|
||||
bool readWriteInSameRound; // true if curReadingBlock > curWritingBlock, false otherwise
|
||||
|
||||
// Functions
|
||||
void writeDataToFile(HANDLE hFile, long long offset, unsigned int sizeInBytes, void *pData);
|
||||
void readDataFromFile(HANDLE hFile, long long offset, unsigned int sizeInBytes, void *pData);
|
||||
// Functions
|
||||
void writeDataToFile(HANDLE hFile, long long offset, unsigned int sizeInBytes, void *pData);
|
||||
void readDataFromFile(HANDLE hFile, long long offset, unsigned int sizeInBytes, void *pData);
|
||||
|
||||
public:
|
||||
// Constructor / destructor
|
||||
CyclicArray(unsigned int blockSizeInBytes, unsigned int numberOfBlocks, const char *fileName);
|
||||
~CyclicArray();
|
||||
// Constructor / destructor
|
||||
CyclicArray(unsigned int blockSizeInBytes, unsigned int numberOfBlocks, const char *fileName);
|
||||
~CyclicArray();
|
||||
|
||||
// Functions
|
||||
bool addBytes(unsigned int numBytes, unsigned char *pData);
|
||||
bool takeBytes(unsigned int numBytes, unsigned char *pData);
|
||||
bool loadFile(const char *fileName, LONGLONG &numBytesLoaded);
|
||||
bool saveFile(const char *fileName);
|
||||
bool bytesAvailable();
|
||||
// Functions
|
||||
bool addBytes(unsigned int numBytes, unsigned char *pData);
|
||||
bool takeBytes(unsigned int numBytes, unsigned char *pData);
|
||||
bool loadFile(const char *fileName, LONGLONG &numBytesLoaded);
|
||||
bool saveFile(const char *fileName);
|
||||
bool bytesAvailable();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -36,7 +36,7 @@ int main(void)
|
|||
cout << "*************************" << endl;
|
||||
cout << "* Muehle *" << endl;
|
||||
cout << "*************************" << endl
|
||||
<< endl;
|
||||
<< endl;
|
||||
|
||||
ai->setDatabasePath(databaseDirectory);
|
||||
|
||||
|
@ -47,23 +47,20 @@ int main(void)
|
|||
pos->beginNewGame(ai, ai, (rand() % 2) ? fieldStruct::playerOne : fieldStruct::playerTwo);
|
||||
#endif // SELF_PLAY
|
||||
|
||||
if (calculateDatabase)
|
||||
{
|
||||
if (calculateDatabase) {
|
||||
|
||||
// calculate
|
||||
ai->calculateDatabase(MAX_DEPTH_OF_TREE, false);
|
||||
|
||||
// test database
|
||||
cout << endl
|
||||
<< "Begin test starting from layer: ";
|
||||
<< "Begin test starting from layer: ";
|
||||
startTestFromLayer;
|
||||
cout << endl
|
||||
<< "End test at layer: ";
|
||||
<< "End test at layer: ";
|
||||
endTestAtLayer;
|
||||
ai->testLayers(startTestFromLayer, endTestAtLayer);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
|
||||
#ifdef SELF_PLAY
|
||||
int moveCount = 0;
|
||||
|
@ -79,8 +76,7 @@ int main(void)
|
|||
#endif // SELF_PLAY
|
||||
|
||||
// play
|
||||
do
|
||||
{
|
||||
do {
|
||||
// print board
|
||||
cout << "\n\n\n\n\n\n\n\n\n\n\n";
|
||||
pos->getComputersChoice(&pushFrom, &pushTo);
|
||||
|
@ -89,8 +85,7 @@ int main(void)
|
|||
|
||||
#ifdef SELF_PLAY
|
||||
moveCount++;
|
||||
if (moveCount > 99)
|
||||
{
|
||||
if (moveCount > 99) {
|
||||
goto out;
|
||||
}
|
||||
#endif // SELF_PLAY
|
||||
|
@ -98,10 +93,8 @@ int main(void)
|
|||
pos->printBoard();
|
||||
|
||||
// Human
|
||||
if ((pos->getCurrentPlayer() == fieldStruct::playerOne && playerOneHuman) || (pos->getCurrentPlayer() == fieldStruct::playerTwo && playerTwoHuman))
|
||||
{
|
||||
do
|
||||
{
|
||||
if ((pos->getCurrentPlayer() == fieldStruct::playerOne && playerOneHuman) || (pos->getCurrentPlayer() == fieldStruct::playerTwo && playerTwoHuman)) {
|
||||
do {
|
||||
// Show text
|
||||
if (pos->mustStoneBeRemoved())
|
||||
cout << "\n Which stone do you want to remove? [a-x]: \n\n\n";
|
||||
|
@ -117,15 +110,12 @@ int main(void)
|
|||
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
|
||||
{
|
||||
} else {
|
||||
if ((ch[1] >= 'a') && (ch[1] <= 'x'))
|
||||
pushTo = ch[1] - 'a';
|
||||
else
|
||||
|
@ -133,12 +123,10 @@ int main(void)
|
|||
}
|
||||
|
||||
// undo
|
||||
if (ch[0] == 'u' && ch[1] == 'n' && ch[2] == 'd' && ch[3] == 'o')
|
||||
{
|
||||
if (ch[0] == 'u' && ch[1] == 'n' && ch[2] == 'd' && ch[3] == 'o') {
|
||||
|
||||
// undo moves until a human player shall move
|
||||
do
|
||||
{
|
||||
do {
|
||||
pos->undo_move();
|
||||
} while (!((pos->getCurrentPlayer() == fieldStruct::playerOne && playerOneHuman) || (pos->getCurrentPlayer() == fieldStruct::playerTwo && playerTwoHuman)));
|
||||
|
||||
|
@ -149,9 +137,7 @@ int main(void)
|
|||
} while (pos->do_move(pushFrom, pushTo) == false);
|
||||
|
||||
// Computer
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
cout << "\n";
|
||||
pos->do_move(pushFrom, pushTo);
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
/*********************************************************************
|
||||
millAI.cpp
|
||||
Copyright (c) Thomas Weber. All rights reserved.
|
||||
Copyright (C) 2021 The Sanmill developers (see AUTHORS file)
|
||||
Licensed under the MIT License.
|
||||
https://github.com/madweasel/madweasels-cpp
|
||||
millAI.cpp
|
||||
Copyright (c) Thomas Weber. All rights reserved.
|
||||
Copyright (C) 2021 The Sanmill developers (see AUTHORS file)
|
||||
Licensed under the MIT License.
|
||||
https://github.com/madweasel/madweasels-cpp
|
||||
\*********************************************************************/
|
||||
|
||||
#include "millAI.h"
|
||||
|
@ -16,42 +16,42 @@ using namespace std;
|
|||
//-----------------------------------------------------------------------------
|
||||
void fieldStruct::printBoard()
|
||||
{
|
||||
// locals
|
||||
unsigned int index;
|
||||
char c[fieldStruct::size];
|
||||
// locals
|
||||
unsigned int index;
|
||||
char c[fieldStruct::size];
|
||||
|
||||
for (index = 0; index < fieldStruct::size; index++)
|
||||
c[index] = GetCharFromStone(this->board[index]);
|
||||
for (index = 0; index < fieldStruct::size; index++)
|
||||
c[index] = GetCharFromStone(this->board[index]);
|
||||
|
||||
cout << "current player : " << GetCharFromStone(this->curPlayer->id) << " has " << this->curPlayer->numStones << " stones\n";
|
||||
cout << "opponent player : " << GetCharFromStone(this->oppPlayer->id) << " has " << this->oppPlayer->numStones << " stones\n";
|
||||
cout << "Num Stones to be removed: " << this->stoneMustBeRemoved << "\n";
|
||||
cout << "setting phase : " << (this->settingPhase ? "true" : "false");
|
||||
cout << "\n";
|
||||
cout << "\n a-----b-----c " << c[0] << "-----" << c[1] << "-----" << c[2];
|
||||
cout << "\n | | | "
|
||||
<< "| | |";
|
||||
cout << "\n | d---e---f | "
|
||||
<< "| " << c[3] << "---" << c[4] << "---" << c[5] << " |";
|
||||
cout << "\n | | | | | "
|
||||
<< "| | | | |";
|
||||
cout << "\n | | g-h-i | | "
|
||||
<< "| | " << c[6] << "-" << c[7] << "-" << c[8] << " | |";
|
||||
cout << "\n | | | | | | | "
|
||||
<< "| | | | | |";
|
||||
cout << "\n j-k-l m-n-o " << c[9] << "-" << c[10] << "-" << c[11] << " " << c[12] << "-" << c[13] << "-" << c[14];
|
||||
cout << "\n | | | | | | | "
|
||||
<< "| | | | | |";
|
||||
cout << "\n | | p-q-r | | "
|
||||
<< "| | " << c[15] << "-" << c[16] << "-" << c[17] << " | |";
|
||||
cout << "\n | | | | | "
|
||||
<< "| | | | |";
|
||||
cout << "\n | s---t---u | "
|
||||
<< "| " << c[18] << "---" << c[19] << "---" << c[20] << " |";
|
||||
cout << "\n | | | "
|
||||
<< "| | |";
|
||||
cout << "\n v-----w-----x " << c[21] << "-----" << c[22] << "-----" << c[23];
|
||||
cout << "\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 << "Num Stones to be removed: " << this->stoneMustBeRemoved << "\n";
|
||||
cout << "setting phase : " << (this->settingPhase ? "true" : "false");
|
||||
cout << "\n";
|
||||
cout << "\n a-----b-----c " << c[0] << "-----" << c[1] << "-----" << c[2];
|
||||
cout << "\n | | | "
|
||||
<< "| | |";
|
||||
cout << "\n | d---e---f | "
|
||||
<< "| " << c[3] << "---" << c[4] << "---" << c[5] << " |";
|
||||
cout << "\n | | | | | "
|
||||
<< "| | | | |";
|
||||
cout << "\n | | g-h-i | | "
|
||||
<< "| | " << c[6] << "-" << c[7] << "-" << c[8] << " | |";
|
||||
cout << "\n | | | | | | | "
|
||||
<< "| | | | | |";
|
||||
cout << "\n j-k-l m-n-o " << c[9] << "-" << c[10] << "-" << c[11] << " " << c[12] << "-" << c[13] << "-" << c[14];
|
||||
cout << "\n | | | | | | | "
|
||||
<< "| | | | | |";
|
||||
cout << "\n | | p-q-r | | "
|
||||
<< "| | " << c[15] << "-" << c[16] << "-" << c[17] << " | |";
|
||||
cout << "\n | | | | | "
|
||||
<< "| | | | |";
|
||||
cout << "\n | s---t---u | "
|
||||
<< "| " << c[18] << "---" << c[19] << "---" << c[20] << " |";
|
||||
cout << "\n | | | "
|
||||
<< "| | |";
|
||||
cout << "\n v-----w-----x " << c[21] << "-----" << c[22] << "-----" << c[23];
|
||||
cout << "\n";
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -60,22 +60,21 @@ void fieldStruct::printBoard()
|
|||
//-----------------------------------------------------------------------------
|
||||
char fieldStruct::GetCharFromStone(int stone)
|
||||
{
|
||||
switch (stone)
|
||||
{
|
||||
case fieldStruct::playerOne:
|
||||
return 'o';
|
||||
case fieldStruct::playerTwo:
|
||||
return 'x';
|
||||
case fieldStruct::playerOneWarning:
|
||||
return '1';
|
||||
case fieldStruct::playerTwoWarning:
|
||||
return '2';
|
||||
case fieldStruct::playerBothWarning:
|
||||
return '3';
|
||||
case fieldStruct::squareIsFree:
|
||||
return ' ';
|
||||
}
|
||||
return 'f';
|
||||
switch (stone) {
|
||||
case fieldStruct::playerOne:
|
||||
return 'o';
|
||||
case fieldStruct::playerTwo:
|
||||
return 'x';
|
||||
case fieldStruct::playerOneWarning:
|
||||
return '1';
|
||||
case fieldStruct::playerTwoWarning:
|
||||
return '2';
|
||||
case fieldStruct::playerBothWarning:
|
||||
return '3';
|
||||
case fieldStruct::squareIsFree:
|
||||
return ' ';
|
||||
}
|
||||
return 'f';
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -84,30 +83,28 @@ char fieldStruct::GetCharFromStone(int stone)
|
|||
//-----------------------------------------------------------------------------
|
||||
void fieldStruct::copyBoard(fieldStruct *destination)
|
||||
{
|
||||
unsigned int i, j;
|
||||
unsigned int i, j;
|
||||
|
||||
this->curPlayer->copyPlayer(destination->curPlayer);
|
||||
this->oppPlayer->copyPlayer(destination->oppPlayer);
|
||||
this->curPlayer->copyPlayer(destination->curPlayer);
|
||||
this->oppPlayer->copyPlayer(destination->oppPlayer);
|
||||
|
||||
destination->stonesSet = this->stonesSet;
|
||||
destination->settingPhase = this->settingPhase;
|
||||
destination->stoneMustBeRemoved = this->stoneMustBeRemoved;
|
||||
destination->stonesSet = this->stonesSet;
|
||||
destination->settingPhase = this->settingPhase;
|
||||
destination->stoneMustBeRemoved = this->stoneMustBeRemoved;
|
||||
|
||||
for (i = 0; i < this->size; i++)
|
||||
{
|
||||
for (i = 0; i < this->size; i++) {
|
||||
|
||||
destination->board[i] = this->board[i];
|
||||
destination->warnings[i] = this->warnings[i];
|
||||
destination->stonePartOfMill[i] = this->stonePartOfMill[i];
|
||||
destination->board[i] = this->board[i];
|
||||
destination->warnings[i] = this->warnings[i];
|
||||
destination->stonePartOfMill[i] = this->stonePartOfMill[i];
|
||||
|
||||
for (j = 0; j < 4; j++)
|
||||
{
|
||||
for (j = 0; j < 4; j++) {
|
||||
|
||||
destination->connectedSquare[i][j] = this->connectedSquare[i][j];
|
||||
destination->stoneMoveAble[i][j] = this->stoneMoveAble[i][j];
|
||||
destination->neighbour[i][j / 2][j % 2] = this->neighbour[i][j / 2][j % 2];
|
||||
}
|
||||
}
|
||||
destination->connectedSquare[i][j] = this->connectedSquare[i][j];
|
||||
destination->stoneMoveAble[i][j] = this->stoneMoveAble[i][j];
|
||||
destination->neighbour[i][j / 2][j % 2] = this->neighbour[i][j / 2][j % 2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -116,18 +113,18 @@ void fieldStruct::copyBoard(fieldStruct *destination)
|
|||
//-----------------------------------------------------------------------------
|
||||
void Player::copyPlayer(Player *destination)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int i;
|
||||
|
||||
destination->numStonesMissing = this->numStonesMissing;
|
||||
destination->numStones = this->numStones;
|
||||
destination->id = this->id;
|
||||
destination->warning = this->warning;
|
||||
destination->numPossibleMoves = this->numPossibleMoves;
|
||||
destination->numStonesMissing = this->numStonesMissing;
|
||||
destination->numStones = this->numStones;
|
||||
destination->id = this->id;
|
||||
destination->warning = this->warning;
|
||||
destination->numPossibleMoves = this->numPossibleMoves;
|
||||
|
||||
for (i = 0; i < MAX_NUM_POS_MOVES; i++)
|
||||
destination->posFrom[i] = this->posFrom[i];
|
||||
for (i = 0; i < MAX_NUM_POS_MOVES; i++)
|
||||
destination->posTo[i] = this->posTo[i];
|
||||
for (i = 0; i < MAX_NUM_POS_MOVES; i++)
|
||||
destination->posFrom[i] = this->posFrom[i];
|
||||
for (i = 0; i < MAX_NUM_POS_MOVES; i++)
|
||||
destination->posTo[i] = this->posTo[i];
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -136,91 +133,90 @@ void Player::copyPlayer(Player *destination)
|
|||
//-----------------------------------------------------------------------------
|
||||
void fieldStruct::createBoard()
|
||||
{
|
||||
// locals
|
||||
unsigned int i;
|
||||
// locals
|
||||
unsigned int i;
|
||||
|
||||
curPlayer = new Player;
|
||||
oppPlayer = new Player;
|
||||
curPlayer = new Player;
|
||||
oppPlayer = new Player;
|
||||
|
||||
curPlayer->id = playerOne;
|
||||
stonesSet = 0;
|
||||
stoneMustBeRemoved = 0;
|
||||
settingPhase = true;
|
||||
curPlayer->warning = (curPlayer->id == playerOne) ? playerOneWarning : playerTwoWarning;
|
||||
oppPlayer->id = (curPlayer->id == playerOne) ? playerTwo : playerOne;
|
||||
oppPlayer->warning = (curPlayer->id == playerOne) ? playerTwoWarning : playerOneWarning;
|
||||
curPlayer->numStones = 0;
|
||||
oppPlayer->numStones = 0;
|
||||
curPlayer->numPossibleMoves = 0;
|
||||
oppPlayer->numPossibleMoves = 0;
|
||||
curPlayer->numStonesMissing = 0;
|
||||
oppPlayer->numStonesMissing = 0;
|
||||
curPlayer->id = playerOne;
|
||||
stonesSet = 0;
|
||||
stoneMustBeRemoved = 0;
|
||||
settingPhase = true;
|
||||
curPlayer->warning = (curPlayer->id == playerOne) ? playerOneWarning : playerTwoWarning;
|
||||
oppPlayer->id = (curPlayer->id == playerOne) ? playerTwo : playerOne;
|
||||
oppPlayer->warning = (curPlayer->id == playerOne) ? playerTwoWarning : playerOneWarning;
|
||||
curPlayer->numStones = 0;
|
||||
oppPlayer->numStones = 0;
|
||||
curPlayer->numPossibleMoves = 0;
|
||||
oppPlayer->numPossibleMoves = 0;
|
||||
curPlayer->numStonesMissing = 0;
|
||||
oppPlayer->numStonesMissing = 0;
|
||||
|
||||
// zero
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
board[i] = squareIsFree;
|
||||
warnings[i] = noWarning;
|
||||
stonePartOfMill[i] = 0;
|
||||
stoneMoveAble[i][0] = false;
|
||||
stoneMoveAble[i][1] = false;
|
||||
stoneMoveAble[i][2] = false;
|
||||
stoneMoveAble[i][3] = false;
|
||||
}
|
||||
// zero
|
||||
for (i = 0; i < size; i++) {
|
||||
board[i] = squareIsFree;
|
||||
warnings[i] = noWarning;
|
||||
stonePartOfMill[i] = 0;
|
||||
stoneMoveAble[i][0] = false;
|
||||
stoneMoveAble[i][1] = false;
|
||||
stoneMoveAble[i][2] = false;
|
||||
stoneMoveAble[i][3] = false;
|
||||
}
|
||||
|
||||
// set connections
|
||||
i = size;
|
||||
// set connections
|
||||
i = size;
|
||||
|
||||
setConnection(0, 1, 9, i, i);
|
||||
setConnection(1, 2, 4, 0, i);
|
||||
setConnection(2, i, 14, 1, i);
|
||||
setConnection(3, 4, 10, i, i);
|
||||
setConnection(4, 5, 7, 3, 1);
|
||||
setConnection(5, i, 13, 4, i);
|
||||
setConnection(6, 7, 11, i, i);
|
||||
setConnection(7, 8, i, 6, 4);
|
||||
setConnection(8, i, 12, 7, i);
|
||||
setConnection(9, 10, 21, i, 0);
|
||||
setConnection(10, 11, 18, 9, 3);
|
||||
setConnection(11, i, 15, 10, 6);
|
||||
setConnection(12, 13, 17, i, 8);
|
||||
setConnection(13, 14, 20, 12, 5);
|
||||
setConnection(14, i, 23, 13, 2);
|
||||
setConnection(15, 16, i, i, 11);
|
||||
setConnection(16, 17, 19, 15, i);
|
||||
setConnection(17, i, i, 16, 12);
|
||||
setConnection(18, 19, i, i, 10);
|
||||
setConnection(19, 20, 22, 18, 16);
|
||||
setConnection(20, i, i, 19, 13);
|
||||
setConnection(21, 22, i, i, 9);
|
||||
setConnection(22, 23, i, 21, 19);
|
||||
setConnection(23, i, i, 22, 14);
|
||||
setConnection(0, 1, 9, i, i);
|
||||
setConnection(1, 2, 4, 0, i);
|
||||
setConnection(2, i, 14, 1, i);
|
||||
setConnection(3, 4, 10, i, i);
|
||||
setConnection(4, 5, 7, 3, 1);
|
||||
setConnection(5, i, 13, 4, i);
|
||||
setConnection(6, 7, 11, i, i);
|
||||
setConnection(7, 8, i, 6, 4);
|
||||
setConnection(8, i, 12, 7, i);
|
||||
setConnection(9, 10, 21, i, 0);
|
||||
setConnection(10, 11, 18, 9, 3);
|
||||
setConnection(11, i, 15, 10, 6);
|
||||
setConnection(12, 13, 17, i, 8);
|
||||
setConnection(13, 14, 20, 12, 5);
|
||||
setConnection(14, i, 23, 13, 2);
|
||||
setConnection(15, 16, i, i, 11);
|
||||
setConnection(16, 17, 19, 15, i);
|
||||
setConnection(17, i, i, 16, 12);
|
||||
setConnection(18, 19, i, i, 10);
|
||||
setConnection(19, 20, 22, 18, 16);
|
||||
setConnection(20, i, i, 19, 13);
|
||||
setConnection(21, 22, i, i, 9);
|
||||
setConnection(22, 23, i, 21, 19);
|
||||
setConnection(23, i, i, 22, 14);
|
||||
|
||||
// neighbours
|
||||
setNeighbour(0, 1, 2, 9, 21);
|
||||
setNeighbour(1, 0, 2, 4, 7);
|
||||
setNeighbour(2, 0, 1, 14, 23);
|
||||
setNeighbour(3, 4, 5, 10, 18);
|
||||
setNeighbour(4, 1, 7, 3, 5);
|
||||
setNeighbour(5, 3, 4, 13, 20);
|
||||
setNeighbour(6, 7, 8, 11, 15);
|
||||
setNeighbour(7, 1, 4, 6, 8);
|
||||
setNeighbour(8, 6, 7, 12, 17);
|
||||
setNeighbour(9, 10, 11, 0, 21);
|
||||
setNeighbour(10, 9, 11, 3, 18);
|
||||
setNeighbour(11, 9, 10, 6, 15);
|
||||
setNeighbour(12, 13, 14, 8, 17);
|
||||
setNeighbour(13, 12, 14, 5, 20);
|
||||
setNeighbour(14, 12, 13, 2, 23);
|
||||
setNeighbour(15, 6, 11, 16, 17);
|
||||
setNeighbour(16, 15, 17, 19, 22);
|
||||
setNeighbour(17, 15, 16, 8, 12);
|
||||
setNeighbour(18, 3, 10, 19, 20);
|
||||
setNeighbour(19, 18, 20, 16, 22);
|
||||
setNeighbour(20, 5, 13, 18, 19);
|
||||
setNeighbour(21, 0, 9, 22, 23);
|
||||
setNeighbour(22, 16, 19, 21, 23);
|
||||
setNeighbour(23, 2, 14, 21, 22);
|
||||
// neighbours
|
||||
setNeighbour(0, 1, 2, 9, 21);
|
||||
setNeighbour(1, 0, 2, 4, 7);
|
||||
setNeighbour(2, 0, 1, 14, 23);
|
||||
setNeighbour(3, 4, 5, 10, 18);
|
||||
setNeighbour(4, 1, 7, 3, 5);
|
||||
setNeighbour(5, 3, 4, 13, 20);
|
||||
setNeighbour(6, 7, 8, 11, 15);
|
||||
setNeighbour(7, 1, 4, 6, 8);
|
||||
setNeighbour(8, 6, 7, 12, 17);
|
||||
setNeighbour(9, 10, 11, 0, 21);
|
||||
setNeighbour(10, 9, 11, 3, 18);
|
||||
setNeighbour(11, 9, 10, 6, 15);
|
||||
setNeighbour(12, 13, 14, 8, 17);
|
||||
setNeighbour(13, 12, 14, 5, 20);
|
||||
setNeighbour(14, 12, 13, 2, 23);
|
||||
setNeighbour(15, 6, 11, 16, 17);
|
||||
setNeighbour(16, 15, 17, 19, 22);
|
||||
setNeighbour(17, 15, 16, 8, 12);
|
||||
setNeighbour(18, 3, 10, 19, 20);
|
||||
setNeighbour(19, 18, 20, 16, 22);
|
||||
setNeighbour(20, 5, 13, 18, 19);
|
||||
setNeighbour(21, 0, 9, 22, 23);
|
||||
setNeighbour(22, 16, 19, 21, 23);
|
||||
setNeighbour(23, 2, 14, 21, 22);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -229,8 +225,8 @@ void fieldStruct::createBoard()
|
|||
//-----------------------------------------------------------------------------
|
||||
void fieldStruct::deleteBoard()
|
||||
{
|
||||
SAFE_DELETE(curPlayer);
|
||||
SAFE_DELETE(oppPlayer);
|
||||
SAFE_DELETE(curPlayer);
|
||||
SAFE_DELETE(oppPlayer);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -239,10 +235,10 @@ void fieldStruct::deleteBoard()
|
|||
//-----------------------------------------------------------------------------
|
||||
inline void fieldStruct::setConnection(unsigned int index, int firstDirection, int secondDirection, int thirdDirection, int fourthDirection)
|
||||
{
|
||||
connectedSquare[index][0] = firstDirection;
|
||||
connectedSquare[index][1] = secondDirection;
|
||||
connectedSquare[index][2] = thirdDirection;
|
||||
connectedSquare[index][3] = fourthDirection;
|
||||
connectedSquare[index][0] = firstDirection;
|
||||
connectedSquare[index][1] = secondDirection;
|
||||
connectedSquare[index][2] = thirdDirection;
|
||||
connectedSquare[index][3] = fourthDirection;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -251,8 +247,8 @@ inline void fieldStruct::setConnection(unsigned int index, int firstDirection, i
|
|||
//-----------------------------------------------------------------------------
|
||||
inline void fieldStruct::setNeighbour(unsigned int index, unsigned int firstNeighbour0, unsigned int secondNeighbour0, unsigned int firstNeighbour1, unsigned int secondNeighbour1)
|
||||
{
|
||||
neighbour[index][0][0] = firstNeighbour0;
|
||||
neighbour[index][0][1] = secondNeighbour0;
|
||||
neighbour[index][1][0] = firstNeighbour1;
|
||||
neighbour[index][1][1] = secondNeighbour1;
|
||||
neighbour[index][0][0] = firstNeighbour0;
|
||||
neighbour[index][0][1] = secondNeighbour0;
|
||||
neighbour[index][1][0] = firstNeighbour1;
|
||||
neighbour[index][1][1] = secondNeighbour1;
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
/*********************************************************************\
|
||||
millAI.h
|
||||
Copyright (c) Thomas Weber. All rights reserved.
|
||||
Copyright (C) 2021 The Sanmill developers (see AUTHORS file)
|
||||
Licensed under the MIT License.
|
||||
https://github.com/madweasel/madweasels-cpp
|
||||
millAI.h
|
||||
Copyright (c) Thomas Weber. All rights reserved.
|
||||
Copyright (C) 2021 The Sanmill developers (see AUTHORS file)
|
||||
Licensed under the MIT License.
|
||||
https://github.com/madweasel/madweasels-cpp
|
||||
\*********************************************************************/
|
||||
|
||||
#ifndef MUEHLE_AI_H
|
||||
|
@ -30,77 +30,77 @@
|
|||
class Player
|
||||
{
|
||||
public:
|
||||
int id; // static
|
||||
unsigned int warning; // static
|
||||
unsigned int numStones; // number of stones of this player on the board
|
||||
unsigned int numStonesMissing; // number of stones, which where stolen by the opponent
|
||||
unsigned int numPossibleMoves; // amount of possible moves
|
||||
unsigned int posTo[MAX_NUM_POS_MOVES]; // target board position of a possible move
|
||||
unsigned int posFrom[MAX_NUM_POS_MOVES]; // source board position of a possible move
|
||||
int id; // static
|
||||
unsigned int warning; // static
|
||||
unsigned int numStones; // number of stones of this player on the board
|
||||
unsigned int numStonesMissing; // number of stones, which where stolen by the opponent
|
||||
unsigned int numPossibleMoves; // amount of possible moves
|
||||
unsigned int posTo[MAX_NUM_POS_MOVES]; // target board position of a possible move
|
||||
unsigned int posFrom[MAX_NUM_POS_MOVES]; // source board position of a possible move
|
||||
|
||||
void copyPlayer(Player *destination);
|
||||
void copyPlayer(Player *destination);
|
||||
};
|
||||
|
||||
class fieldStruct
|
||||
{
|
||||
public:
|
||||
// constants
|
||||
static const int squareIsFree = 0; // trivial
|
||||
static const int playerOne = -1; // so rowOwner can be calculated easy
|
||||
static const int playerTwo = 1;
|
||||
static const int playerBlack = -1; // so rowOwner can be calculated easy
|
||||
static const int playerWhite = 1;
|
||||
static const unsigned int noWarning = 0; // so the bitwise or-operation can be applied, without interacting with playerOne & Two
|
||||
static const unsigned int playerOneWarning = 2;
|
||||
static const unsigned int playerTwoWarning = 4;
|
||||
static const unsigned int playerBothWarning = 6;
|
||||
static const unsigned int numStonesPerPlayer = 9;
|
||||
static const unsigned int size = 24; // number of squares
|
||||
static const int gameDrawn = 3; // only a nonzero value
|
||||
// constants
|
||||
static const int squareIsFree = 0; // trivial
|
||||
static const int playerOne = -1; // so rowOwner can be calculated easy
|
||||
static const int playerTwo = 1;
|
||||
static const int playerBlack = -1; // so rowOwner can be calculated easy
|
||||
static const int playerWhite = 1;
|
||||
static const unsigned int noWarning = 0; // so the bitwise or-operation can be applied, without interacting with playerOne & Two
|
||||
static const unsigned int playerOneWarning = 2;
|
||||
static const unsigned int playerTwoWarning = 4;
|
||||
static const unsigned int playerBothWarning = 6;
|
||||
static const unsigned int numStonesPerPlayer = 9;
|
||||
static const unsigned int size = 24; // number of squares
|
||||
static const int gameDrawn = 3; // only a nonzero value
|
||||
|
||||
// variables
|
||||
int board[size]; // one of the values above for each board position
|
||||
unsigned int warnings[size]; // array containing the warnings for each board position
|
||||
bool stoneMoveAble[size][4]; // true if stone can be moved in this direction
|
||||
unsigned int stonePartOfMill[size]; // the number of mills, of which this stone is part of
|
||||
unsigned int connectedSquare[size][4]; // static array containg the index of the neighbour or "size"
|
||||
unsigned int neighbour[size][2][2]; // static array containing the two neighbours of each squares
|
||||
unsigned int stonesSet; // number of stones set in the setting phase
|
||||
bool settingPhase; // true if stonesSet < 18
|
||||
unsigned int stoneMustBeRemoved; // number of stones which must be removed by the current player
|
||||
Player *curPlayer, *oppPlayer; // pointers to the current and opponent player
|
||||
// variables
|
||||
int board[size]; // one of the values above for each board position
|
||||
unsigned int warnings[size]; // array containing the warnings for each board position
|
||||
bool stoneMoveAble[size][4]; // true if stone can be moved in this direction
|
||||
unsigned int stonePartOfMill[size]; // the number of mills, of which this stone is part of
|
||||
unsigned int connectedSquare[size][4]; // static array containg the index of the neighbour or "size"
|
||||
unsigned int neighbour[size][2][2]; // static array containing the two neighbours of each squares
|
||||
unsigned int stonesSet; // number of stones set in the setting phase
|
||||
bool settingPhase; // true if stonesSet < 18
|
||||
unsigned int stoneMustBeRemoved; // number of stones which must be removed by the current player
|
||||
Player *curPlayer, *oppPlayer; // pointers to the current and opponent player
|
||||
|
||||
// useful functions
|
||||
void printBoard();
|
||||
void copyBoard(fieldStruct *destination);
|
||||
void createBoard();
|
||||
void deleteBoard();
|
||||
// useful functions
|
||||
void printBoard();
|
||||
void copyBoard(fieldStruct *destination);
|
||||
void createBoard();
|
||||
void deleteBoard();
|
||||
|
||||
private:
|
||||
// helper functions
|
||||
char GetCharFromStone(int stone);
|
||||
void setConnection(unsigned int index, int firstDirection, int secondDirection, int thirdDirection, int fourthDirection);
|
||||
void setNeighbour(unsigned int index, unsigned int firstNeighbour0, unsigned int secondNeighbour0, unsigned int firstNeighbour1, unsigned int secondNeighbour1);
|
||||
// helper functions
|
||||
char GetCharFromStone(int stone);
|
||||
void setConnection(unsigned int index, int firstDirection, int secondDirection, int thirdDirection, int fourthDirection);
|
||||
void setNeighbour(unsigned int index, unsigned int firstNeighbour0, unsigned int secondNeighbour0, unsigned int firstNeighbour1, unsigned int secondNeighbour1);
|
||||
};
|
||||
|
||||
class MillAI abstract
|
||||
{
|
||||
protected:
|
||||
fieldStruct dummyField;
|
||||
fieldStruct dummyField;
|
||||
|
||||
public:
|
||||
// Constructor / destructor
|
||||
MillAI()
|
||||
{
|
||||
dummyField.createBoard();
|
||||
};
|
||||
~MillAI()
|
||||
{
|
||||
dummyField.deleteBoard();
|
||||
};
|
||||
// Constructor / destructor
|
||||
MillAI()
|
||||
{
|
||||
dummyField.createBoard();
|
||||
};
|
||||
~MillAI()
|
||||
{
|
||||
dummyField.deleteBoard();
|
||||
};
|
||||
|
||||
// Functions
|
||||
virtual void play(fieldStruct *theField, unsigned int *pushFrom, unsigned int *pushTo) = 0;
|
||||
// Functions
|
||||
virtual void play(fieldStruct *theField, unsigned int *pushFrom, unsigned int *pushTo) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
/*********************************************************************
|
||||
MiniMaxAI.cpp
|
||||
Copyright (c) Thomas Weber. All rights reserved.
|
||||
Copyright (C) 2021 The Sanmill developers (see AUTHORS file)
|
||||
Licensed under the MIT License.
|
||||
https://github.com/madweasel/madweasels-cpp
|
||||
MiniMaxAI.cpp
|
||||
Copyright (c) Thomas Weber. All rights reserved.
|
||||
Copyright (C) 2021 The Sanmill developers (see AUTHORS file)
|
||||
Licensed under the MIT License.
|
||||
https://github.com/madweasel/madweasels-cpp
|
||||
\*********************************************************************/
|
||||
|
||||
#include "miniMaxAI.h"
|
||||
|
@ -14,7 +14,7 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
MiniMaxAI::MiniMaxAI()
|
||||
{
|
||||
depthOfFullTree = 0;
|
||||
depthOfFullTree = 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -31,65 +31,57 @@ MiniMaxAI::~MiniMaxAI()
|
|||
//-----------------------------------------------------------------------------
|
||||
void MiniMaxAI::play(fieldStruct *theField, unsigned int *pushFrom, unsigned int *pushTo)
|
||||
{
|
||||
// globals
|
||||
field = theField;
|
||||
ownId = field->curPlayer->id;
|
||||
curSearchDepth = 0;
|
||||
unsigned int bestChoice;
|
||||
unsigned int searchDepth;
|
||||
// globals
|
||||
field = theField;
|
||||
ownId = field->curPlayer->id;
|
||||
curSearchDepth = 0;
|
||||
unsigned int bestChoice;
|
||||
unsigned int searchDepth;
|
||||
|
||||
// automatic depth
|
||||
if (depthOfFullTree == 0)
|
||||
{
|
||||
if (theField->settingPhase)
|
||||
searchDepth = 5;
|
||||
else if (theField->curPlayer->numStones <= 4)
|
||||
searchDepth = 7;
|
||||
else if (theField->oppPlayer->numStones <= 4)
|
||||
searchDepth = 7;
|
||||
else
|
||||
searchDepth = 7;
|
||||
}
|
||||
else
|
||||
{
|
||||
searchDepth = depthOfFullTree;
|
||||
}
|
||||
// automatic depth
|
||||
if (depthOfFullTree == 0) {
|
||||
if (theField->settingPhase)
|
||||
searchDepth = 5;
|
||||
else if (theField->curPlayer->numStones <= 4)
|
||||
searchDepth = 7;
|
||||
else if (theField->oppPlayer->numStones <= 4)
|
||||
searchDepth = 7;
|
||||
else
|
||||
searchDepth = 7;
|
||||
} else {
|
||||
searchDepth = depthOfFullTree;
|
||||
}
|
||||
|
||||
// Inform user about progress
|
||||
cout << "MiniMaxAI is thinking with a depth of " << searchDepth << " steps!\n\n\n";
|
||||
// Inform user about progress
|
||||
cout << "MiniMaxAI is thinking with a depth of " << searchDepth << " steps!\n\n\n";
|
||||
|
||||
// reserve memory
|
||||
possibilities = new Possibility[searchDepth + 1];
|
||||
oldStates = new Backup[searchDepth + 1];
|
||||
idPossibilities = new unsigned int[(searchDepth + 1) * MAX_NUM_POS_MOVES];
|
||||
// reserve memory
|
||||
possibilities = new Possibility[searchDepth + 1];
|
||||
oldStates = new Backup[searchDepth + 1];
|
||||
idPossibilities = new unsigned int[(searchDepth + 1) * MAX_NUM_POS_MOVES];
|
||||
|
||||
// start the miniMax-algorithmn
|
||||
Possibility *rootPossibilities = (Possibility *)getBestChoice(searchDepth, &bestChoice, MAX_NUM_POS_MOVES);
|
||||
// start the miniMax-algorithmn
|
||||
Possibility *rootPossibilities = (Possibility *)getBestChoice(searchDepth, &bestChoice, MAX_NUM_POS_MOVES);
|
||||
|
||||
// decode the best choice
|
||||
if (field->stoneMustBeRemoved)
|
||||
{
|
||||
*pushFrom = bestChoice;
|
||||
*pushTo = 0;
|
||||
}
|
||||
else if (field->settingPhase)
|
||||
{
|
||||
*pushFrom = 0;
|
||||
*pushTo = bestChoice;
|
||||
}
|
||||
else
|
||||
{
|
||||
*pushFrom = rootPossibilities->from[bestChoice];
|
||||
*pushTo = rootPossibilities->to[bestChoice];
|
||||
}
|
||||
// decode the best choice
|
||||
if (field->stoneMustBeRemoved) {
|
||||
*pushFrom = bestChoice;
|
||||
*pushTo = 0;
|
||||
} else if (field->settingPhase) {
|
||||
*pushFrom = 0;
|
||||
*pushTo = bestChoice;
|
||||
} else {
|
||||
*pushFrom = rootPossibilities->from[bestChoice];
|
||||
*pushTo = rootPossibilities->to[bestChoice];
|
||||
}
|
||||
|
||||
// release memory
|
||||
delete[] oldStates;
|
||||
delete[] idPossibilities;
|
||||
delete[] possibilities;
|
||||
// release memory
|
||||
delete[] oldStates;
|
||||
delete[] idPossibilities;
|
||||
delete[] possibilities;
|
||||
|
||||
// release memory
|
||||
field = nullptr;
|
||||
// release memory
|
||||
field = nullptr;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -98,7 +90,7 @@ void MiniMaxAI::play(fieldStruct *theField, unsigned int *pushFrom, unsigned int
|
|||
//-----------------------------------------------------------------------------
|
||||
void MiniMaxAI::setSearchDepth(unsigned int depth)
|
||||
{
|
||||
depthOfFullTree = depth;
|
||||
depthOfFullTree = depth;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -107,9 +99,9 @@ void MiniMaxAI::setSearchDepth(unsigned int depth)
|
|||
//-----------------------------------------------------------------------------
|
||||
void MiniMaxAI::prepareBestChoiceCalculation()
|
||||
{
|
||||
// calculate current value
|
||||
currentValue = 0;
|
||||
gameHasFinished = false;
|
||||
// calculate current value
|
||||
currentValue = 0;
|
||||
gameHasFinished = false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -118,27 +110,25 @@ void MiniMaxAI::prepareBestChoiceCalculation()
|
|||
//-----------------------------------------------------------------------------
|
||||
unsigned int *MiniMaxAI::getPossSettingPhase(unsigned int *numPossibilities, void **pPossibilities)
|
||||
{
|
||||
// locals
|
||||
unsigned int i;
|
||||
unsigned int *idPossibility = &idPossibilities[curSearchDepth * MAX_NUM_POS_MOVES];
|
||||
// locals
|
||||
unsigned int i;
|
||||
unsigned int *idPossibility = &idPossibilities[curSearchDepth * MAX_NUM_POS_MOVES];
|
||||
|
||||
// possibilities with cut off
|
||||
for ((*numPossibilities) = 0, i = 0; i < field->size; i++)
|
||||
{
|
||||
// possibilities with cut off
|
||||
for ((*numPossibilities) = 0, i = 0; i < field->size; i++) {
|
||||
|
||||
// move possible ?
|
||||
if (field->board[i] == field->squareIsFree)
|
||||
{
|
||||
// move possible ?
|
||||
if (field->board[i] == field->squareIsFree) {
|
||||
|
||||
idPossibility[*numPossibilities] = i;
|
||||
(*numPossibilities)++;
|
||||
}
|
||||
}
|
||||
idPossibility[*numPossibilities] = i;
|
||||
(*numPossibilities)++;
|
||||
}
|
||||
}
|
||||
|
||||
// possibility code is simple
|
||||
*pPossibilities = nullptr;
|
||||
// possibility code is simple
|
||||
*pPossibilities = nullptr;
|
||||
|
||||
return idPossibility;
|
||||
return idPossibility;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -147,64 +137,55 @@ unsigned int *MiniMaxAI::getPossSettingPhase(unsigned int *numPossibilities, voi
|
|||
//-----------------------------------------------------------------------------
|
||||
unsigned int *MiniMaxAI::getPossNormalMove(unsigned int *numPossibilities, void **pPossibilities)
|
||||
{
|
||||
// locals
|
||||
unsigned int from, to, dir;
|
||||
unsigned int *idPossibility = &idPossibilities[curSearchDepth * MAX_NUM_POS_MOVES];
|
||||
Possibility *possibility = &possibilities[curSearchDepth];
|
||||
// locals
|
||||
unsigned int from, to, dir;
|
||||
unsigned int *idPossibility = &idPossibilities[curSearchDepth * MAX_NUM_POS_MOVES];
|
||||
Possibility *possibility = &possibilities[curSearchDepth];
|
||||
|
||||
// if he is not allowed to spring
|
||||
if (field->curPlayer->numStones > 3)
|
||||
{
|
||||
// if he is not allowed to spring
|
||||
if (field->curPlayer->numStones > 3) {
|
||||
|
||||
for ((*numPossibilities) = 0, from = 0; from < field->size; from++)
|
||||
{
|
||||
for (dir = 0; dir < 4; dir++)
|
||||
{
|
||||
for ((*numPossibilities) = 0, from = 0; from < field->size; from++) {
|
||||
for (dir = 0; dir < 4; dir++) {
|
||||
|
||||
// destination
|
||||
to = field->connectedSquare[from][dir];
|
||||
// destination
|
||||
to = field->connectedSquare[from][dir];
|
||||
|
||||
// move possible ?
|
||||
if (to < field->size && field->board[from] == field->curPlayer->id && field->board[to] == field->squareIsFree)
|
||||
{
|
||||
// move possible ?
|
||||
if (to < field->size && field->board[from] == field->curPlayer->id && field->board[to] == field->squareIsFree) {
|
||||
|
||||
// stone is moveable
|
||||
idPossibility[*numPossibilities] = *numPossibilities;
|
||||
possibility->from[*numPossibilities] = from;
|
||||
possibility->to[*numPossibilities] = to;
|
||||
(*numPossibilities)++;
|
||||
// stone is moveable
|
||||
idPossibility[*numPossibilities] = *numPossibilities;
|
||||
possibility->from[*numPossibilities] = from;
|
||||
possibility->to[*numPossibilities] = to;
|
||||
(*numPossibilities)++;
|
||||
|
||||
// current player is allowed to spring
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// current player is allowed to spring
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
for ((*numPossibilities) = 0, from = 0; from < field->size; from++)
|
||||
{
|
||||
for (to = 0; to < field->size; to++)
|
||||
{
|
||||
for ((*numPossibilities) = 0, from = 0; from < field->size; from++) {
|
||||
for (to = 0; to < field->size; to++) {
|
||||
|
||||
// move possible ?
|
||||
if (field->board[from] == field->curPlayer->id && field->board[to] == field->squareIsFree && *numPossibilities < MAX_NUM_POS_MOVES)
|
||||
{
|
||||
// move possible ?
|
||||
if (field->board[from] == field->curPlayer->id && field->board[to] == field->squareIsFree && *numPossibilities < MAX_NUM_POS_MOVES) {
|
||||
|
||||
// stone is moveable
|
||||
idPossibility[*numPossibilities] = *numPossibilities;
|
||||
possibility->from[*numPossibilities] = from;
|
||||
possibility->to[*numPossibilities] = to;
|
||||
(*numPossibilities)++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// stone is moveable
|
||||
idPossibility[*numPossibilities] = *numPossibilities;
|
||||
possibility->from[*numPossibilities] = from;
|
||||
possibility->to[*numPossibilities] = to;
|
||||
(*numPossibilities)++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// pass possibilities
|
||||
*pPossibilities = (void *)possibility;
|
||||
// pass possibilities
|
||||
*pPossibilities = (void *)possibility;
|
||||
|
||||
return idPossibility;
|
||||
return idPossibility;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -213,27 +194,25 @@ unsigned int *MiniMaxAI::getPossNormalMove(unsigned int *numPossibilities, void
|
|||
//-----------------------------------------------------------------------------
|
||||
unsigned int *MiniMaxAI::getPossStoneRemove(unsigned int *numPossibilities, void **pPossibilities)
|
||||
{
|
||||
// locals
|
||||
unsigned int i;
|
||||
unsigned int *idPossibility = &idPossibilities[curSearchDepth * MAX_NUM_POS_MOVES];
|
||||
// locals
|
||||
unsigned int i;
|
||||
unsigned int *idPossibility = &idPossibilities[curSearchDepth * MAX_NUM_POS_MOVES];
|
||||
|
||||
// possibilities with cut off
|
||||
for ((*numPossibilities) = 0, i = 0; i < field->size; i++)
|
||||
{
|
||||
// possibilities with cut off
|
||||
for ((*numPossibilities) = 0, i = 0; i < field->size; i++) {
|
||||
|
||||
// move possible ?
|
||||
if (field->board[i] == field->oppPlayer->id && !field->stonePartOfMill[i])
|
||||
{
|
||||
// move possible ?
|
||||
if (field->board[i] == field->oppPlayer->id && !field->stonePartOfMill[i]) {
|
||||
|
||||
idPossibility[*numPossibilities] = i;
|
||||
(*numPossibilities)++;
|
||||
}
|
||||
}
|
||||
idPossibility[*numPossibilities] = i;
|
||||
(*numPossibilities)++;
|
||||
}
|
||||
}
|
||||
|
||||
// possibility code is simple
|
||||
*pPossibilities = nullptr;
|
||||
// possibility code is simple
|
||||
*pPossibilities = nullptr;
|
||||
|
||||
return idPossibility;
|
||||
return idPossibility;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -242,25 +221,22 @@ unsigned int *MiniMaxAI::getPossStoneRemove(unsigned int *numPossibilities, void
|
|||
//-----------------------------------------------------------------------------
|
||||
unsigned int *MiniMaxAI::getPossibilities(unsigned int threadNo, unsigned int *numPossibilities, bool *opponentsMove, void **pPossibilities)
|
||||
{
|
||||
// set opponentsMove
|
||||
*opponentsMove = (field->curPlayer->id == ownId) ? false : true;
|
||||
// set opponentsMove
|
||||
*opponentsMove = (field->curPlayer->id == ownId) ? false : true;
|
||||
|
||||
// When game has ended of course nothing happens any more
|
||||
if (gameHasFinished)
|
||||
{
|
||||
*numPossibilities = 0;
|
||||
return 0;
|
||||
// look what is to do
|
||||
}
|
||||
else
|
||||
{
|
||||
if (field->stoneMustBeRemoved)
|
||||
return getPossStoneRemove(numPossibilities, pPossibilities);
|
||||
else if (field->settingPhase)
|
||||
return getPossSettingPhase(numPossibilities, pPossibilities);
|
||||
else
|
||||
return getPossNormalMove(numPossibilities, pPossibilities);
|
||||
}
|
||||
// When game has ended of course nothing happens any more
|
||||
if (gameHasFinished) {
|
||||
*numPossibilities = 0;
|
||||
return 0;
|
||||
// look what is to do
|
||||
} else {
|
||||
if (field->stoneMustBeRemoved)
|
||||
return getPossStoneRemove(numPossibilities, pPossibilities);
|
||||
else if (field->settingPhase)
|
||||
return getPossSettingPhase(numPossibilities, pPossibilities);
|
||||
else
|
||||
return getPossNormalMove(numPossibilities, pPossibilities);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -269,8 +245,8 @@ unsigned int *MiniMaxAI::getPossibilities(unsigned int threadNo, unsigned int *n
|
|||
//-----------------------------------------------------------------------------
|
||||
void MiniMaxAI::getValueOfSituation(unsigned int threadNo, float &floatValue, TwoBit &shortValue)
|
||||
{
|
||||
floatValue = currentValue;
|
||||
shortValue = 0;
|
||||
floatValue = currentValue;
|
||||
shortValue = 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -287,34 +263,33 @@ void MiniMaxAI::deletePossibilities(unsigned int threadNo, void *pPossibilities)
|
|||
//-----------------------------------------------------------------------------
|
||||
void MiniMaxAI::undo(unsigned int threadNo, unsigned int idPossibility, bool opponentsMove, void *pBackup, void *pPossibilities)
|
||||
{
|
||||
// locals
|
||||
Backup *oldState = (Backup *)pBackup;
|
||||
// locals
|
||||
Backup *oldState = (Backup *)pBackup;
|
||||
|
||||
// reset old value
|
||||
currentValue = oldState->value;
|
||||
gameHasFinished = oldState->gameHasFinished;
|
||||
curSearchDepth--;
|
||||
// reset old value
|
||||
currentValue = oldState->value;
|
||||
gameHasFinished = oldState->gameHasFinished;
|
||||
curSearchDepth--;
|
||||
|
||||
field->curPlayer = oldState->curPlayer;
|
||||
field->oppPlayer = oldState->oppPlayer;
|
||||
field->curPlayer->numStones = oldState->curNumStones;
|
||||
field->oppPlayer->numStones = oldState->oppNumStones;
|
||||
field->curPlayer->numStonesMissing = oldState->curMissStones;
|
||||
field->oppPlayer->numStonesMissing = oldState->oppMissStones;
|
||||
field->curPlayer->numPossibleMoves = oldState->curPosMoves;
|
||||
field->oppPlayer->numPossibleMoves = oldState->oppPosMoves;
|
||||
field->settingPhase = oldState->settingPhase;
|
||||
field->stonesSet = oldState->stonesSet;
|
||||
field->stoneMustBeRemoved = oldState->stoneMustBeRemoved;
|
||||
field->board[oldState->from] = oldState->fieldFrom;
|
||||
field->board[oldState->to] = oldState->fieldTo;
|
||||
field->curPlayer = oldState->curPlayer;
|
||||
field->oppPlayer = oldState->oppPlayer;
|
||||
field->curPlayer->numStones = oldState->curNumStones;
|
||||
field->oppPlayer->numStones = oldState->oppNumStones;
|
||||
field->curPlayer->numStonesMissing = oldState->curMissStones;
|
||||
field->oppPlayer->numStonesMissing = oldState->oppMissStones;
|
||||
field->curPlayer->numPossibleMoves = oldState->curPosMoves;
|
||||
field->oppPlayer->numPossibleMoves = oldState->oppPosMoves;
|
||||
field->settingPhase = oldState->settingPhase;
|
||||
field->stonesSet = oldState->stonesSet;
|
||||
field->stoneMustBeRemoved = oldState->stoneMustBeRemoved;
|
||||
field->board[oldState->from] = oldState->fieldFrom;
|
||||
field->board[oldState->to] = oldState->fieldTo;
|
||||
|
||||
// very expensive
|
||||
for (int i = 0; i < field->size; i++)
|
||||
{
|
||||
field->stonePartOfMill[i] = oldState->stonePartOfMill[i];
|
||||
field->warnings[i] = oldState->warnings[i];
|
||||
}
|
||||
// very expensive
|
||||
for (int i = 0; i < field->size; i++) {
|
||||
field->stonePartOfMill[i] = oldState->stonePartOfMill[i];
|
||||
field->warnings[i] = oldState->warnings[i];
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -323,81 +298,73 @@ void MiniMaxAI::undo(unsigned int threadNo, unsigned int idPossibility, bool opp
|
|||
//-----------------------------------------------------------------------------
|
||||
inline void MiniMaxAI::setWarning(unsigned int stoneOne, unsigned int stoneTwo, unsigned int stoneThree)
|
||||
{
|
||||
// if all 3 fields are occupied by current player than he closed a mill
|
||||
if (field->board[stoneOne] == field->curPlayer->id && field->board[stoneTwo] == field->curPlayer->id && field->board[stoneThree] == field->curPlayer->id)
|
||||
{
|
||||
// if 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) {
|
||||
|
||||
field->stonePartOfMill[stoneOne]++;
|
||||
field->stonePartOfMill[stoneTwo]++;
|
||||
field->stonePartOfMill[stoneThree]++;
|
||||
field->stoneMustBeRemoved = 1;
|
||||
}
|
||||
field->stonePartOfMill[stoneOne]++;
|
||||
field->stonePartOfMill[stoneTwo]++;
|
||||
field->stonePartOfMill[stoneThree]++;
|
||||
field->stoneMustBeRemoved = 1;
|
||||
}
|
||||
|
||||
// is a mill destroyed ?
|
||||
if (field->board[stoneOne] == field->squareIsFree && field->stonePartOfMill[stoneOne] && field->stonePartOfMill[stoneTwo] && field->stonePartOfMill[stoneThree])
|
||||
{
|
||||
// is a mill destroyed ?
|
||||
if (field->board[stoneOne] == field->squareIsFree && field->stonePartOfMill[stoneOne] && field->stonePartOfMill[stoneTwo] && field->stonePartOfMill[stoneThree]) {
|
||||
|
||||
field->stonePartOfMill[stoneOne]--;
|
||||
field->stonePartOfMill[stoneTwo]--;
|
||||
field->stonePartOfMill[stoneThree]--;
|
||||
}
|
||||
field->stonePartOfMill[stoneOne]--;
|
||||
field->stonePartOfMill[stoneTwo]--;
|
||||
field->stonePartOfMill[stoneThree]--;
|
||||
}
|
||||
|
||||
// stone was set
|
||||
if (field->board[stoneOne] == field->curPlayer->id)
|
||||
{
|
||||
// stone was set
|
||||
if (field->board[stoneOne] == field->curPlayer->id) {
|
||||
|
||||
// a warnig was destroyed
|
||||
field->warnings[stoneOne] = field->noWarning;
|
||||
// a warnig was destroyed
|
||||
field->warnings[stoneOne] = field->noWarning;
|
||||
|
||||
// a warning is created
|
||||
if (field->board[stoneTwo] == field->curPlayer->id && field->board[stoneThree] == field->squareIsFree)
|
||||
field->warnings[stoneThree] |= field->curPlayer->warning;
|
||||
if (field->board[stoneThree] == field->curPlayer->id && field->board[stoneTwo] == field->squareIsFree)
|
||||
field->warnings[stoneTwo] |= field->curPlayer->warning;
|
||||
// a warning is created
|
||||
if (field->board[stoneTwo] == field->curPlayer->id && field->board[stoneThree] == field->squareIsFree)
|
||||
field->warnings[stoneThree] |= field->curPlayer->warning;
|
||||
if (field->board[stoneThree] == field->curPlayer->id && field->board[stoneTwo] == field->squareIsFree)
|
||||
field->warnings[stoneTwo] |= field->curPlayer->warning;
|
||||
|
||||
// stone was removed
|
||||
}
|
||||
else if (field->board[stoneOne] == field->squareIsFree)
|
||||
{
|
||||
// stone was removed
|
||||
} else if (field->board[stoneOne] == field->squareIsFree) {
|
||||
|
||||
// a warning is created
|
||||
if (field->board[stoneTwo] == field->curPlayer->id && field->board[stoneThree] == field->curPlayer->id)
|
||||
field->warnings[stoneOne] |= field->curPlayer->warning;
|
||||
if (field->board[stoneTwo] == field->oppPlayer->id && field->board[stoneThree] == field->oppPlayer->id)
|
||||
field->warnings[stoneOne] |= field->oppPlayer->warning;
|
||||
// a warning is created
|
||||
if (field->board[stoneTwo] == field->curPlayer->id && field->board[stoneThree] == field->curPlayer->id)
|
||||
field->warnings[stoneOne] |= field->curPlayer->warning;
|
||||
if (field->board[stoneTwo] == field->oppPlayer->id && field->board[stoneThree] == field->oppPlayer->id)
|
||||
field->warnings[stoneOne] |= field->oppPlayer->warning;
|
||||
|
||||
// a warning is destroyed
|
||||
if (field->warnings[stoneTwo] && field->board[stoneThree] != field->squareIsFree)
|
||||
{
|
||||
// a warning is destroyed
|
||||
if (field->warnings[stoneTwo] && field->board[stoneThree] != field->squareIsFree) {
|
||||
|
||||
// reset warning if necessary
|
||||
if (field->board[field->neighbour[stoneTwo][0][0]] == field->curPlayer->id && field->board[field->neighbour[stoneTwo][0][1]] == field->curPlayer->id)
|
||||
field->warnings[stoneTwo] = field->curPlayer->warning;
|
||||
else if (field->board[field->neighbour[stoneTwo][1][0]] == field->curPlayer->id && field->board[field->neighbour[stoneTwo][1][1]] == field->curPlayer->id)
|
||||
field->warnings[stoneTwo] = field->curPlayer->warning;
|
||||
else if (field->board[field->neighbour[stoneTwo][0][0]] == field->oppPlayer->id && field->board[field->neighbour[stoneTwo][0][1]] == field->oppPlayer->id)
|
||||
field->warnings[stoneTwo] = field->oppPlayer->warning;
|
||||
else if (field->board[field->neighbour[stoneTwo][1][0]] == field->oppPlayer->id && field->board[field->neighbour[stoneTwo][1][1]] == field->oppPlayer->id)
|
||||
field->warnings[stoneTwo] = field->oppPlayer->warning;
|
||||
else
|
||||
field->warnings[stoneTwo] = field->noWarning;
|
||||
}
|
||||
else if (field->warnings[stoneThree] && field->board[stoneTwo] != field->squareIsFree)
|
||||
{
|
||||
// reset warning if necessary
|
||||
if (field->board[field->neighbour[stoneTwo][0][0]] == field->curPlayer->id && field->board[field->neighbour[stoneTwo][0][1]] == field->curPlayer->id)
|
||||
field->warnings[stoneTwo] = field->curPlayer->warning;
|
||||
else if (field->board[field->neighbour[stoneTwo][1][0]] == field->curPlayer->id && field->board[field->neighbour[stoneTwo][1][1]] == field->curPlayer->id)
|
||||
field->warnings[stoneTwo] = field->curPlayer->warning;
|
||||
else if (field->board[field->neighbour[stoneTwo][0][0]] == field->oppPlayer->id && field->board[field->neighbour[stoneTwo][0][1]] == field->oppPlayer->id)
|
||||
field->warnings[stoneTwo] = field->oppPlayer->warning;
|
||||
else if (field->board[field->neighbour[stoneTwo][1][0]] == field->oppPlayer->id && field->board[field->neighbour[stoneTwo][1][1]] == field->oppPlayer->id)
|
||||
field->warnings[stoneTwo] = field->oppPlayer->warning;
|
||||
else
|
||||
field->warnings[stoneTwo] = field->noWarning;
|
||||
} else if (field->warnings[stoneThree] && field->board[stoneTwo] != field->squareIsFree) {
|
||||
|
||||
// reset warning if necessary
|
||||
if (field->board[field->neighbour[stoneThree][0][0]] == field->curPlayer->id && field->board[field->neighbour[stoneThree][0][1]] == field->curPlayer->id)
|
||||
field->warnings[stoneThree] = field->curPlayer->warning;
|
||||
else if (field->board[field->neighbour[stoneThree][1][0]] == field->curPlayer->id && field->board[field->neighbour[stoneThree][1][1]] == field->curPlayer->id)
|
||||
field->warnings[stoneThree] = field->curPlayer->warning;
|
||||
else if (field->board[field->neighbour[stoneThree][0][0]] == field->oppPlayer->id && field->board[field->neighbour[stoneThree][0][1]] == field->oppPlayer->id)
|
||||
field->warnings[stoneThree] = field->oppPlayer->warning;
|
||||
else if (field->board[field->neighbour[stoneThree][1][0]] == field->oppPlayer->id && field->board[field->neighbour[stoneThree][1][1]] == field->oppPlayer->id)
|
||||
field->warnings[stoneThree] = field->oppPlayer->warning;
|
||||
else
|
||||
field->warnings[stoneThree] = field->noWarning;
|
||||
}
|
||||
}
|
||||
// reset warning if necessary
|
||||
if (field->board[field->neighbour[stoneThree][0][0]] == field->curPlayer->id && field->board[field->neighbour[stoneThree][0][1]] == field->curPlayer->id)
|
||||
field->warnings[stoneThree] = field->curPlayer->warning;
|
||||
else if (field->board[field->neighbour[stoneThree][1][0]] == field->curPlayer->id && field->board[field->neighbour[stoneThree][1][1]] == field->curPlayer->id)
|
||||
field->warnings[stoneThree] = field->curPlayer->warning;
|
||||
else if (field->board[field->neighbour[stoneThree][0][0]] == field->oppPlayer->id && field->board[field->neighbour[stoneThree][0][1]] == field->oppPlayer->id)
|
||||
field->warnings[stoneThree] = field->oppPlayer->warning;
|
||||
else if (field->board[field->neighbour[stoneThree][1][0]] == field->oppPlayer->id && field->board[field->neighbour[stoneThree][1][1]] == field->oppPlayer->id)
|
||||
field->warnings[stoneThree] = field->oppPlayer->warning;
|
||||
else
|
||||
field->warnings[stoneThree] = field->noWarning;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -406,29 +373,28 @@ inline void MiniMaxAI::setWarning(unsigned int stoneOne, unsigned int stoneTwo,
|
|||
//-----------------------------------------------------------------------------
|
||||
inline void MiniMaxAI::updateWarning(unsigned int firstStone, unsigned int secondStone)
|
||||
{
|
||||
// set warnings
|
||||
if (firstStone < field->size)
|
||||
setWarning(firstStone, field->neighbour[firstStone][0][0], field->neighbour[firstStone][0][1]);
|
||||
if (firstStone < field->size)
|
||||
setWarning(firstStone, field->neighbour[firstStone][1][0], field->neighbour[firstStone][1][1]);
|
||||
// set warnings
|
||||
if (firstStone < field->size)
|
||||
setWarning(firstStone, field->neighbour[firstStone][0][0], field->neighbour[firstStone][0][1]);
|
||||
if (firstStone < field->size)
|
||||
setWarning(firstStone, field->neighbour[firstStone][1][0], field->neighbour[firstStone][1][1]);
|
||||
|
||||
if (secondStone < field->size)
|
||||
setWarning(secondStone, field->neighbour[secondStone][0][0], field->neighbour[secondStone][0][1]);
|
||||
if (secondStone < field->size)
|
||||
setWarning(secondStone, field->neighbour[secondStone][1][0], field->neighbour[secondStone][1][1]);
|
||||
if (secondStone < field->size)
|
||||
setWarning(secondStone, field->neighbour[secondStone][0][0], field->neighbour[secondStone][0][1]);
|
||||
if (secondStone < field->size)
|
||||
setWarning(secondStone, field->neighbour[secondStone][1][0], field->neighbour[secondStone][1][1]);
|
||||
|
||||
// no stone must be removed if each belongs to a mill
|
||||
unsigned int i;
|
||||
bool atLeastOneStoneRemoveAble = false;
|
||||
if (field->stoneMustBeRemoved)
|
||||
for (i = 0; i < field->size; i++)
|
||||
if (field->stonePartOfMill[i] == 0 && field->board[i] == field->oppPlayer->id)
|
||||
{
|
||||
atLeastOneStoneRemoveAble = true;
|
||||
break;
|
||||
}
|
||||
if (!atLeastOneStoneRemoveAble)
|
||||
field->stoneMustBeRemoved = 0;
|
||||
// no stone must be removed if each belongs to a mill
|
||||
unsigned int i;
|
||||
bool atLeastOneStoneRemoveAble = false;
|
||||
if (field->stoneMustBeRemoved)
|
||||
for (i = 0; i < field->size; i++)
|
||||
if (field->stonePartOfMill[i] == 0 && field->board[i] == field->oppPlayer->id) {
|
||||
atLeastOneStoneRemoveAble = true;
|
||||
break;
|
||||
}
|
||||
if (!atLeastOneStoneRemoveAble)
|
||||
field->stoneMustBeRemoved = 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -437,58 +403,51 @@ inline void MiniMaxAI::updateWarning(unsigned int firstStone, unsigned int secon
|
|||
//-----------------------------------------------------------------------------
|
||||
inline void MiniMaxAI::updatePossibleMoves(unsigned int stone, Player *stoneOwner, bool stoneRemoved, unsigned int ignoreStone)
|
||||
{
|
||||
// locals
|
||||
unsigned int neighbor, direction;
|
||||
// locals
|
||||
unsigned int neighbor, direction;
|
||||
|
||||
// look into every direction
|
||||
for (direction = 0; direction < 4; direction++)
|
||||
{
|
||||
// look into every direction
|
||||
for (direction = 0; direction < 4; direction++) {
|
||||
|
||||
neighbor = field->connectedSquare[stone][direction];
|
||||
neighbor = field->connectedSquare[stone][direction];
|
||||
|
||||
// neighbor must exist
|
||||
if (neighbor < field->size)
|
||||
{
|
||||
// neighbor must exist
|
||||
if (neighbor < field->size) {
|
||||
|
||||
// relevant when moving from one square to another connected square
|
||||
if (ignoreStone == neighbor)
|
||||
continue;
|
||||
// relevant when moving from one square to another connected square
|
||||
if (ignoreStone == neighbor)
|
||||
continue;
|
||||
|
||||
// if there is no neighbour stone than it only affects the actual stone
|
||||
if (field->board[neighbor] == field->squareIsFree)
|
||||
{
|
||||
// if there is no neighbour stone than it only affects the actual stone
|
||||
if (field->board[neighbor] == field->squareIsFree) {
|
||||
|
||||
if (stoneRemoved)
|
||||
stoneOwner->numPossibleMoves--;
|
||||
else
|
||||
stoneOwner->numPossibleMoves++;
|
||||
if (stoneRemoved)
|
||||
stoneOwner->numPossibleMoves--;
|
||||
else
|
||||
stoneOwner->numPossibleMoves++;
|
||||
|
||||
// if there is a neighbour stone than it effects only this one
|
||||
}
|
||||
else if (field->board[neighbor] == field->curPlayer->id)
|
||||
{
|
||||
// if there is a neighbour stone than it effects only this one
|
||||
} else if (field->board[neighbor] == field->curPlayer->id) {
|
||||
|
||||
if (stoneRemoved)
|
||||
field->curPlayer->numPossibleMoves++;
|
||||
else
|
||||
field->curPlayer->numPossibleMoves--;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (stoneRemoved)
|
||||
field->curPlayer->numPossibleMoves++;
|
||||
else
|
||||
field->curPlayer->numPossibleMoves--;
|
||||
} else {
|
||||
|
||||
if (stoneRemoved)
|
||||
field->oppPlayer->numPossibleMoves++;
|
||||
else
|
||||
field->oppPlayer->numPossibleMoves--;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (stoneRemoved)
|
||||
field->oppPlayer->numPossibleMoves++;
|
||||
else
|
||||
field->oppPlayer->numPossibleMoves--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// only 3 stones resting
|
||||
if (field->curPlayer->numStones <= 3 && !field->settingPhase)
|
||||
field->curPlayer->numPossibleMoves = field->curPlayer->numStones * (field->size - field->curPlayer->numStones - field->oppPlayer->numStones);
|
||||
if (field->oppPlayer->numStones <= 3 && !field->settingPhase)
|
||||
field->oppPlayer->numPossibleMoves = field->oppPlayer->numStones * (field->size - field->curPlayer->numStones - field->oppPlayer->numStones);
|
||||
// only 3 stones resting
|
||||
if (field->curPlayer->numStones <= 3 && !field->settingPhase)
|
||||
field->curPlayer->numPossibleMoves = field->curPlayer->numStones * (field->size - field->curPlayer->numStones - field->oppPlayer->numStones);
|
||||
if (field->oppPlayer->numStones <= 3 && !field->settingPhase)
|
||||
field->oppPlayer->numPossibleMoves = field->oppPlayer->numStones * (field->size - field->curPlayer->numStones - field->oppPlayer->numStones);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -497,26 +456,26 @@ inline void MiniMaxAI::updatePossibleMoves(unsigned int stone, Player *stoneOwne
|
|||
//-----------------------------------------------------------------------------
|
||||
inline void MiniMaxAI::setStone(unsigned int to, Backup *backup)
|
||||
{
|
||||
// backup
|
||||
backup->from = field->size;
|
||||
backup->to = to;
|
||||
backup->fieldFrom = field->size;
|
||||
backup->fieldTo = field->board[to];
|
||||
// backup
|
||||
backup->from = field->size;
|
||||
backup->to = to;
|
||||
backup->fieldFrom = field->size;
|
||||
backup->fieldTo = field->board[to];
|
||||
|
||||
// set stone into board
|
||||
field->board[to] = field->curPlayer->id;
|
||||
field->curPlayer->numStones++;
|
||||
field->stonesSet++;
|
||||
// set stone into board
|
||||
field->board[to] = field->curPlayer->id;
|
||||
field->curPlayer->numStones++;
|
||||
field->stonesSet++;
|
||||
|
||||
// setting phase finished ?
|
||||
if (field->stonesSet == 18)
|
||||
field->settingPhase = false;
|
||||
// setting phase finished ?
|
||||
if (field->stonesSet == 18)
|
||||
field->settingPhase = false;
|
||||
|
||||
// update possible moves
|
||||
updatePossibleMoves(to, field->curPlayer, false, field->size);
|
||||
// update possible moves
|
||||
updatePossibleMoves(to, field->curPlayer, false, field->size);
|
||||
|
||||
// update warnings
|
||||
updateWarning(to, field->size);
|
||||
// update warnings
|
||||
updateWarning(to, field->size);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -525,22 +484,22 @@ inline void MiniMaxAI::setStone(unsigned int to, Backup *backup)
|
|||
//-----------------------------------------------------------------------------
|
||||
inline void MiniMaxAI::normalMove(unsigned int from, unsigned int to, Backup *backup)
|
||||
{
|
||||
// backup
|
||||
backup->from = from;
|
||||
backup->to = to;
|
||||
backup->fieldFrom = field->board[from];
|
||||
backup->fieldTo = field->board[to];
|
||||
// backup
|
||||
backup->from = from;
|
||||
backup->to = to;
|
||||
backup->fieldFrom = field->board[from];
|
||||
backup->fieldTo = field->board[to];
|
||||
|
||||
// set stone into board
|
||||
field->board[from] = field->squareIsFree;
|
||||
field->board[to] = field->curPlayer->id;
|
||||
// set stone into board
|
||||
field->board[from] = field->squareIsFree;
|
||||
field->board[to] = field->curPlayer->id;
|
||||
|
||||
// update possible moves
|
||||
updatePossibleMoves(from, field->curPlayer, true, to);
|
||||
updatePossibleMoves(to, field->curPlayer, false, from);
|
||||
// update possible moves
|
||||
updatePossibleMoves(from, field->curPlayer, true, to);
|
||||
updatePossibleMoves(to, field->curPlayer, false, from);
|
||||
|
||||
// update warnings
|
||||
updateWarning(from, to);
|
||||
// update warnings
|
||||
updateWarning(from, to);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -549,27 +508,27 @@ inline void MiniMaxAI::normalMove(unsigned int from, unsigned int to, Backup *ba
|
|||
//-----------------------------------------------------------------------------
|
||||
inline void MiniMaxAI::removeStone(unsigned int from, Backup *backup)
|
||||
{
|
||||
// backup
|
||||
backup->from = from;
|
||||
backup->to = field->size;
|
||||
backup->fieldFrom = field->board[from];
|
||||
backup->fieldTo = field->size;
|
||||
// backup
|
||||
backup->from = from;
|
||||
backup->to = field->size;
|
||||
backup->fieldFrom = field->board[from];
|
||||
backup->fieldTo = field->size;
|
||||
|
||||
// remove stone
|
||||
field->board[from] = field->squareIsFree;
|
||||
field->oppPlayer->numStones--;
|
||||
field->oppPlayer->numStonesMissing++;
|
||||
field->stoneMustBeRemoved--;
|
||||
// remove stone
|
||||
field->board[from] = field->squareIsFree;
|
||||
field->oppPlayer->numStones--;
|
||||
field->oppPlayer->numStonesMissing++;
|
||||
field->stoneMustBeRemoved--;
|
||||
|
||||
// update possible moves
|
||||
updatePossibleMoves(from, field->oppPlayer, true, field->size);
|
||||
// update possible moves
|
||||
updatePossibleMoves(from, field->oppPlayer, true, field->size);
|
||||
|
||||
// update warnings
|
||||
updateWarning(from, field->size);
|
||||
// update warnings
|
||||
updateWarning(from, field->size);
|
||||
|
||||
// end of game ?
|
||||
if ((field->oppPlayer->numStones < 3) && (!field->settingPhase))
|
||||
gameHasFinished = true;
|
||||
// end of game ?
|
||||
if ((field->oppPlayer->numStones < 3) && (!field->settingPhase))
|
||||
gameHasFinished = true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -578,73 +537,66 @@ inline void MiniMaxAI::removeStone(unsigned int from, Backup *backup)
|
|||
//-----------------------------------------------------------------------------
|
||||
void MiniMaxAI::move(unsigned int threadNo, unsigned int idPossibility, bool opponentsMove, void **pBackup, void *pPossibilities)
|
||||
{
|
||||
// locals
|
||||
Backup *oldState = &oldStates[curSearchDepth];
|
||||
Possibility *tmpPossibility = (Possibility *)pPossibilities;
|
||||
Player *tmpPlayer;
|
||||
unsigned int i;
|
||||
// locals
|
||||
Backup *oldState = &oldStates[curSearchDepth];
|
||||
Possibility *tmpPossibility = (Possibility *)pPossibilities;
|
||||
Player *tmpPlayer;
|
||||
unsigned int i;
|
||||
|
||||
// calculate place of stone
|
||||
*pBackup = (void *)oldState;
|
||||
oldState->value = currentValue;
|
||||
oldState->gameHasFinished = gameHasFinished;
|
||||
oldState->curPlayer = field->curPlayer;
|
||||
oldState->oppPlayer = field->oppPlayer;
|
||||
oldState->curNumStones = field->curPlayer->numStones;
|
||||
oldState->oppNumStones = field->oppPlayer->numStones;
|
||||
oldState->curPosMoves = field->curPlayer->numPossibleMoves;
|
||||
oldState->oppPosMoves = field->oppPlayer->numPossibleMoves;
|
||||
oldState->curMissStones = field->curPlayer->numStonesMissing;
|
||||
oldState->oppMissStones = field->oppPlayer->numStonesMissing;
|
||||
oldState->settingPhase = field->settingPhase;
|
||||
oldState->stonesSet = field->stonesSet;
|
||||
oldState->stoneMustBeRemoved = field->stoneMustBeRemoved;
|
||||
curSearchDepth++;
|
||||
// calculate place of stone
|
||||
*pBackup = (void *)oldState;
|
||||
oldState->value = currentValue;
|
||||
oldState->gameHasFinished = gameHasFinished;
|
||||
oldState->curPlayer = field->curPlayer;
|
||||
oldState->oppPlayer = field->oppPlayer;
|
||||
oldState->curNumStones = field->curPlayer->numStones;
|
||||
oldState->oppNumStones = field->oppPlayer->numStones;
|
||||
oldState->curPosMoves = field->curPlayer->numPossibleMoves;
|
||||
oldState->oppPosMoves = field->oppPlayer->numPossibleMoves;
|
||||
oldState->curMissStones = field->curPlayer->numStonesMissing;
|
||||
oldState->oppMissStones = field->oppPlayer->numStonesMissing;
|
||||
oldState->settingPhase = field->settingPhase;
|
||||
oldState->stonesSet = field->stonesSet;
|
||||
oldState->stoneMustBeRemoved = field->stoneMustBeRemoved;
|
||||
curSearchDepth++;
|
||||
|
||||
// very expensive
|
||||
for (i = 0; i < field->size; i++)
|
||||
{
|
||||
oldState->stonePartOfMill[i] = field->stonePartOfMill[i];
|
||||
oldState->warnings[i] = field->warnings[i];
|
||||
}
|
||||
// very expensive
|
||||
for (i = 0; i < field->size; i++) {
|
||||
oldState->stonePartOfMill[i] = field->stonePartOfMill[i];
|
||||
oldState->warnings[i] = field->warnings[i];
|
||||
}
|
||||
|
||||
// move
|
||||
if (field->stoneMustBeRemoved)
|
||||
{
|
||||
removeStone(idPossibility, oldState);
|
||||
}
|
||||
else if (field->settingPhase)
|
||||
{
|
||||
setStone(idPossibility, oldState);
|
||||
}
|
||||
else
|
||||
{
|
||||
normalMove(tmpPossibility->from[idPossibility], tmpPossibility->to[idPossibility], oldState);
|
||||
}
|
||||
// move
|
||||
if (field->stoneMustBeRemoved) {
|
||||
removeStone(idPossibility, oldState);
|
||||
} else if (field->settingPhase) {
|
||||
setStone(idPossibility, oldState);
|
||||
} else {
|
||||
normalMove(tmpPossibility->from[idPossibility], tmpPossibility->to[idPossibility], oldState);
|
||||
}
|
||||
|
||||
// when opponent is unable to move than current player has won
|
||||
if ((!field->oppPlayer->numPossibleMoves) && (!field->settingPhase) && (!field->stoneMustBeRemoved) && (field->oppPlayer->numStones > 3))
|
||||
gameHasFinished = true;
|
||||
// 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;
|
||||
|
||||
// calc value
|
||||
if (!opponentsMove)
|
||||
currentValue = (float)field->oppPlayer->numStonesMissing - field->curPlayer->numStonesMissing + field->stoneMustBeRemoved + field->curPlayer->numPossibleMoves * 0.1f - field->oppPlayer->numPossibleMoves * 0.1f;
|
||||
else
|
||||
currentValue = (float)field->curPlayer->numStonesMissing - field->oppPlayer->numStonesMissing - field->stoneMustBeRemoved + field->oppPlayer->numPossibleMoves * 0.1f - field->curPlayer->numPossibleMoves * 0.1f;
|
||||
// calc value
|
||||
if (!opponentsMove)
|
||||
currentValue = (float)field->oppPlayer->numStonesMissing - field->curPlayer->numStonesMissing + field->stoneMustBeRemoved + field->curPlayer->numPossibleMoves * 0.1f - field->oppPlayer->numPossibleMoves * 0.1f;
|
||||
else
|
||||
currentValue = (float)field->curPlayer->numStonesMissing - field->oppPlayer->numStonesMissing - field->stoneMustBeRemoved + field->oppPlayer->numPossibleMoves * 0.1f - field->curPlayer->numPossibleMoves * 0.1f;
|
||||
|
||||
// when game has finished - perfect for the current player
|
||||
if (gameHasFinished && !opponentsMove)
|
||||
currentValue = VALUE_GAME_WON - curSearchDepth;
|
||||
if (gameHasFinished && opponentsMove)
|
||||
currentValue = VALUE_GAME_LOST + curSearchDepth;
|
||||
// when game has finished - perfect for the current player
|
||||
if (gameHasFinished && !opponentsMove)
|
||||
currentValue = VALUE_GAME_WON - curSearchDepth;
|
||||
if (gameHasFinished && opponentsMove)
|
||||
currentValue = VALUE_GAME_LOST + curSearchDepth;
|
||||
|
||||
// set next player
|
||||
if (!field->stoneMustBeRemoved)
|
||||
{
|
||||
tmpPlayer = field->curPlayer;
|
||||
field->curPlayer = field->oppPlayer;
|
||||
field->oppPlayer = tmpPlayer;
|
||||
}
|
||||
// set next player
|
||||
if (!field->stoneMustBeRemoved) {
|
||||
tmpPlayer = field->curPlayer;
|
||||
field->curPlayer = field->oppPlayer;
|
||||
field->oppPlayer = tmpPlayer;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -653,14 +605,14 @@ void MiniMaxAI::move(unsigned int threadNo, unsigned int idPossibility, bool opp
|
|||
//-----------------------------------------------------------------------------
|
||||
void MiniMaxAI::printMoveInformation(unsigned int threadNo, unsigned int idPossibility, void *pPossibilities)
|
||||
{
|
||||
// locals
|
||||
Possibility *tmpPossibility = (Possibility *)pPossibilities;
|
||||
// locals
|
||||
Possibility *tmpPossibility = (Possibility *)pPossibilities;
|
||||
|
||||
// move
|
||||
if (field->stoneMustBeRemoved)
|
||||
cout << "remove stone from " << (char)(idPossibility + 97);
|
||||
else if (field->settingPhase)
|
||||
cout << "set stone to " << (char)(idPossibility + 97);
|
||||
else
|
||||
cout << "move from " << (char)(tmpPossibility->from[idPossibility] + 97) << " to " << (char)(tmpPossibility->to[idPossibility] + 97);
|
||||
// move
|
||||
if (field->stoneMustBeRemoved)
|
||||
cout << "remove stone from " << (char)(idPossibility + 97);
|
||||
else if (field->settingPhase)
|
||||
cout << "set stone to " << (char)(idPossibility + 97);
|
||||
else
|
||||
cout << "move from " << (char)(tmpPossibility->from[idPossibility] + 97) << " to " << (char)(tmpPossibility->to[idPossibility] + 97);
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
/*********************************************************************
|
||||
MiniMax.cpp
|
||||
Copyright (c) Thomas Weber. All rights reserved.
|
||||
Copyright (C) 2021 The Sanmill developers (see AUTHORS file)
|
||||
Licensed under the MIT License.
|
||||
https://github.com/madweasel/madweasels-cpp
|
||||
MiniMax.cpp
|
||||
Copyright (c) Thomas Weber. All rights reserved.
|
||||
Copyright (C) 2021 The Sanmill developers (see AUTHORS file)
|
||||
Licensed under the MIT License.
|
||||
https://github.com/madweasel/madweasels-cpp
|
||||
\*********************************************************************/
|
||||
|
||||
#include "miniMax.h"
|
||||
|
@ -14,64 +14,61 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
MiniMax::MiniMax()
|
||||
{
|
||||
// init default values
|
||||
hFileShortKnotValues = nullptr;
|
||||
hFilePlyInfo = nullptr;
|
||||
memoryUsed2 = 0;
|
||||
arrayInfos.c = this;
|
||||
arrayInfos.arrayInfosToBeUpdated.clear();
|
||||
arrayInfos.listArrays.clear();
|
||||
onlyPrepareLayer = false;
|
||||
curCalculatedLayer = 0;
|
||||
osPrint = &cout;
|
||||
verbosity = 3;
|
||||
stopOnCriticalError = true;
|
||||
pDataForUserPrintFunc = nullptr;
|
||||
userPrintFunc = nullptr;
|
||||
layerStats = nullptr;
|
||||
plyInfos = nullptr;
|
||||
fileDirectory.assign("");
|
||||
InitializeCriticalSection(&csDatabase);
|
||||
InitializeCriticalSection(&csOsPrint);
|
||||
// init default values
|
||||
hFileShortKnotValues = nullptr;
|
||||
hFilePlyInfo = nullptr;
|
||||
memoryUsed2 = 0;
|
||||
arrayInfos.c = this;
|
||||
arrayInfos.arrayInfosToBeUpdated.clear();
|
||||
arrayInfos.listArrays.clear();
|
||||
onlyPrepareLayer = false;
|
||||
curCalculatedLayer = 0;
|
||||
osPrint = &cout;
|
||||
verbosity = 3;
|
||||
stopOnCriticalError = true;
|
||||
pDataForUserPrintFunc = nullptr;
|
||||
userPrintFunc = nullptr;
|
||||
layerStats = nullptr;
|
||||
plyInfos = nullptr;
|
||||
fileDirectory.assign("");
|
||||
InitializeCriticalSection(&csDatabase);
|
||||
InitializeCriticalSection(&csOsPrint);
|
||||
|
||||
// Tausender-Trennzeichen
|
||||
locale locale("German_Switzerland");
|
||||
cout.imbue(locale);
|
||||
// Tausender-Trennzeichen
|
||||
locale locale("German_Switzerland");
|
||||
cout.imbue(locale);
|
||||
|
||||
// for io operations per second measurement
|
||||
QueryPerformanceFrequency(&frequency);
|
||||
numReadSkvOperations = 0;
|
||||
numWriteSkvOperations = 0;
|
||||
numReadPlyOperations = 0;
|
||||
numWritePlyOperations = 0;
|
||||
if (MEASURE_ONLY_IO)
|
||||
{
|
||||
readSkvInterval.QuadPart = 0;
|
||||
writeSkvInterval.QuadPart = 0;
|
||||
readPlyInterval.QuadPart = 0;
|
||||
writePlyInterval.QuadPart = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
QueryPerformanceCounter(&readSkvInterval);
|
||||
QueryPerformanceCounter(&writeSkvInterval);
|
||||
QueryPerformanceCounter(&readPlyInterval);
|
||||
QueryPerformanceCounter(&writePlyInterval);
|
||||
}
|
||||
// for io operations per second measurement
|
||||
QueryPerformanceFrequency(&frequency);
|
||||
numReadSkvOperations = 0;
|
||||
numWriteSkvOperations = 0;
|
||||
numReadPlyOperations = 0;
|
||||
numWritePlyOperations = 0;
|
||||
if (MEASURE_ONLY_IO) {
|
||||
readSkvInterval.QuadPart = 0;
|
||||
writeSkvInterval.QuadPart = 0;
|
||||
readPlyInterval.QuadPart = 0;
|
||||
writePlyInterval.QuadPart = 0;
|
||||
} else {
|
||||
QueryPerformanceCounter(&readSkvInterval);
|
||||
QueryPerformanceCounter(&writeSkvInterval);
|
||||
QueryPerformanceCounter(&readPlyInterval);
|
||||
QueryPerformanceCounter(&writePlyInterval);
|
||||
}
|
||||
|
||||
// The algorithm assumes that each player does only one move.
|
||||
// That means closing a mill and removing a stone should be one move.
|
||||
// PL_TO_MOVE_CHANGED means that in the predecessor state the player to move has changed to the other player.
|
||||
// PL_TO_MOVE_UNCHANGED means that the player to move is still the one who shall move.
|
||||
unsigned char skvPerspectiveMatrixTmp[4][2] = {
|
||||
// PL_TO_MOVE_UNCHANGED PL_TO_MOVE_CHANGED
|
||||
SKV_VALUE_INVALID, SKV_VALUE_INVALID, // SKV_VALUE_INVALID
|
||||
SKV_VALUE_GAME_WON, SKV_VALUE_GAME_LOST, // SKV_VALUE_GAME_LOST
|
||||
SKV_VALUE_GAME_DRAWN, SKV_VALUE_GAME_DRAWN, // SKV_VALUE_GAME_DRAWN
|
||||
SKV_VALUE_GAME_LOST, SKV_VALUE_GAME_WON // SKV_VALUE_GAME_WON
|
||||
};
|
||||
// The algorithm assumes that each player does only one move.
|
||||
// That means closing a mill and removing a stone should be one move.
|
||||
// PL_TO_MOVE_CHANGED means that in the predecessor state the player to move has changed to the other player.
|
||||
// PL_TO_MOVE_UNCHANGED means that the player to move is still the one who shall move.
|
||||
unsigned char skvPerspectiveMatrixTmp[4][2] = {
|
||||
// PL_TO_MOVE_UNCHANGED PL_TO_MOVE_CHANGED
|
||||
SKV_VALUE_INVALID, SKV_VALUE_INVALID, // SKV_VALUE_INVALID
|
||||
SKV_VALUE_GAME_WON, SKV_VALUE_GAME_LOST, // SKV_VALUE_GAME_LOST
|
||||
SKV_VALUE_GAME_DRAWN, SKV_VALUE_GAME_DRAWN, // SKV_VALUE_GAME_DRAWN
|
||||
SKV_VALUE_GAME_LOST, SKV_VALUE_GAME_WON // SKV_VALUE_GAME_WON
|
||||
};
|
||||
|
||||
memcpy(skvPerspectiveMatrix, skvPerspectiveMatrixTmp, 4 * 2);
|
||||
memcpy(skvPerspectiveMatrix, skvPerspectiveMatrixTmp, 4 * 2);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -80,9 +77,9 @@ MiniMax::MiniMax()
|
|||
//-----------------------------------------------------------------------------
|
||||
MiniMax::~MiniMax()
|
||||
{
|
||||
closeDatabase();
|
||||
DeleteCriticalSection(&csOsPrint);
|
||||
DeleteCriticalSection(&csDatabase);
|
||||
closeDatabase();
|
||||
DeleteCriticalSection(&csOsPrint);
|
||||
DeleteCriticalSection(&csDatabase);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -91,9 +88,9 @@ MiniMax::~MiniMax()
|
|||
//-----------------------------------------------------------------------------
|
||||
bool MiniMax::falseOrStop()
|
||||
{
|
||||
if (stopOnCriticalError)
|
||||
WaitForSingleObject(GetCurrentProcess(), INFINITE);
|
||||
return false;
|
||||
if (stopOnCriticalError)
|
||||
WaitForSingleObject(GetCurrentProcess(), INFINITE);
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -102,30 +99,30 @@ bool MiniMax::falseOrStop()
|
|||
//-----------------------------------------------------------------------------
|
||||
void *MiniMax::getBestChoice(unsigned int tilLevel, unsigned int *choice, unsigned int maximumNumberOfBranches)
|
||||
{
|
||||
// set global vars
|
||||
depthOfFullTree = tilLevel;
|
||||
maxNumBranches = maximumNumberOfBranches;
|
||||
layerInDatabase = isCurrentStateInDatabase(0);
|
||||
calcDatabase = false;
|
||||
// set global vars
|
||||
depthOfFullTree = tilLevel;
|
||||
maxNumBranches = maximumNumberOfBranches;
|
||||
layerInDatabase = isCurrentStateInDatabase(0);
|
||||
calcDatabase = false;
|
||||
|
||||
// Locals
|
||||
Node root;
|
||||
AlphaBetaGlobalVars alphaBetaVars(this, getLayerNumber(0));
|
||||
RunAlphaBetaVars tva(this, &alphaBetaVars, alphaBetaVars.layerNumber);
|
||||
srand((unsigned int)time(nullptr));
|
||||
tva.curThreadNo = 0;
|
||||
// Locals
|
||||
Node root;
|
||||
AlphaBetaGlobalVars alphaBetaVars(this, getLayerNumber(0));
|
||||
RunAlphaBetaVars tva(this, &alphaBetaVars, alphaBetaVars.layerNumber);
|
||||
srand((unsigned int)time(nullptr));
|
||||
tva.curThreadNo = 0;
|
||||
|
||||
// prepare the situation
|
||||
prepareBestChoiceCalculation();
|
||||
// prepare the situation
|
||||
prepareBestChoiceCalculation();
|
||||
|
||||
// First make a tree until the desired level
|
||||
letTheTreeGrow(&root, &tva, depthOfFullTree, FPKV_MIN_VALUE, FPKV_MAX_VALUE);
|
||||
// First make a tree until the desired level
|
||||
letTheTreeGrow(&root, &tva, depthOfFullTree, FPKV_MIN_VALUE, FPKV_MAX_VALUE);
|
||||
|
||||
// pass best choice and close database
|
||||
*choice = root.bestMoveId;
|
||||
// pass best choice and close database
|
||||
*choice = root.bestMoveId;
|
||||
|
||||
// Return the best branch of the root
|
||||
return pRootPossibilities;
|
||||
// Return the best branch of the root
|
||||
return pRootPossibilities;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -134,90 +131,85 @@ void *MiniMax::getBestChoice(unsigned int tilLevel, unsigned int *choice, unsign
|
|||
//-----------------------------------------------------------------------------
|
||||
void MiniMax::calculateDatabase(unsigned int maxDepthOfTree, bool onlyPrepareLayer)
|
||||
{
|
||||
// locals
|
||||
bool abortCalculation = false;
|
||||
this->onlyPrepareLayer = onlyPrepareLayer;
|
||||
lastCalculatedLayer.clear();
|
||||
// locals
|
||||
bool abortCalculation = false;
|
||||
this->onlyPrepareLayer = onlyPrepareLayer;
|
||||
lastCalculatedLayer.clear();
|
||||
|
||||
PRINT(1, this, "*************************");
|
||||
PRINT(1, this, "* Calculate Database *");
|
||||
PRINT(1, this, "*************************");
|
||||
PRINT(1, this, "*************************");
|
||||
PRINT(1, this, "* Calculate Database *");
|
||||
PRINT(1, this, "*************************");
|
||||
|
||||
// call preparation function of parent class
|
||||
prepareDatabaseCalculation();
|
||||
// call preparation function of parent class
|
||||
prepareDatabaseCalculation();
|
||||
|
||||
// when database not completed then do it
|
||||
if (hFileShortKnotValues != nullptr && skvfHeader.completed == false)
|
||||
{
|
||||
// when database not completed then do it
|
||||
if (hFileShortKnotValues != nullptr && skvfHeader.completed == false) {
|
||||
|
||||
// reserve memory
|
||||
lastCalculatedLayer.clear();
|
||||
depthOfFullTree = maxDepthOfTree;
|
||||
layerInDatabase = false;
|
||||
calcDatabase = true;
|
||||
threadManager.uncancelExecution();
|
||||
arrayInfos.vectorArrays.resize(ArrayInfo::numArrayTypes * skvfHeader.numLayers, arrayInfos.listArrays.end());
|
||||
// reserve memory
|
||||
lastCalculatedLayer.clear();
|
||||
depthOfFullTree = maxDepthOfTree;
|
||||
layerInDatabase = false;
|
||||
calcDatabase = true;
|
||||
threadManager.uncancelExecution();
|
||||
arrayInfos.vectorArrays.resize(ArrayInfo::numArrayTypes * skvfHeader.numLayers, arrayInfos.listArrays.end());
|
||||
|
||||
// calc layer after layer, beginning with the last one
|
||||
for (curCalculatedLayer = 0; curCalculatedLayer < skvfHeader.numLayers; curCalculatedLayer++)
|
||||
{
|
||||
// calc layer after layer, beginning with the last one
|
||||
for (curCalculatedLayer = 0; curCalculatedLayer < skvfHeader.numLayers; curCalculatedLayer++) {
|
||||
|
||||
// layer already calculated?
|
||||
if (layerStats[curCalculatedLayer].layerIsCompletedAndInFile)
|
||||
continue;
|
||||
// layer already calculated?
|
||||
if (layerStats[curCalculatedLayer].layerIsCompletedAndInFile)
|
||||
continue;
|
||||
|
||||
// don't calc if neither the layer nor the partner layer has any knots
|
||||
if (layerStats[curCalculatedLayer].knotsInLayer == 0 && layerStats[layerStats[curCalculatedLayer].partnerLayer].knotsInLayer == 0)
|
||||
continue;
|
||||
// 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;
|
||||
|
||||
// calc
|
||||
abortCalculation = (!calcLayer(curCalculatedLayer));
|
||||
// calc
|
||||
abortCalculation = (!calcLayer(curCalculatedLayer));
|
||||
|
||||
// relase memory
|
||||
unloadAllLayers();
|
||||
unloadAllPlyInfos();
|
||||
// relase memory
|
||||
unloadAllLayers();
|
||||
unloadAllPlyInfos();
|
||||
|
||||
// don't save layer and header when only preparing layers
|
||||
if (onlyPrepareLayer)
|
||||
return;
|
||||
if (abortCalculation)
|
||||
break;
|
||||
// don't save layer and header when only preparing layers
|
||||
if (onlyPrepareLayer)
|
||||
return;
|
||||
if (abortCalculation)
|
||||
break;
|
||||
|
||||
// save header
|
||||
saveHeader(&skvfHeader, layerStats);
|
||||
saveHeader(&plyInfoHeader, plyInfos);
|
||||
}
|
||||
// save header
|
||||
saveHeader(&skvfHeader, layerStats);
|
||||
saveHeader(&plyInfoHeader, plyInfos);
|
||||
}
|
||||
|
||||
// don't save layer and header when only preparing layers or when
|
||||
if (onlyPrepareLayer)
|
||||
return;
|
||||
if (!abortCalculation)
|
||||
{
|
||||
// don't save layer and header when only preparing layers or when
|
||||
if (onlyPrepareLayer)
|
||||
return;
|
||||
if (!abortCalculation) {
|
||||
|
||||
// calc layer statistics
|
||||
calcLayerStatistics("statistics.txt");
|
||||
// calc layer statistics
|
||||
calcLayerStatistics("statistics.txt");
|
||||
|
||||
// save header
|
||||
skvfHeader.completed = true;
|
||||
plyInfoHeader.plyInfoCompleted = true;
|
||||
saveHeader(&skvfHeader, layerStats);
|
||||
saveHeader(&plyInfoHeader, plyInfos);
|
||||
}
|
||||
// save header
|
||||
skvfHeader.completed = true;
|
||||
plyInfoHeader.plyInfoCompleted = true;
|
||||
saveHeader(&skvfHeader, layerStats);
|
||||
saveHeader(&plyInfoHeader, plyInfos);
|
||||
}
|
||||
|
||||
// free mem
|
||||
curCalculationActionId = MM_ACTION_NONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
PRINT(1, this, "\nThe database is already fully calculated.\n");
|
||||
}
|
||||
// free mem
|
||||
curCalculationActionId = MM_ACTION_NONE;
|
||||
} else {
|
||||
PRINT(1, this, "\nThe database is already fully calculated.\n");
|
||||
}
|
||||
|
||||
// call warp-up function of parent class
|
||||
wrapUpDatabaseCalculation(abortCalculation);
|
||||
// call warp-up function of parent class
|
||||
wrapUpDatabaseCalculation(abortCalculation);
|
||||
|
||||
PRINT(1, this, "*************************");
|
||||
PRINT(1, this, "* Calculation finished *");
|
||||
PRINT(1, this, "*************************");
|
||||
PRINT(1, this, "*************************");
|
||||
PRINT(1, this, "* Calculation finished *");
|
||||
PRINT(1, this, "*************************");
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -226,64 +218,56 @@ void MiniMax::calculateDatabase(unsigned int maxDepthOfTree, bool onlyPrepareLay
|
|||
//-----------------------------------------------------------------------------
|
||||
bool MiniMax::calcLayer(unsigned int layerNumber)
|
||||
{
|
||||
// locals
|
||||
vector<unsigned int> layersToCalculate;
|
||||
// locals
|
||||
vector<unsigned int> layersToCalculate;
|
||||
|
||||
// moves can be done reverse, leading to too depth searching trees
|
||||
if (shallRetroAnalysisBeUsed(layerNumber))
|
||||
{
|
||||
// moves can be done reverse, leading to too depth searching trees
|
||||
if (shallRetroAnalysisBeUsed(layerNumber)) {
|
||||
|
||||
// calc values for all states of layer
|
||||
layersToCalculate.push_back(layerNumber);
|
||||
if (layerNumber != layerStats[layerNumber].partnerLayer)
|
||||
layersToCalculate.push_back(layerStats[layerNumber].partnerLayer);
|
||||
if (!calcKnotValuesByRetroAnalysis(layersToCalculate))
|
||||
return false;
|
||||
// calc values for all states of layer
|
||||
layersToCalculate.push_back(layerNumber);
|
||||
if (layerNumber != layerStats[layerNumber].partnerLayer)
|
||||
layersToCalculate.push_back(layerStats[layerNumber].partnerLayer);
|
||||
if (!calcKnotValuesByRetroAnalysis(layersToCalculate))
|
||||
return false;
|
||||
|
||||
// save partner layer
|
||||
if (layerStats[layerNumber].partnerLayer != layerNumber)
|
||||
{
|
||||
saveLayerToFile(layerStats[layerNumber].partnerLayer);
|
||||
}
|
||||
// save partner layer
|
||||
if (layerStats[layerNumber].partnerLayer != layerNumber) {
|
||||
saveLayerToFile(layerStats[layerNumber].partnerLayer);
|
||||
}
|
||||
|
||||
// use minimax-algorithm
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!calcKnotValuesByAlphaBeta(layerNumber))
|
||||
return false;
|
||||
}
|
||||
// use minimax-algorithm
|
||||
} else {
|
||||
if (!calcKnotValuesByAlphaBeta(layerNumber))
|
||||
return false;
|
||||
}
|
||||
|
||||
// save layer
|
||||
saveLayerToFile(layerNumber);
|
||||
// save layer
|
||||
saveLayerToFile(layerNumber);
|
||||
|
||||
// test layer
|
||||
if (!testLayer(layerNumber))
|
||||
{
|
||||
PRINT(0, this, "ERROR: Layer calculation cancelled or failed!" << endl);
|
||||
return false;
|
||||
}
|
||||
// test layer
|
||||
if (!testLayer(layerNumber)) {
|
||||
PRINT(0, this, "ERROR: Layer calculation cancelled or failed!" << endl);
|
||||
return false;
|
||||
}
|
||||
|
||||
// test partner layer if retro-analysis has been used
|
||||
if (shallRetroAnalysisBeUsed(layerNumber) && layerStats[layerNumber].partnerLayer != layerNumber)
|
||||
{
|
||||
if (!testLayer(layerStats[layerNumber].partnerLayer))
|
||||
{
|
||||
PRINT(0, this, "ERROR: Layer calculation cancelled or failed!" << endl);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// test partner layer if retro-analysis has been used
|
||||
if (shallRetroAnalysisBeUsed(layerNumber) && layerStats[layerNumber].partnerLayer != layerNumber) {
|
||||
if (!testLayer(layerStats[layerNumber].partnerLayer)) {
|
||||
PRINT(0, this, "ERROR: Layer calculation cancelled or failed!" << endl);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// update output information
|
||||
EnterCriticalSection(&csOsPrint);
|
||||
if (shallRetroAnalysisBeUsed(layerNumber) && layerNumber != layerStats[layerNumber].partnerLayer)
|
||||
{
|
||||
lastCalculatedLayer.push_back(layerStats[layerNumber].partnerLayer);
|
||||
}
|
||||
lastCalculatedLayer.push_back(layerNumber);
|
||||
LeaveCriticalSection(&csOsPrint);
|
||||
// update output information
|
||||
EnterCriticalSection(&csOsPrint);
|
||||
if (shallRetroAnalysisBeUsed(layerNumber) && layerNumber != layerStats[layerNumber].partnerLayer) {
|
||||
lastCalculatedLayer.push_back(layerStats[layerNumber].partnerLayer);
|
||||
}
|
||||
lastCalculatedLayer.push_back(layerNumber);
|
||||
LeaveCriticalSection(&csOsPrint);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -292,7 +276,7 @@ bool MiniMax::calcLayer(unsigned int layerNumber)
|
|||
//-----------------------------------------------------------------------------
|
||||
void MiniMax::pauseDatabaseCalculation()
|
||||
{
|
||||
threadManager.pauseExecution();
|
||||
threadManager.pauseExecution();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -301,8 +285,8 @@ void MiniMax::pauseDatabaseCalculation()
|
|||
//-----------------------------------------------------------------------------
|
||||
void MiniMax::cancelDatabaseCalculation()
|
||||
{
|
||||
// when returning from executeParallelLoop() all function shall quit immediatelly up to calculateDatabase()
|
||||
threadManager.cancelExecution();
|
||||
// when returning from executeParallelLoop() all function shall quit immediatelly up to calculateDatabase()
|
||||
threadManager.cancelExecution();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -311,5 +295,5 @@ void MiniMax::cancelDatabaseCalculation()
|
|||
//-----------------------------------------------------------------------------
|
||||
bool MiniMax::wasDatabaseCalculationCancelled()
|
||||
{
|
||||
return threadManager.wasExecutionCancelled();
|
||||
return threadManager.wasExecutionCancelled();
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,9 +1,9 @@
|
|||
/*********************************************************************\
|
||||
MiniMaxAI.h
|
||||
Copyright (c) Thomas Weber. All rights reserved.
|
||||
Copyright (C) 2021 The Sanmill developers (see AUTHORS file)
|
||||
Licensed under the MIT License.
|
||||
https://github.com/madweasel/madweasels-cpp
|
||||
MiniMaxAI.h
|
||||
Copyright (c) Thomas Weber. All rights reserved.
|
||||
Copyright (C) 2021 The Sanmill developers (see AUTHORS file)
|
||||
Licensed under the MIT License.
|
||||
https://github.com/madweasel/madweasels-cpp
|
||||
\*********************************************************************/
|
||||
|
||||
#ifndef MINIMAXAI_H
|
||||
|
@ -24,112 +24,126 @@
|
|||
class MiniMaxAI : public MillAI, MiniMax
|
||||
{
|
||||
protected:
|
||||
// structs
|
||||
struct Possibility
|
||||
{
|
||||
unsigned int from[MAX_NUM_POS_MOVES];
|
||||
unsigned int to[MAX_NUM_POS_MOVES];
|
||||
};
|
||||
// structs
|
||||
struct Possibility
|
||||
{
|
||||
unsigned int from[MAX_NUM_POS_MOVES];
|
||||
unsigned int to[MAX_NUM_POS_MOVES];
|
||||
};
|
||||
|
||||
struct Backup
|
||||
{
|
||||
float value;
|
||||
bool gameHasFinished;
|
||||
bool settingPhase;
|
||||
int fieldFrom, fieldTo; // value of board
|
||||
unsigned int from, to; // index of board
|
||||
unsigned int curNumStones, oppNumStones;
|
||||
unsigned int curPosMoves, oppPosMoves;
|
||||
unsigned int curMissStones, oppMissStones;
|
||||
unsigned int stonesSet;
|
||||
unsigned int stoneMustBeRemoved;
|
||||
unsigned int stonePartOfMill[fieldStruct::size];
|
||||
unsigned int warnings[fieldStruct::size];
|
||||
Player *curPlayer, *oppPlayer;
|
||||
};
|
||||
struct Backup
|
||||
{
|
||||
float value;
|
||||
bool gameHasFinished;
|
||||
bool settingPhase;
|
||||
int fieldFrom, fieldTo; // value of board
|
||||
unsigned int from, to; // index of board
|
||||
unsigned int curNumStones, oppNumStones;
|
||||
unsigned int curPosMoves, oppPosMoves;
|
||||
unsigned int curMissStones, oppMissStones;
|
||||
unsigned int stonesSet;
|
||||
unsigned int stoneMustBeRemoved;
|
||||
unsigned int stonePartOfMill[fieldStruct::size];
|
||||
unsigned int warnings[fieldStruct::size];
|
||||
Player *curPlayer, *oppPlayer;
|
||||
};
|
||||
|
||||
// Variables
|
||||
fieldStruct *field; // pointer of the current board [changed by move()]
|
||||
float currentValue; // value of current situation for board->currentPlayer
|
||||
bool gameHasFinished; // someone has won or current board is full
|
||||
// Variables
|
||||
fieldStruct *field; // pointer of the current board [changed by move()]
|
||||
float currentValue; // value of current situation for board->currentPlayer
|
||||
bool gameHasFinished; // someone has won or current board is full
|
||||
|
||||
int ownId; // id of the player who called the play()-function
|
||||
unsigned int curSearchDepth; // current level
|
||||
unsigned int depthOfFullTree; // search depth where the whole tree is explored
|
||||
unsigned int *idPossibilities; // returned pointer of getPossibilities()-function
|
||||
Backup *oldStates; // for undo()-function
|
||||
Possibility *possibilities; // for getPossNormalMove()-function
|
||||
int ownId; // id of the player who called the play()-function
|
||||
unsigned int curSearchDepth; // current level
|
||||
unsigned int depthOfFullTree; // search depth where the whole tree is explored
|
||||
unsigned int *idPossibilities; // returned pointer of getPossibilities()-function
|
||||
Backup *oldStates; // for undo()-function
|
||||
Possibility *possibilities; // for getPossNormalMove()-function
|
||||
|
||||
// Functions
|
||||
unsigned int *getPossSettingPhase(unsigned int *numPossibilities, void **pPossibilities);
|
||||
unsigned int *getPossNormalMove(unsigned int *numPossibilities, void **pPossibilities);
|
||||
unsigned int *getPossStoneRemove(unsigned int *numPossibilities, void **pPossibilities);
|
||||
// Functions
|
||||
unsigned int *getPossSettingPhase(unsigned int *numPossibilities, void **pPossibilities);
|
||||
unsigned int *getPossNormalMove(unsigned int *numPossibilities, void **pPossibilities);
|
||||
unsigned int *getPossStoneRemove(unsigned int *numPossibilities, void **pPossibilities);
|
||||
|
||||
// move functions
|
||||
inline void updatePossibleMoves(unsigned int stone, Player *stoneOwner, bool stoneRemoved, unsigned int ignoreStone);
|
||||
inline void updateWarning(unsigned int firstStone, unsigned int secondStone);
|
||||
inline void setWarning(unsigned int stoneOne, unsigned int stoneTwo, unsigned int stoneThree);
|
||||
inline void removeStone(unsigned int from, Backup *backup);
|
||||
inline void setStone(unsigned int to, Backup *backup);
|
||||
inline void normalMove(unsigned int from, unsigned int to, Backup *backup);
|
||||
// move functions
|
||||
inline void updatePossibleMoves(unsigned int stone, Player *stoneOwner, bool stoneRemoved, unsigned int ignoreStone);
|
||||
inline void updateWarning(unsigned int firstStone, unsigned int secondStone);
|
||||
inline void setWarning(unsigned int stoneOne, unsigned int stoneTwo, unsigned int stoneThree);
|
||||
inline void removeStone(unsigned int from, Backup *backup);
|
||||
inline void setStone(unsigned int to, Backup *backup);
|
||||
inline void normalMove(unsigned int from, unsigned int to, Backup *backup);
|
||||
|
||||
// Virtual Functions
|
||||
void prepareBestChoiceCalculation();
|
||||
unsigned int *getPossibilities(unsigned int threadNo, unsigned int *numPossibilities, bool *opponentsMove, void **pPossibilities);
|
||||
void deletePossibilities(unsigned int threadNo, void *pPossibilities);
|
||||
void move(unsigned int threadNo, unsigned int idPossibility, bool opponentsMove, void **pBackup, void *pPossibilities);
|
||||
void undo(unsigned int threadNo, unsigned int idPossibility, bool opponentsMove, void *pBackup, void *pPossibilities);
|
||||
void getValueOfSituation(unsigned int threadNo, float &floatValue, TwoBit &shortValue);
|
||||
void printMoveInformation(unsigned int threadNo, unsigned int idPossibility, void *pPossibilities);
|
||||
// Virtual Functions
|
||||
void prepareBestChoiceCalculation();
|
||||
unsigned int *getPossibilities(unsigned int threadNo, unsigned int *numPossibilities, bool *opponentsMove, void **pPossibilities);
|
||||
void deletePossibilities(unsigned int threadNo, void *pPossibilities);
|
||||
void move(unsigned int threadNo, unsigned int idPossibility, bool opponentsMove, void **pBackup, void *pPossibilities);
|
||||
void undo(unsigned int threadNo, unsigned int idPossibility, bool opponentsMove, void *pBackup, void *pPossibilities);
|
||||
void getValueOfSituation(unsigned int threadNo, float &floatValue, TwoBit &shortValue);
|
||||
void printMoveInformation(unsigned int threadNo, unsigned int idPossibility, void *pPossibilities);
|
||||
|
||||
unsigned int getNumberOfLayers()
|
||||
{
|
||||
return 0;
|
||||
};
|
||||
unsigned int getNumberOfKnotsInLayer(unsigned int layerNum)
|
||||
{
|
||||
return 0;
|
||||
};
|
||||
void getSuccLayers(unsigned int layerNum, unsigned int *amountOfSuccLayers, unsigned int *succLayers){};
|
||||
unsigned int getPartnerLayer(unsigned int layerNum)
|
||||
{
|
||||
return 0;
|
||||
};
|
||||
string getOutputInformation(unsigned int layerNum)
|
||||
{
|
||||
return string("");
|
||||
};
|
||||
void setOpponentLevel(unsigned int threadNo, bool isOpponentLevel){};
|
||||
bool setSituation(unsigned int threadNo, unsigned int layerNum, unsigned int stateNumber)
|
||||
{
|
||||
return false;
|
||||
};
|
||||
bool getOpponentLevel(unsigned int threadNo)
|
||||
{
|
||||
return false;
|
||||
};
|
||||
unsigned int getLayerAndStateNumber(unsigned int threadNo, unsigned int &layerNum, unsigned int &stateNumber)
|
||||
{
|
||||
return 0;
|
||||
};
|
||||
unsigned int getLayerNumber(unsigned int threadNo)
|
||||
{
|
||||
return 0;
|
||||
};
|
||||
void getSymStateNumWithDoubles(unsigned int threadNo, unsigned int *numSymmetricStates, unsigned int **symStateNumbers){};
|
||||
void getPredecessors(unsigned int threadNo, unsigned int *amountOfPred, RetroAnalysisPredVars *predVars){};
|
||||
void printBoard(unsigned int threadNo, unsigned char value){};
|
||||
void prepareDatabaseCalculation(){};
|
||||
void wrapUpDatabaseCalculation(bool calculationAborted){};
|
||||
unsigned int getNumberOfLayers()
|
||||
{
|
||||
return 0;
|
||||
};
|
||||
unsigned int getNumberOfKnotsInLayer(unsigned int layerNum)
|
||||
{
|
||||
return 0;
|
||||
};
|
||||
void getSuccLayers(unsigned int layerNum, unsigned int *amountOfSuccLayers, unsigned int *succLayers)
|
||||
{
|
||||
};
|
||||
unsigned int getPartnerLayer(unsigned int layerNum)
|
||||
{
|
||||
return 0;
|
||||
};
|
||||
string getOutputInformation(unsigned int layerNum)
|
||||
{
|
||||
return string("");
|
||||
};
|
||||
void setOpponentLevel(unsigned int threadNo, bool isOpponentLevel)
|
||||
{
|
||||
};
|
||||
bool setSituation(unsigned int threadNo, unsigned int layerNum, unsigned int stateNumber)
|
||||
{
|
||||
return false;
|
||||
};
|
||||
bool getOpponentLevel(unsigned int threadNo)
|
||||
{
|
||||
return false;
|
||||
};
|
||||
unsigned int getLayerAndStateNumber(unsigned int threadNo, unsigned int &layerNum, unsigned int &stateNumber)
|
||||
{
|
||||
return 0;
|
||||
};
|
||||
unsigned int getLayerNumber(unsigned int threadNo)
|
||||
{
|
||||
return 0;
|
||||
};
|
||||
void getSymStateNumWithDoubles(unsigned int threadNo, unsigned int *numSymmetricStates, unsigned int **symStateNumbers)
|
||||
{
|
||||
};
|
||||
void getPredecessors(unsigned int threadNo, unsigned int *amountOfPred, RetroAnalysisPredVars *predVars)
|
||||
{
|
||||
};
|
||||
void printBoard(unsigned int threadNo, unsigned char value)
|
||||
{
|
||||
};
|
||||
void prepareDatabaseCalculation()
|
||||
{
|
||||
};
|
||||
void wrapUpDatabaseCalculation(bool calculationAborted)
|
||||
{
|
||||
};
|
||||
|
||||
public:
|
||||
// Constructor / destructor
|
||||
MiniMaxAI();
|
||||
~MiniMaxAI();
|
||||
// Constructor / destructor
|
||||
MiniMaxAI();
|
||||
~MiniMaxAI();
|
||||
|
||||
// Functions
|
||||
void play(fieldStruct *theField, unsigned int *pushFrom, unsigned int *pushTo);
|
||||
void setSearchDepth(unsigned int depth);
|
||||
// Functions
|
||||
void play(fieldStruct *theField, unsigned int *pushFrom, unsigned int *pushTo);
|
||||
void setSearchDepth(unsigned int depth);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,9 +1,9 @@
|
|||
/*********************************************************************
|
||||
miniMaxWin.h
|
||||
Copyright (c) Thomas Weber. All rights reserved.
|
||||
Copyright (C) 2021 The Sanmill developers (see AUTHORS file)
|
||||
Licensed under the MIT License.
|
||||
https://github.com/madweasel/madweasels-cpp
|
||||
miniMaxWin.h
|
||||
Copyright (c) Thomas Weber. All rights reserved.
|
||||
Copyright (C) 2021 The Sanmill developers (see AUTHORS file)
|
||||
Licensed under the MIT License.
|
||||
https://github.com/madweasel/madweasels-cpp
|
||||
\*********************************************************************/
|
||||
|
||||
#ifndef MINIMAXWIN_H
|
||||
|
@ -19,9 +19,15 @@
|
|||
class MiniMaxGuiField
|
||||
{
|
||||
public:
|
||||
virtual void setAlignment(wildWeasel::alignment &newAlignment){};
|
||||
virtual void setVisibility(bool visible){};
|
||||
virtual void setState(unsigned int curShowedLayer, MiniMax::StateNumberVarType curShowedState){};
|
||||
virtual void setAlignment(wildWeasel::alignment &newAlignment)
|
||||
{
|
||||
};
|
||||
virtual void setVisibility(bool visible)
|
||||
{
|
||||
};
|
||||
virtual void setState(unsigned int curShowedLayer, MiniMax::StateNumberVarType curShowedState)
|
||||
{
|
||||
};
|
||||
};
|
||||
|
||||
/*------------------------------------------------------------------------------------
|
||||
|
@ -52,23 +58,23 @@ public:
|
|||
class MiniMaxWinInspectDb
|
||||
{
|
||||
protected:
|
||||
// General Variables
|
||||
MiniMax *pMiniMax = nullptr; // pointer to perfect AI class granting the access to the database
|
||||
MiniMaxGuiField *pGuiField = nullptr;
|
||||
bool showingInspectionControls = false;
|
||||
unsigned int curShowedLayer = 0; // current showed layer
|
||||
MiniMax::StateNumberVarType curShowedState = 0; // current showed state
|
||||
const unsigned int scrollBarWidth = 20;
|
||||
// General Variables
|
||||
MiniMax *pMiniMax = nullptr; // pointer to perfect AI class granting the access to the database
|
||||
MiniMaxGuiField *pGuiField = nullptr;
|
||||
bool showingInspectionControls = false;
|
||||
unsigned int curShowedLayer = 0; // current showed layer
|
||||
MiniMax::StateNumberVarType curShowedState = 0; // current showed state
|
||||
const unsigned int scrollBarWidth = 20;
|
||||
|
||||
public:
|
||||
// Constructor / destructor
|
||||
MiniMaxWinInspectDb(wildWeasel::masterMind *ww, MiniMax *pMiniMax, wildWeasel::alignment &amInspectDb, wildWeasel::font2D *font, wildWeasel::texture *textureLine, MiniMaxGuiField &guiField);
|
||||
~MiniMaxWinInspectDb();
|
||||
// Constructor / destructor
|
||||
MiniMaxWinInspectDb(wildWeasel::masterMind *ww, MiniMax *pMiniMax, wildWeasel::alignment &amInspectDb, wildWeasel::font2D *font, wildWeasel::texture *textureLine, MiniMaxGuiField &guiField);
|
||||
~MiniMaxWinInspectDb();
|
||||
|
||||
// Generals Functions
|
||||
bool createControls();
|
||||
bool showControls(bool visible);
|
||||
void resize(wildWeasel::alignment &rcNewArea);
|
||||
// Generals Functions
|
||||
bool createControls();
|
||||
bool showControls(bool visible);
|
||||
void resize(wildWeasel::alignment &rcNewArea);
|
||||
};
|
||||
|
||||
/*------------------------------------------------------------------------------------
|
||||
|
@ -102,59 +108,59 @@ public:
|
|||
class MiniMaxWinCalcDb
|
||||
{
|
||||
protected:
|
||||
// Calculation variables
|
||||
wildWeasel::masterMind *ww = nullptr; // pointer to engine
|
||||
MiniMax *pMiniMax = nullptr; // pointer to perfect AI class granting the access to the database
|
||||
ostream *outputStream = nullptr; // pointer to a stream for the console output of the calculation done by the class MiniMax
|
||||
stringbuf outputStringBuf; // buffer linked to the stream, for reading out of the stream into the buffer
|
||||
locale myLocale; // for formatting the output
|
||||
queue<unsigned int> layersToTest; // layer numbers to be tested
|
||||
thread hThreadSolve;
|
||||
thread hThreadTestLayer;
|
||||
bool showingCalculationControls = false;
|
||||
bool threadSolveIsRunning = false;
|
||||
bool threadTestLayerIsRunning = false;
|
||||
condition_variable threadConditionVariable;
|
||||
mutex threadMutex;
|
||||
// Calculation variables
|
||||
wildWeasel::masterMind *ww = nullptr; // pointer to engine
|
||||
MiniMax *pMiniMax = nullptr; // pointer to perfect AI class granting the access to the database
|
||||
ostream *outputStream = nullptr; // pointer to a stream for the console output of the calculation done by the class MiniMax
|
||||
stringbuf outputStringBuf; // buffer linked to the stream, for reading out of the stream into the buffer
|
||||
locale myLocale; // for formatting the output
|
||||
queue<unsigned int> layersToTest; // layer numbers to be tested
|
||||
thread hThreadSolve;
|
||||
thread hThreadTestLayer;
|
||||
bool showingCalculationControls = false;
|
||||
bool threadSolveIsRunning = false;
|
||||
bool threadTestLayerIsRunning = false;
|
||||
condition_variable threadConditionVariable;
|
||||
mutex threadMutex;
|
||||
|
||||
// positions, metrics, sizes, dimensions
|
||||
unsigned int listViewRowHeight = 20; // height in pixel of a single row
|
||||
const float defPixelDist = 15; //
|
||||
const float labelHeight = 30; //
|
||||
const float buttonHeight = 30; //
|
||||
// positions, metrics, sizes, dimensions
|
||||
unsigned int listViewRowHeight = 20; // height in pixel of a single row
|
||||
const float defPixelDist = 15; //
|
||||
const float labelHeight = 30; //
|
||||
const float buttonHeight = 30; //
|
||||
|
||||
// Calculation Functions
|
||||
void buttonFuncCalcStartOrContinue(void *pUser);
|
||||
void buttonFuncCalcCancel(void *pUser);
|
||||
void buttonFuncCalcPause(void *pUser);
|
||||
void buttonFuncCalcTest();
|
||||
void buttonFuncCalcTestAll(void *pUser);
|
||||
void buttonFuncCalcTestLayer(void *pUser);
|
||||
void lvSelectedLayerChanged(unsigned int row, unsigned int col, wildWeasel::guiElemEvFol *guiElem, void *pUser);
|
||||
static void updateOutputControls(void *pUser);
|
||||
void updateListItemLayer(unsigned int layerNumber);
|
||||
void updateListItemArray(MiniMax::ArrayInfoChange infoChange);
|
||||
void threadSolve();
|
||||
void threadProcTestLayer();
|
||||
// Calculation Functions
|
||||
void buttonFuncCalcStartOrContinue(void *pUser);
|
||||
void buttonFuncCalcCancel(void *pUser);
|
||||
void buttonFuncCalcPause(void *pUser);
|
||||
void buttonFuncCalcTest();
|
||||
void buttonFuncCalcTestAll(void *pUser);
|
||||
void buttonFuncCalcTestLayer(void *pUser);
|
||||
void lvSelectedLayerChanged(unsigned int row, unsigned int col, wildWeasel::guiElemEvFol *guiElem, void *pUser);
|
||||
static void updateOutputControls(void *pUser);
|
||||
void updateListItemLayer(unsigned int layerNumber);
|
||||
void updateListItemArray(MiniMax::ArrayInfoChange infoChange);
|
||||
void threadSolve();
|
||||
void threadProcTestLayer();
|
||||
|
||||
public:
|
||||
// Constructor / destructor
|
||||
MiniMaxWinCalcDb(wildWeasel::masterMind *ww, MiniMax *pMiniMax, wildWeasel::alignment &amCalculation, wildWeasel::font2D *font, wildWeasel::texture *textureLine);
|
||||
~MiniMaxWinCalcDb();
|
||||
// Constructor / destructor
|
||||
MiniMaxWinCalcDb(wildWeasel::masterMind *ww, MiniMax *pMiniMax, wildWeasel::alignment &amCalculation, wildWeasel::font2D *font, wildWeasel::texture *textureLine);
|
||||
~MiniMaxWinCalcDb();
|
||||
|
||||
// Generals Functions
|
||||
bool createControls();
|
||||
void resize(wildWeasel::alignment &amNewArea);
|
||||
bool showControls(bool visible);
|
||||
bool isCalculationOngoing();
|
||||
MiniMax *getMinimaxPointer()
|
||||
{
|
||||
return pMiniMax;
|
||||
};
|
||||
CRITICAL_SECTION *getCriticalSectionOutput()
|
||||
{
|
||||
return &pMiniMax->csOsPrint;
|
||||
};
|
||||
// Generals Functions
|
||||
bool createControls();
|
||||
void resize(wildWeasel::alignment &amNewArea);
|
||||
bool showControls(bool visible);
|
||||
bool isCalculationOngoing();
|
||||
MiniMax *getMinimaxPointer()
|
||||
{
|
||||
return pMiniMax;
|
||||
};
|
||||
CRITICAL_SECTION *getCriticalSectionOutput()
|
||||
{
|
||||
return &pMiniMax->csOsPrint;
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,71 +1,71 @@
|
|||
/*********************************************************************\
|
||||
strLib.h
|
||||
Copyright (c) Thomas Weber. All rights reserved.
|
||||
Copyright (C) 2021 The Sanmill developers (see AUTHORS file)
|
||||
Licensed under the MIT License.
|
||||
https://github.com/madweasel/madweasels-cpp
|
||||
strLib.h
|
||||
Copyright (c) Thomas Weber. All rights reserved.
|
||||
Copyright (C) 2021 The Sanmill developers (see AUTHORS file)
|
||||
Licensed under the MIT License.
|
||||
https://github.com/madweasel/madweasels-cpp
|
||||
\*********************************************************************/
|
||||
|
||||
struct RetroAnalysisQueueState
|
||||
{
|
||||
StateNumberVarType stateNumber; // state stored in the retro analysis queue. the queue is a buffer containing states to be passed to 'RetroAnalysisThreadVars::statesToProcess'
|
||||
PlyInfoVarType numPliesTillCurState; // ply number for the stored state
|
||||
StateNumberVarType stateNumber; // state stored in the retro analysis queue. the queue is a buffer containing states to be passed to 'RetroAnalysisThreadVars::statesToProcess'
|
||||
PlyInfoVarType numPliesTillCurState; // ply number for the stored state
|
||||
};
|
||||
|
||||
struct RetroAnalysisThreadVars // thread specific variables for each thread in the retro analysis
|
||||
{
|
||||
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.
|
||||
long long numStatesToProcess; // Number of states in 'statesToProcess' which have to be processed
|
||||
unsigned int threadNo;
|
||||
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.
|
||||
long long numStatesToProcess; // Number of states in 'statesToProcess' which have to be processed
|
||||
unsigned int threadNo;
|
||||
};
|
||||
|
||||
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<compressorClass::compressedArrayClass *> countArraysCompr; // '' but compressed
|
||||
vector<bool> layerInitialized; //
|
||||
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 numKnotsToCalc; // number of knots of all layers to be calculated
|
||||
vector<RetroAnalysisThreadVars> thread;
|
||||
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<bool> layerInitialized; //
|
||||
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 numKnotsToCalc; // number of knots of all layers to be calculated
|
||||
vector<RetroAnalysisThreadVars> thread;
|
||||
};
|
||||
|
||||
struct InitRetroAnalysisVars
|
||||
{
|
||||
MiniMax *pMiniMax;
|
||||
unsigned int curThreadNo;
|
||||
unsigned int layerNumber;
|
||||
LONGLONG statesProcessed;
|
||||
unsigned int statsValueCounter[SKV_NUM_VALUES];
|
||||
BufferedFile *bufferedFile;
|
||||
RetroAnalysisVars *retroVars;
|
||||
bool initAlreadyDone; // true if the initialization information is already available in a file
|
||||
MiniMax *pMiniMax;
|
||||
unsigned int curThreadNo;
|
||||
unsigned int layerNumber;
|
||||
LONGLONG statesProcessed;
|
||||
unsigned int statsValueCounter[SKV_NUM_VALUES];
|
||||
BufferedFile *bufferedFile;
|
||||
RetroAnalysisVars *retroVars;
|
||||
bool initAlreadyDone; // true if the initialization information is already available in a file
|
||||
};
|
||||
|
||||
struct addSuccLayersVars
|
||||
{
|
||||
MiniMax *pMiniMax;
|
||||
unsigned int curThreadNo;
|
||||
unsigned int statsValueCounter[SKV_NUM_VALUES];
|
||||
unsigned int layerNumber;
|
||||
RetroAnalysisVars *retroVars;
|
||||
MiniMax *pMiniMax;
|
||||
unsigned int curThreadNo;
|
||||
unsigned int statsValueCounter[SKV_NUM_VALUES];
|
||||
unsigned int layerNumber;
|
||||
RetroAnalysisVars *retroVars;
|
||||
};
|
||||
|
||||
struct RetroAnalysisPredVars
|
||||
{
|
||||
unsigned int predStateNumbers;
|
||||
unsigned int predLayerNumbers;
|
||||
unsigned int predSymOperation;
|
||||
bool playerToMoveChanged;
|
||||
unsigned int predStateNumbers;
|
||||
unsigned int predLayerNumbers;
|
||||
unsigned int predSymOperation;
|
||||
bool playerToMoveChanged;
|
||||
};
|
||||
|
||||
struct AddNumSuccedorsVars
|
||||
{
|
||||
MiniMax *pMiniMax;
|
||||
unsigned int curThreadNo;
|
||||
unsigned int layerNumber;
|
||||
LONGLONG statesProcessed;
|
||||
RetroAnalysisVars *retroVars;
|
||||
RetroAnalysisPredVars *predVars;
|
||||
MiniMax *pMiniMax;
|
||||
unsigned int curThreadNo;
|
||||
unsigned int layerNumber;
|
||||
LONGLONG statesProcessed;
|
||||
RetroAnalysisVars *retroVars;
|
||||
RetroAnalysisPredVars *predVars;
|
||||
};
|
|
@ -1,9 +1,9 @@
|
|||
/*********************************************************************
|
||||
miniMax_statistics.cpp
|
||||
Copyright (c) Thomas Weber. All rights reserved.
|
||||
Copyright (C) 2021 The Sanmill developers (see AUTHORS file)
|
||||
Licensed under the MIT License.
|
||||
https://github.com/madweasel/madweasels-cpp
|
||||
miniMax_statistics.cpp
|
||||
Copyright (c) Thomas Weber. All rights reserved.
|
||||
Copyright (C) 2021 The Sanmill developers (see AUTHORS file)
|
||||
Licensed under the MIT License.
|
||||
https://github.com/madweasel/madweasels-cpp
|
||||
\*********************************************************************/
|
||||
|
||||
#include "miniMax.h"
|
||||
|
@ -14,7 +14,7 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
unsigned int MiniMax::getNumThreads()
|
||||
{
|
||||
return threadManager.getNumThreads();
|
||||
return threadManager.getNumThreads();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -23,7 +23,7 @@ unsigned int MiniMax::getNumThreads()
|
|||
//-----------------------------------------------------------------------------
|
||||
bool MiniMax::anyFreshlyCalculatedLayer()
|
||||
{
|
||||
return (lastCalculatedLayer.size() > 0);
|
||||
return (lastCalculatedLayer.size() > 0);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -32,9 +32,9 @@ bool MiniMax::anyFreshlyCalculatedLayer()
|
|||
//-----------------------------------------------------------------------------
|
||||
unsigned int MiniMax::getLastCalculatedLayer()
|
||||
{
|
||||
unsigned int tmp = lastCalculatedLayer.front();
|
||||
lastCalculatedLayer.pop_front();
|
||||
return tmp;
|
||||
unsigned int tmp = lastCalculatedLayer.front();
|
||||
lastCalculatedLayer.pop_front();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -43,8 +43,8 @@ unsigned int MiniMax::getLastCalculatedLayer()
|
|||
//-----------------------------------------------------------------------------
|
||||
bool MiniMax::isLayerInDatabase(unsigned int layerNum)
|
||||
{
|
||||
if (layerStats == nullptr) return false;
|
||||
return layerStats[layerNum].layerIsCompletedAndInFile;
|
||||
if (layerStats == nullptr) return false;
|
||||
return layerStats[layerNum].layerIsCompletedAndInFile;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -53,8 +53,8 @@ bool MiniMax::isLayerInDatabase(unsigned int layerNum)
|
|||
//-----------------------------------------------------------------------------
|
||||
long long MiniMax::getLayerSizeInBytes(unsigned int layerNum)
|
||||
{
|
||||
if (plyInfos == nullptr || layerStats == nullptr) return 0;
|
||||
return (long long)layerStats[layerNum].sizeInBytes + (long long)plyInfos[layerNum].sizeInBytes;
|
||||
if (plyInfos == nullptr || layerStats == nullptr) return 0;
|
||||
return (long long)layerStats[layerNum].sizeInBytes + (long long)plyInfos[layerNum].sizeInBytes;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -63,8 +63,8 @@ long long MiniMax::getLayerSizeInBytes(unsigned int layerNum)
|
|||
//-----------------------------------------------------------------------------
|
||||
MiniMax::StateNumberVarType MiniMax::getNumWonStates(unsigned int layerNum)
|
||||
{
|
||||
if (layerStats == nullptr) return 0;
|
||||
return layerStats[layerNum].numWonStates;
|
||||
if (layerStats == nullptr) return 0;
|
||||
return layerStats[layerNum].numWonStates;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -73,8 +73,8 @@ MiniMax::StateNumberVarType MiniMax::getNumWonStates(unsigned int layerNum)
|
|||
//-----------------------------------------------------------------------------
|
||||
MiniMax::StateNumberVarType MiniMax::getNumLostStates(unsigned int layerNum)
|
||||
{
|
||||
if (layerStats == nullptr) return 0;
|
||||
return layerStats[layerNum].numLostStates;
|
||||
if (layerStats == nullptr) return 0;
|
||||
return layerStats[layerNum].numLostStates;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -83,8 +83,8 @@ MiniMax::StateNumberVarType MiniMax::getNumLostStates(unsigned int layerNum)
|
|||
//-----------------------------------------------------------------------------
|
||||
MiniMax::StateNumberVarType MiniMax::getNumDrawnStates(unsigned int layerNum)
|
||||
{
|
||||
if (layerStats == nullptr) return 0;
|
||||
return layerStats[layerNum].numDrawnStates;
|
||||
if (layerStats == nullptr) return 0;
|
||||
return layerStats[layerNum].numDrawnStates;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -93,8 +93,8 @@ MiniMax::StateNumberVarType MiniMax::getNumDrawnStates(unsigned int layerNum)
|
|||
//-----------------------------------------------------------------------------
|
||||
MiniMax::StateNumberVarType MiniMax::getNumInvalidStates(unsigned int layerNum)
|
||||
{
|
||||
if (layerStats == nullptr) return 0;
|
||||
return layerStats[layerNum].numInvalidStates;
|
||||
if (layerStats == nullptr) return 0;
|
||||
return layerStats[layerNum].numInvalidStates;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -103,18 +103,18 @@ MiniMax::StateNumberVarType MiniMax::getNumInvalidStates(unsigned int layerNum)
|
|||
//-----------------------------------------------------------------------------
|
||||
void MiniMax::showMemoryStatus()
|
||||
{
|
||||
MEMORYSTATUSEX memStatus;
|
||||
memStatus.dwLength = sizeof(memStatus);
|
||||
GlobalMemoryStatusEx(&memStatus);
|
||||
MEMORYSTATUSEX memStatus;
|
||||
memStatus.dwLength = sizeof(memStatus);
|
||||
GlobalMemoryStatusEx(&memStatus);
|
||||
|
||||
cout << endl << "dwMemoryLoad : " << memStatus.dwMemoryLoad;
|
||||
cout << endl << "ullAvailExtendedVirtual: " << memStatus.ullAvailExtendedVirtual;
|
||||
cout << endl << "ullAvailPageFile : " << memStatus.ullAvailPageFile;
|
||||
cout << endl << "ullAvailPhys : " << memStatus.ullAvailPhys;
|
||||
cout << endl << "ullAvailVirtual : " << memStatus.ullAvailVirtual;
|
||||
cout << endl << "ullTotalPageFile : " << memStatus.ullTotalPageFile;
|
||||
cout << endl << "ullTotalPhys : " << memStatus.ullTotalPhys;
|
||||
cout << endl << "ullTotalVirtual : " << memStatus.ullTotalVirtual;
|
||||
cout << endl << "dwMemoryLoad : " << memStatus.dwMemoryLoad;
|
||||
cout << endl << "ullAvailExtendedVirtual: " << memStatus.ullAvailExtendedVirtual;
|
||||
cout << endl << "ullAvailPageFile : " << memStatus.ullAvailPageFile;
|
||||
cout << endl << "ullAvailPhys : " << memStatus.ullAvailPhys;
|
||||
cout << endl << "ullAvailVirtual : " << memStatus.ullAvailVirtual;
|
||||
cout << endl << "ullTotalPageFile : " << memStatus.ullTotalPageFile;
|
||||
cout << endl << "ullTotalPhys : " << memStatus.ullTotalPhys;
|
||||
cout << endl << "ullTotalVirtual : " << memStatus.ullTotalVirtual;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -123,9 +123,9 @@ void MiniMax::showMemoryStatus()
|
|||
//-----------------------------------------------------------------------------
|
||||
void MiniMax::setOutputStream(ostream *theStream, void(*printFunc)(void *pUserData), void *pUserData)
|
||||
{
|
||||
osPrint = theStream;
|
||||
pDataForUserPrintFunc = pUserData;
|
||||
userPrintFunc = printFunc;
|
||||
osPrint = theStream;
|
||||
pDataForUserPrintFunc = pUserData;
|
||||
userPrintFunc = printFunc;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -134,31 +134,31 @@ void MiniMax::setOutputStream(ostream *theStream, void(*printFunc)(void *pUserDa
|
|||
//-----------------------------------------------------------------------------
|
||||
void MiniMax::showLayerStats(unsigned int layerNumber)
|
||||
{
|
||||
// locals
|
||||
StateAdress curState;
|
||||
unsigned int statsValueCounter[] = { 0,0,0,0 };
|
||||
TwoBit curStateValue;
|
||||
// locals
|
||||
StateAdress curState;
|
||||
unsigned int statsValueCounter[] = { 0,0,0,0 };
|
||||
TwoBit curStateValue;
|
||||
|
||||
// calc and show statistics
|
||||
for (curState.layerNumber = layerNumber, curState.stateNumber = 0; curState.stateNumber < layerStats[curState.layerNumber].knotsInLayer; curState.stateNumber++) {
|
||||
// calc and show statistics
|
||||
for (curState.layerNumber = layerNumber, curState.stateNumber = 0; curState.stateNumber < layerStats[curState.layerNumber].knotsInLayer; curState.stateNumber++) {
|
||||
|
||||
// get state value
|
||||
readKnotValueFromDatabase(curState.layerNumber, curState.stateNumber, curStateValue);
|
||||
statsValueCounter[curStateValue]++;
|
||||
}
|
||||
// get state value
|
||||
readKnotValueFromDatabase(curState.layerNumber, curState.stateNumber, curStateValue);
|
||||
statsValueCounter[curStateValue]++;
|
||||
}
|
||||
|
||||
layerStats[layerNumber].numWonStates = statsValueCounter[SKV_VALUE_GAME_WON];
|
||||
layerStats[layerNumber].numLostStates = statsValueCounter[SKV_VALUE_GAME_LOST];
|
||||
layerStats[layerNumber].numDrawnStates = statsValueCounter[SKV_VALUE_GAME_DRAWN];
|
||||
layerStats[layerNumber].numInvalidStates = statsValueCounter[SKV_VALUE_INVALID];
|
||||
layerStats[layerNumber].numWonStates = statsValueCounter[SKV_VALUE_GAME_WON];
|
||||
layerStats[layerNumber].numLostStates = statsValueCounter[SKV_VALUE_GAME_LOST];
|
||||
layerStats[layerNumber].numDrawnStates = statsValueCounter[SKV_VALUE_GAME_DRAWN];
|
||||
layerStats[layerNumber].numInvalidStates = statsValueCounter[SKV_VALUE_INVALID];
|
||||
|
||||
PRINT(1, this, endl << "FINAL STATISTICS OF LAYER " << layerNumber);
|
||||
PRINT(1, this, (getOutputInformation(layerNumber)));
|
||||
PRINT(1, this, " number states: " << layerStats[curState.layerNumber].knotsInLayer);
|
||||
PRINT(1, this, " won states: " << statsValueCounter[SKV_VALUE_GAME_WON]);
|
||||
PRINT(1, this, " lost states: " << statsValueCounter[SKV_VALUE_GAME_LOST]);
|
||||
PRINT(1, this, " draw states: " << statsValueCounter[SKV_VALUE_GAME_DRAWN]);
|
||||
PRINT(1, this, " invalid states: " << statsValueCounter[SKV_VALUE_INVALID]);
|
||||
PRINT(1, this, endl << "FINAL STATISTICS OF LAYER " << layerNumber);
|
||||
PRINT(1, this, (getOutputInformation(layerNumber)));
|
||||
PRINT(1, this, " number states: " << layerStats[curState.layerNumber].knotsInLayer);
|
||||
PRINT(1, this, " won states: " << statsValueCounter[SKV_VALUE_GAME_WON]);
|
||||
PRINT(1, this, " lost states: " << statsValueCounter[SKV_VALUE_GAME_LOST]);
|
||||
PRINT(1, this, " draw states: " << statsValueCounter[SKV_VALUE_GAME_DRAWN]);
|
||||
PRINT(1, this, " invalid states: " << statsValueCounter[SKV_VALUE_INVALID]);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -167,93 +167,93 @@ void MiniMax::showLayerStats(unsigned int layerNumber)
|
|||
//-----------------------------------------------------------------------------
|
||||
bool MiniMax::calcLayerStatistics(char *statisticsFileName)
|
||||
{
|
||||
// locals
|
||||
HANDLE statFile;
|
||||
DWORD dwBytesWritten;
|
||||
StateAdress curState;
|
||||
unsigned int *statsValueCounter;
|
||||
TwoBit curStateValue;
|
||||
char line[10000];
|
||||
string text("");
|
||||
// locals
|
||||
HANDLE statFile;
|
||||
DWORD dwBytesWritten;
|
||||
StateAdress curState;
|
||||
unsigned int *statsValueCounter;
|
||||
TwoBit curStateValue;
|
||||
char line[10000];
|
||||
string text("");
|
||||
|
||||
// database must be open
|
||||
if (hFileShortKnotValues == nullptr) return false;
|
||||
// database must be open
|
||||
if (hFileShortKnotValues == nullptr) return false;
|
||||
|
||||
// Open statistics file
|
||||
statFile = CreateFileA(statisticsFileName, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
// Open statistics file
|
||||
statFile = CreateFileA(statisticsFileName, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
|
||||
// opened file succesfully?
|
||||
if (statFile == INVALID_HANDLE_VALUE) {
|
||||
statFile = nullptr;
|
||||
return false;
|
||||
}
|
||||
// opened file succesfully?
|
||||
if (statFile == INVALID_HANDLE_VALUE) {
|
||||
statFile = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
// headline
|
||||
text += "layer number\t";
|
||||
text += "white stones\t";
|
||||
text += "black stones\t";
|
||||
text += "won states\t";
|
||||
text += "lost states\t";
|
||||
text += "draw states\t";
|
||||
text += "invalid states\t";
|
||||
text += "total num states\t";
|
||||
text += "num succeding layers\t";
|
||||
text += "partner layer\t";
|
||||
text += "size in bytes\t";
|
||||
text += "succLayers[0]\t";
|
||||
text += "succLayers[1]\n";
|
||||
// headline
|
||||
text += "layer number\t";
|
||||
text += "white stones\t";
|
||||
text += "black stones\t";
|
||||
text += "won states\t";
|
||||
text += "lost states\t";
|
||||
text += "draw states\t";
|
||||
text += "invalid states\t";
|
||||
text += "total num states\t";
|
||||
text += "num succeding layers\t";
|
||||
text += "partner layer\t";
|
||||
text += "size in bytes\t";
|
||||
text += "succLayers[0]\t";
|
||||
text += "succLayers[1]\n";
|
||||
|
||||
statsValueCounter = new unsigned int[4 * skvfHeader.numLayers];
|
||||
curCalculationActionId = MM_ACTION_CALC_LAYER_STATS;
|
||||
statsValueCounter = new unsigned int[4 * skvfHeader.numLayers];
|
||||
curCalculationActionId = MM_ACTION_CALC_LAYER_STATS;
|
||||
|
||||
// calc and show statistics
|
||||
for (layerInDatabase = false, curState.layerNumber = 0; curState.layerNumber < skvfHeader.numLayers; curState.layerNumber++) {
|
||||
// calc and show statistics
|
||||
for (layerInDatabase = false, curState.layerNumber = 0; curState.layerNumber < skvfHeader.numLayers; curState.layerNumber++) {
|
||||
|
||||
// status output
|
||||
PRINT(0, this, "Calculating statistics of layer: " << (int)curState.layerNumber);
|
||||
// status output
|
||||
PRINT(0, this, "Calculating statistics of layer: " << (int)curState.layerNumber);
|
||||
|
||||
// zero counters
|
||||
statsValueCounter[4 * curState.layerNumber + SKV_VALUE_GAME_WON] = 0;
|
||||
statsValueCounter[4 * curState.layerNumber + SKV_VALUE_GAME_LOST] = 0;
|
||||
statsValueCounter[4 * curState.layerNumber + SKV_VALUE_GAME_DRAWN] = 0;
|
||||
statsValueCounter[4 * curState.layerNumber + SKV_VALUE_INVALID] = 0;
|
||||
// zero counters
|
||||
statsValueCounter[4 * curState.layerNumber + SKV_VALUE_GAME_WON] = 0;
|
||||
statsValueCounter[4 * curState.layerNumber + SKV_VALUE_GAME_LOST] = 0;
|
||||
statsValueCounter[4 * curState.layerNumber + SKV_VALUE_GAME_DRAWN] = 0;
|
||||
statsValueCounter[4 * curState.layerNumber + SKV_VALUE_INVALID] = 0;
|
||||
|
||||
// only calc stats of completed layers
|
||||
if (layerStats[curState.layerNumber].layerIsCompletedAndInFile) {
|
||||
// only calc stats of completed layers
|
||||
if (layerStats[curState.layerNumber].layerIsCompletedAndInFile) {
|
||||
|
||||
for (curState.stateNumber = 0; curState.stateNumber < layerStats[curState.layerNumber].knotsInLayer; curState.stateNumber++) {
|
||||
for (curState.stateNumber = 0; curState.stateNumber < layerStats[curState.layerNumber].knotsInLayer; curState.stateNumber++) {
|
||||
|
||||
// get state value
|
||||
readKnotValueFromDatabase(curState.layerNumber, curState.stateNumber, curStateValue);
|
||||
statsValueCounter[4 * curState.layerNumber + curStateValue]++;
|
||||
}
|
||||
// get state value
|
||||
readKnotValueFromDatabase(curState.layerNumber, curState.stateNumber, curStateValue);
|
||||
statsValueCounter[4 * curState.layerNumber + curStateValue]++;
|
||||
}
|
||||
|
||||
// free memory
|
||||
unloadLayer(curState.layerNumber);
|
||||
}
|
||||
// free memory
|
||||
unloadLayer(curState.layerNumber);
|
||||
}
|
||||
|
||||
// add line
|
||||
sprintf_s(line, "%d\t%s\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n",
|
||||
curState.layerNumber,
|
||||
getOutputInformation(curState.layerNumber).c_str(),
|
||||
statsValueCounter[4 * curState.layerNumber + SKV_VALUE_GAME_WON],
|
||||
statsValueCounter[4 * curState.layerNumber + SKV_VALUE_GAME_LOST],
|
||||
statsValueCounter[4 * curState.layerNumber + SKV_VALUE_GAME_DRAWN],
|
||||
statsValueCounter[4 * curState.layerNumber + SKV_VALUE_INVALID],
|
||||
layerStats[curState.layerNumber].knotsInLayer,
|
||||
layerStats[curState.layerNumber].numSuccLayers,
|
||||
layerStats[curState.layerNumber].partnerLayer,
|
||||
layerStats[curState.layerNumber].sizeInBytes,
|
||||
layerStats[curState.layerNumber].succLayers[0],
|
||||
layerStats[curState.layerNumber].succLayers[1]);
|
||||
text += line;
|
||||
}
|
||||
// add line
|
||||
sprintf_s(line, "%d\t%s\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n",
|
||||
curState.layerNumber,
|
||||
getOutputInformation(curState.layerNumber).c_str(),
|
||||
statsValueCounter[4 * curState.layerNumber + SKV_VALUE_GAME_WON],
|
||||
statsValueCounter[4 * curState.layerNumber + SKV_VALUE_GAME_LOST],
|
||||
statsValueCounter[4 * curState.layerNumber + SKV_VALUE_GAME_DRAWN],
|
||||
statsValueCounter[4 * curState.layerNumber + SKV_VALUE_INVALID],
|
||||
layerStats[curState.layerNumber].knotsInLayer,
|
||||
layerStats[curState.layerNumber].numSuccLayers,
|
||||
layerStats[curState.layerNumber].partnerLayer,
|
||||
layerStats[curState.layerNumber].sizeInBytes,
|
||||
layerStats[curState.layerNumber].succLayers[0],
|
||||
layerStats[curState.layerNumber].succLayers[1]);
|
||||
text += line;
|
||||
}
|
||||
|
||||
// write to file and close it
|
||||
WriteFile(statFile, text.c_str(), (DWORD)text.length(), &dwBytesWritten, nullptr);
|
||||
CloseHandle(statFile);
|
||||
SAFE_DELETE_ARRAY(statsValueCounter);
|
||||
return true;
|
||||
// write to file and close it
|
||||
WriteFile(statFile, text.c_str(), (DWORD)text.length(), &dwBytesWritten, nullptr);
|
||||
CloseHandle(statFile);
|
||||
SAFE_DELETE_ARRAY(statsValueCounter);
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -262,7 +262,7 @@ bool MiniMax::calcLayerStatistics(char *statisticsFileName)
|
|||
//-----------------------------------------------------------------------------
|
||||
bool MiniMax::anyArrawInfoToUpdate()
|
||||
{
|
||||
return (arrayInfos.arrayInfosToBeUpdated.size() > 0);
|
||||
return (arrayInfos.arrayInfosToBeUpdated.size() > 0);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -271,9 +271,9 @@ bool MiniMax::anyArrawInfoToUpdate()
|
|||
//-----------------------------------------------------------------------------
|
||||
MiniMax::ArrayInfoChange MiniMax::getArrayInfoForUpdate()
|
||||
{
|
||||
MiniMax::ArrayInfoChange tmp = arrayInfos.arrayInfosToBeUpdated.front();
|
||||
arrayInfos.arrayInfosToBeUpdated.pop_front();
|
||||
return tmp;
|
||||
MiniMax::ArrayInfoChange tmp = arrayInfos.arrayInfosToBeUpdated.front();
|
||||
arrayInfos.arrayInfosToBeUpdated.pop_front();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -282,17 +282,17 @@ MiniMax::ArrayInfoChange MiniMax::getArrayInfoForUpdate()
|
|||
//-----------------------------------------------------------------------------
|
||||
LPWSTR MiniMax::getCurrentActionStr()
|
||||
{
|
||||
switch (curCalculationActionId) {
|
||||
case MM_ACTION_INIT_RETRO_ANAL: return L"initiating retro-analysis";
|
||||
case MM_ACTION_PREPARE_COUNT_ARRAY: return L"preparing count arrays";
|
||||
case MM_ACTION_PERFORM_RETRO_ANAL: return L"performing retro analysis";
|
||||
case MM_ACTION_PERFORM_ALPHA_BETA: return L"performing alpha-beta-algorithmn";
|
||||
case MM_ACTION_TESTING_LAYER: return L"testing calculated layer";
|
||||
case MM_ACTION_SAVING_LAYER_TO_FILE: return L"saving layer to file";
|
||||
case MM_ACTION_CALC_LAYER_STATS: return L"making layer statistics";
|
||||
case MM_ACTION_NONE: return L"none";
|
||||
default: return L"undefined";
|
||||
}
|
||||
switch (curCalculationActionId) {
|
||||
case MM_ACTION_INIT_RETRO_ANAL: return L"initiating retro-analysis";
|
||||
case MM_ACTION_PREPARE_COUNT_ARRAY: return L"preparing count arrays";
|
||||
case MM_ACTION_PERFORM_RETRO_ANAL: return L"performing retro analysis";
|
||||
case MM_ACTION_PERFORM_ALPHA_BETA: return L"performing alpha-beta-algorithmn";
|
||||
case MM_ACTION_TESTING_LAYER: return L"testing calculated layer";
|
||||
case MM_ACTION_SAVING_LAYER_TO_FILE: return L"saving layer to file";
|
||||
case MM_ACTION_CALC_LAYER_STATS: return L"making layer statistics";
|
||||
case MM_ACTION_NONE: return L"none";
|
||||
default: return L"undefined";
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -301,15 +301,15 @@ LPWSTR MiniMax::getCurrentActionStr()
|
|||
//-----------------------------------------------------------------------------
|
||||
void MiniMax::getCurrentCalculatedLayer(vector<unsigned int> &layers)
|
||||
{
|
||||
// when retro-analysis is used than two layers are calculated at the same time
|
||||
if (shallRetroAnalysisBeUsed(curCalculatedLayer) && layerStats[curCalculatedLayer].partnerLayer != curCalculatedLayer) {
|
||||
layers.resize(2);
|
||||
layers[0] = curCalculatedLayer;
|
||||
layers[1] = layerStats[curCalculatedLayer].partnerLayer;
|
||||
} else {
|
||||
layers.resize(1);
|
||||
layers[0] = curCalculatedLayer;
|
||||
}
|
||||
// when retro-analysis is used than two layers are calculated at the same time
|
||||
if (shallRetroAnalysisBeUsed(curCalculatedLayer) && layerStats[curCalculatedLayer].partnerLayer != curCalculatedLayer) {
|
||||
layers.resize(2);
|
||||
layers[0] = curCalculatedLayer;
|
||||
layers[1] = layerStats[curCalculatedLayer].partnerLayer;
|
||||
} else {
|
||||
layers.resize(1);
|
||||
layers[0] = curCalculatedLayer;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -319,30 +319,30 @@ void MiniMax::getCurrentCalculatedLayer(vector<unsigned int> &layers)
|
|||
//-----------------------------------------------------------------------------
|
||||
void MiniMax::ArrayInfoContainer::addArray(unsigned int layerNumber, unsigned int type, long long size, long long compressedSize)
|
||||
{
|
||||
// create new info object and add to list
|
||||
EnterCriticalSection(&c->csOsPrint);
|
||||
ArrayInfo ais;
|
||||
ais.belongsToLayer = layerNumber;
|
||||
ais.compressedSizeInBytes = compressedSize;
|
||||
ais.sizeInBytes = size;
|
||||
ais.type = type;
|
||||
ais.updateCounter = 0;
|
||||
listArrays.push_back(ais);
|
||||
// create new info object and add to list
|
||||
EnterCriticalSection(&c->csOsPrint);
|
||||
ArrayInfo ais;
|
||||
ais.belongsToLayer = layerNumber;
|
||||
ais.compressedSizeInBytes = compressedSize;
|
||||
ais.sizeInBytes = size;
|
||||
ais.type = type;
|
||||
ais.updateCounter = 0;
|
||||
listArrays.push_back(ais);
|
||||
|
||||
// notify cahnge
|
||||
ArrayInfoChange aic;
|
||||
aic.arrayInfo = &listArrays.back();
|
||||
aic.itemIndex = (unsigned int)listArrays.size() - 1;
|
||||
arrayInfosToBeUpdated.push_back(aic);
|
||||
// notify cahnge
|
||||
ArrayInfoChange aic;
|
||||
aic.arrayInfo = &listArrays.back();
|
||||
aic.itemIndex = (unsigned int)listArrays.size() - 1;
|
||||
arrayInfosToBeUpdated.push_back(aic);
|
||||
|
||||
// save pointer of info in vector for direct access
|
||||
vectorArrays[layerNumber * ArrayInfo::numArrayTypes + type] = (--listArrays.end());
|
||||
// save pointer of info in vector for direct access
|
||||
vectorArrays[layerNumber * ArrayInfo::numArrayTypes + type] = (--listArrays.end());
|
||||
|
||||
// update GUI
|
||||
if (c->userPrintFunc != nullptr) {
|
||||
c->userPrintFunc(c->pDataForUserPrintFunc);
|
||||
}
|
||||
LeaveCriticalSection(&c->csOsPrint);
|
||||
// update GUI
|
||||
if (c->userPrintFunc != nullptr) {
|
||||
c->userPrintFunc(c->pDataForUserPrintFunc);
|
||||
}
|
||||
LeaveCriticalSection(&c->csOsPrint);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -351,34 +351,34 @@ void MiniMax::ArrayInfoContainer::addArray(unsigned int layerNumber, unsigned in
|
|||
//-----------------------------------------------------------------------------
|
||||
void MiniMax::ArrayInfoContainer::removeArray(unsigned int layerNumber, unsigned int type, long long size, long long compressedSize)
|
||||
{
|
||||
// find info object in list
|
||||
EnterCriticalSection(&c->csOsPrint);
|
||||
// find info object in list
|
||||
EnterCriticalSection(&c->csOsPrint);
|
||||
|
||||
if (vectorArrays.size() > layerNumber * ArrayInfo::numArrayTypes + type) {
|
||||
list<ArrayInfo>::iterator itr = vectorArrays[layerNumber * ArrayInfo::numArrayTypes + type];
|
||||
if (itr != listArrays.end()) {
|
||||
if (vectorArrays.size() > layerNumber * ArrayInfo::numArrayTypes + type) {
|
||||
list<ArrayInfo>::iterator itr = vectorArrays[layerNumber * ArrayInfo::numArrayTypes + type];
|
||||
if (itr != listArrays.end()) {
|
||||
|
||||
// does sizes fit?
|
||||
if (itr->belongsToLayer != layerNumber || itr->type != type || itr->sizeInBytes != size || itr->compressedSizeInBytes != compressedSize) {
|
||||
c->falseOrStop();
|
||||
}
|
||||
// does sizes fit?
|
||||
if (itr->belongsToLayer != layerNumber || itr->type != type || itr->sizeInBytes != size || itr->compressedSizeInBytes != compressedSize) {
|
||||
c->falseOrStop();
|
||||
}
|
||||
|
||||
// notify cahnge
|
||||
ArrayInfoChange aic;
|
||||
aic.arrayInfo = nullptr;
|
||||
aic.itemIndex = (unsigned int)std::distance(listArrays.begin(), itr);
|
||||
arrayInfosToBeUpdated.push_back(aic);
|
||||
// notify cahnge
|
||||
ArrayInfoChange aic;
|
||||
aic.arrayInfo = nullptr;
|
||||
aic.itemIndex = (unsigned int)std::distance(listArrays.begin(), itr);
|
||||
arrayInfosToBeUpdated.push_back(aic);
|
||||
|
||||
// delete tem from list
|
||||
listArrays.erase(itr);
|
||||
}
|
||||
}
|
||||
// delete tem from list
|
||||
listArrays.erase(itr);
|
||||
}
|
||||
}
|
||||
|
||||
// update GUI
|
||||
if (c->userPrintFunc != nullptr) {
|
||||
c->userPrintFunc(c->pDataForUserPrintFunc);
|
||||
}
|
||||
LeaveCriticalSection(&c->csOsPrint);
|
||||
// update GUI
|
||||
if (c->userPrintFunc != nullptr) {
|
||||
c->userPrintFunc(c->pDataForUserPrintFunc);
|
||||
}
|
||||
LeaveCriticalSection(&c->csOsPrint);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -387,24 +387,24 @@ void MiniMax::ArrayInfoContainer::removeArray(unsigned int layerNumber, unsigned
|
|||
//-----------------------------------------------------------------------------
|
||||
void MiniMax::ArrayInfoContainer::updateArray(unsigned int layerNumber, unsigned int type)
|
||||
{
|
||||
// find info object in list
|
||||
list<ArrayInfo>::iterator itr = vectorArrays[layerNumber * ArrayInfo::numArrayTypes + type];
|
||||
// find info object in list
|
||||
list<ArrayInfo>::iterator itr = vectorArrays[layerNumber * ArrayInfo::numArrayTypes + type];
|
||||
|
||||
itr->updateCounter++;
|
||||
if (itr->updateCounter > ArrayInfo::updateCounterThreshold) {
|
||||
itr->updateCounter++;
|
||||
if (itr->updateCounter > ArrayInfo::updateCounterThreshold) {
|
||||
|
||||
// notify cahnge
|
||||
EnterCriticalSection(&c->csOsPrint);
|
||||
ArrayInfoChange aic;
|
||||
aic.arrayInfo = &(*itr);
|
||||
aic.itemIndex = (unsigned int)std::distance(listArrays.begin(), itr);
|
||||
arrayInfosToBeUpdated.push_back(aic);
|
||||
// notify cahnge
|
||||
EnterCriticalSection(&c->csOsPrint);
|
||||
ArrayInfoChange aic;
|
||||
aic.arrayInfo = &(*itr);
|
||||
aic.itemIndex = (unsigned int)std::distance(listArrays.begin(), itr);
|
||||
arrayInfosToBeUpdated.push_back(aic);
|
||||
|
||||
// update GUI
|
||||
if (c->userPrintFunc != nullptr) {
|
||||
c->userPrintFunc(c->pDataForUserPrintFunc);
|
||||
}
|
||||
itr->updateCounter = 0;
|
||||
LeaveCriticalSection(&c->csOsPrint);
|
||||
}
|
||||
// update GUI
|
||||
if (c->userPrintFunc != nullptr) {
|
||||
c->userPrintFunc(c->pDataForUserPrintFunc);
|
||||
}
|
||||
itr->updateCounter = 0;
|
||||
LeaveCriticalSection(&c->csOsPrint);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,9 +1,9 @@
|
|||
/*********************************************************************\
|
||||
PerfectAI.h
|
||||
Copyright (c) Thomas Weber. All rights reserved.
|
||||
Copyright (C) 2021 The Sanmill developers (see AUTHORS file)
|
||||
Licensed under the MIT License.
|
||||
https://github.com/madweasel/madweasels-cpp
|
||||
PerfectAI.h
|
||||
Copyright (c) Thomas Weber. All rights reserved.
|
||||
Copyright (C) 2021 The Sanmill developers (see AUTHORS file)
|
||||
Licensed under the MIT License.
|
||||
https://github.com/madweasel/madweasels-cpp
|
||||
\*********************************************************************/
|
||||
|
||||
#ifndef PERFEKT_AI_H
|
||||
|
@ -78,166 +78,166 @@
|
|||
class PerfectAI : public MillAI, public MiniMax
|
||||
{
|
||||
protected:
|
||||
// structs
|
||||
struct SubLayer
|
||||
{
|
||||
unsigned int minIndex;
|
||||
unsigned int maxIndex;
|
||||
unsigned int numWhiteStonesGroupCD, numBlackStonesGroupCD;
|
||||
unsigned int numWhiteStonesGroupAB, numBlackStonesGroupAB;
|
||||
};
|
||||
// structs
|
||||
struct SubLayer
|
||||
{
|
||||
unsigned int minIndex;
|
||||
unsigned int maxIndex;
|
||||
unsigned int numWhiteStonesGroupCD, numBlackStonesGroupCD;
|
||||
unsigned int numWhiteStonesGroupAB, numBlackStonesGroupAB;
|
||||
};
|
||||
|
||||
struct Layer
|
||||
{
|
||||
unsigned int numWhiteStones;
|
||||
unsigned int numBlackStones;
|
||||
unsigned int numSubLayers;
|
||||
unsigned int subLayerIndexAB[NUM_STONES_PER_PLAYER_PLUS_ONE][NUM_STONES_PER_PLAYER_PLUS_ONE];
|
||||
unsigned int subLayerIndexCD[NUM_STONES_PER_PLAYER_PLUS_ONE][NUM_STONES_PER_PLAYER_PLUS_ONE];
|
||||
SubLayer subLayer[MAX_NUM_SUB_LAYERS];
|
||||
};
|
||||
struct Layer
|
||||
{
|
||||
unsigned int numWhiteStones;
|
||||
unsigned int numBlackStones;
|
||||
unsigned int numSubLayers;
|
||||
unsigned int subLayerIndexAB[NUM_STONES_PER_PLAYER_PLUS_ONE][NUM_STONES_PER_PLAYER_PLUS_ONE];
|
||||
unsigned int subLayerIndexCD[NUM_STONES_PER_PLAYER_PLUS_ONE][NUM_STONES_PER_PLAYER_PLUS_ONE];
|
||||
SubLayer subLayer[MAX_NUM_SUB_LAYERS];
|
||||
};
|
||||
|
||||
struct Possibility
|
||||
{
|
||||
unsigned int from[MAX_NUM_POS_MOVES];
|
||||
unsigned int to[MAX_NUM_POS_MOVES];
|
||||
};
|
||||
struct Possibility
|
||||
{
|
||||
unsigned int from[MAX_NUM_POS_MOVES];
|
||||
unsigned int to[MAX_NUM_POS_MOVES];
|
||||
};
|
||||
|
||||
struct Backup
|
||||
{
|
||||
float floatValue;
|
||||
TwoBit shortValue;
|
||||
bool gameHasFinished;
|
||||
bool settingPhase;
|
||||
int fieldFrom, fieldTo; // value of board
|
||||
unsigned int from, to; // index of board
|
||||
unsigned int curNumStones, oppNumStones;
|
||||
unsigned int curPosMoves, oppPosMoves;
|
||||
unsigned int curMissStones, oppMissStones;
|
||||
unsigned int stonesSet;
|
||||
unsigned int stoneMustBeRemoved;
|
||||
unsigned int stonePartOfMill[fieldStruct::size];
|
||||
Player *curPlayer, *oppPlayer;
|
||||
};
|
||||
struct Backup
|
||||
{
|
||||
float floatValue;
|
||||
TwoBit shortValue;
|
||||
bool gameHasFinished;
|
||||
bool settingPhase;
|
||||
int fieldFrom, fieldTo; // value of board
|
||||
unsigned int from, to; // index of board
|
||||
unsigned int curNumStones, oppNumStones;
|
||||
unsigned int curPosMoves, oppPosMoves;
|
||||
unsigned int curMissStones, oppMissStones;
|
||||
unsigned int stonesSet;
|
||||
unsigned int stoneMustBeRemoved;
|
||||
unsigned int stonePartOfMill[fieldStruct::size];
|
||||
Player *curPlayer, *oppPlayer;
|
||||
};
|
||||
|
||||
// preCalcedVars.dat
|
||||
struct PreCalcedVarsFileHeader
|
||||
{
|
||||
unsigned int sizeInBytes;
|
||||
};
|
||||
// preCalcedVars.dat
|
||||
struct PreCalcedVarsFileHeader
|
||||
{
|
||||
unsigned int sizeInBytes;
|
||||
};
|
||||
|
||||
// constant variables for state addressing in the database
|
||||
Layer layer[NUM_LAYERS]; // the layers
|
||||
unsigned int layerIndex[2][NUM_STONES_PER_PLAYER_PLUS_ONE][NUM_STONES_PER_PLAYER_PLUS_ONE]; // indices of layer [moving/setting phase][number of white stones][number of black stones]
|
||||
unsigned int anzahlStellungenCD[NUM_STONES_PER_PLAYER_PLUS_ONE][NUM_STONES_PER_PLAYER_PLUS_ONE];
|
||||
unsigned int anzahlStellungenAB[NUM_STONES_PER_PLAYER_PLUS_ONE][NUM_STONES_PER_PLAYER_PLUS_ONE];
|
||||
unsigned int indexAB[MAX_ANZ_STELLUNGEN_A * MAX_ANZ_STELLUNGEN_B];
|
||||
unsigned int indexCD[MAX_ANZ_STELLUNGEN_C * MAX_ANZ_STELLUNGEN_D];
|
||||
unsigned char symmetryOperationCD[MAX_ANZ_STELLUNGEN_C * MAX_ANZ_STELLUNGEN_D]; // index of symmetry operation used to get from the original state to the current one
|
||||
unsigned int powerOfThree[numSquaresGroupC + numSquaresGroupD]; // 3^0, 3^1, 3^2, ...
|
||||
unsigned int symmetryOperationTable[NUM_SYM_OPERATIONS][fieldStruct::size]; // Matrix used for application of the symmetry operations
|
||||
unsigned int *originalStateCD[NUM_STONES_PER_PLAYER_PLUS_ONE][NUM_STONES_PER_PLAYER_PLUS_ONE];
|
||||
unsigned int *originalStateAB[NUM_STONES_PER_PLAYER_PLUS_ONE][NUM_STONES_PER_PLAYER_PLUS_ONE];
|
||||
unsigned int reverseSymOperation[NUM_SYM_OPERATIONS]; // index of the reverse symmetry operation
|
||||
unsigned int concSymOperation[NUM_SYM_OPERATIONS][NUM_SYM_OPERATIONS]; // symmetry operation, which is identical to applying those two in the index
|
||||
unsigned int mOverN[fieldStruct::size + 1][fieldStruct::size + 1]; // m over n
|
||||
unsigned char valueOfMove[fieldStruct::size * fieldStruct::size]; // contains the value of the situation, which will be achieved by that move
|
||||
unsigned short plyInfoForOutput[fieldStruct::size * fieldStruct::size]; // contains the value of the situation, which will be achieved by that move
|
||||
unsigned int incidencesValuesSubMoves[fieldStruct::size * fieldStruct::size][4]; // contains the number of ...
|
||||
unsigned int symmetricStateNumberArray[NUM_SYM_OPERATIONS]; // array for state numbers
|
||||
string databaseDirectory; // directory containing the database files
|
||||
// constant variables for state addressing in the database
|
||||
Layer layer[NUM_LAYERS]; // the layers
|
||||
unsigned int layerIndex[2][NUM_STONES_PER_PLAYER_PLUS_ONE][NUM_STONES_PER_PLAYER_PLUS_ONE]; // indices of layer [moving/setting phase][number of white stones][number of black stones]
|
||||
unsigned int anzahlStellungenCD[NUM_STONES_PER_PLAYER_PLUS_ONE][NUM_STONES_PER_PLAYER_PLUS_ONE];
|
||||
unsigned int anzahlStellungenAB[NUM_STONES_PER_PLAYER_PLUS_ONE][NUM_STONES_PER_PLAYER_PLUS_ONE];
|
||||
unsigned int indexAB[MAX_ANZ_STELLUNGEN_A * MAX_ANZ_STELLUNGEN_B];
|
||||
unsigned int indexCD[MAX_ANZ_STELLUNGEN_C * MAX_ANZ_STELLUNGEN_D];
|
||||
unsigned char symmetryOperationCD[MAX_ANZ_STELLUNGEN_C * MAX_ANZ_STELLUNGEN_D]; // index of symmetry operation used to get from the original state to the current one
|
||||
unsigned int powerOfThree[numSquaresGroupC + numSquaresGroupD]; // 3^0, 3^1, 3^2, ...
|
||||
unsigned int symmetryOperationTable[NUM_SYM_OPERATIONS][fieldStruct::size]; // Matrix used for application of the symmetry operations
|
||||
unsigned int *originalStateCD[NUM_STONES_PER_PLAYER_PLUS_ONE][NUM_STONES_PER_PLAYER_PLUS_ONE];
|
||||
unsigned int *originalStateAB[NUM_STONES_PER_PLAYER_PLUS_ONE][NUM_STONES_PER_PLAYER_PLUS_ONE];
|
||||
unsigned int reverseSymOperation[NUM_SYM_OPERATIONS]; // index of the reverse symmetry operation
|
||||
unsigned int concSymOperation[NUM_SYM_OPERATIONS][NUM_SYM_OPERATIONS]; // symmetry operation, which is identical to applying those two in the index
|
||||
unsigned int mOverN[fieldStruct::size + 1][fieldStruct::size + 1]; // m over n
|
||||
unsigned char valueOfMove[fieldStruct::size * fieldStruct::size]; // contains the value of the situation, which will be achieved by that move
|
||||
unsigned short plyInfoForOutput[fieldStruct::size * fieldStruct::size]; // contains the value of the situation, which will be achieved by that move
|
||||
unsigned int incidencesValuesSubMoves[fieldStruct::size * fieldStruct::size][4]; // contains the number of ...
|
||||
unsigned int symmetricStateNumberArray[NUM_SYM_OPERATIONS]; // array for state numbers
|
||||
string databaseDirectory; // directory containing the database files
|
||||
|
||||
// Variables used individually by each single thread
|
||||
class ThreadVars
|
||||
{
|
||||
public:
|
||||
fieldStruct *field; // pointer of the current board [changed by move()]
|
||||
float floatValue; // value of current situation for board->currentPlayer
|
||||
TwoBit shortValue; // ''
|
||||
bool gameHasFinished; // someone has won or current board is full
|
||||
int ownId; // id of the player who called the play()-function
|
||||
unsigned int curSearchDepth; // current level
|
||||
unsigned int depthOfFullTree; // search depth where the whole tree is explored
|
||||
unsigned int *idPossibilities; // returned pointer of getPossibilities()-function
|
||||
Backup *oldStates; // for undo()-function
|
||||
Possibility *possibilities; // for getPossNormalMove()-function
|
||||
PerfectAI *parent; //
|
||||
// Variables used individually by each single thread
|
||||
class ThreadVars
|
||||
{
|
||||
public:
|
||||
fieldStruct *field; // pointer of the current board [changed by move()]
|
||||
float floatValue; // value of current situation for board->currentPlayer
|
||||
TwoBit shortValue; // ''
|
||||
bool gameHasFinished; // someone has won or current board is full
|
||||
int ownId; // id of the player who called the play()-function
|
||||
unsigned int curSearchDepth; // current level
|
||||
unsigned int depthOfFullTree; // search depth where the whole tree is explored
|
||||
unsigned int *idPossibilities; // returned pointer of getPossibilities()-function
|
||||
Backup *oldStates; // for undo()-function
|
||||
Possibility *possibilities; // for getPossNormalMove()-function
|
||||
PerfectAI *parent; //
|
||||
|
||||
// constructor
|
||||
ThreadVars();
|
||||
// constructor
|
||||
ThreadVars();
|
||||
|
||||
// Functions
|
||||
unsigned int *getPossSettingPhase(unsigned int *numPossibilities, void **pPossibilities);
|
||||
unsigned int *getPossNormalMove(unsigned int *numPossibilities, void **pPossibilities);
|
||||
unsigned int *getPossStoneRemove(unsigned int *numPossibilities, void **pPossibilities);
|
||||
// Functions
|
||||
unsigned int *getPossSettingPhase(unsigned int *numPossibilities, void **pPossibilities);
|
||||
unsigned int *getPossNormalMove(unsigned int *numPossibilities, void **pPossibilities);
|
||||
unsigned int *getPossStoneRemove(unsigned int *numPossibilities, void **pPossibilities);
|
||||
|
||||
// move functions
|
||||
inline void updatePossibleMoves(unsigned int stone, Player *stoneOwner, bool stoneRemoved, unsigned int ignoreStone);
|
||||
inline void updateWarning(unsigned int firstStone, unsigned int secondStone);
|
||||
inline void setWarning(unsigned int stoneOne, unsigned int stoneTwo, unsigned int stoneThree);
|
||||
inline void removeStone(unsigned int from, Backup *backup);
|
||||
inline void setStone(unsigned int to, Backup *backup);
|
||||
inline void normalMove(unsigned int from, unsigned int to, Backup *backup);
|
||||
// move functions
|
||||
inline void updatePossibleMoves(unsigned int stone, Player *stoneOwner, bool stoneRemoved, unsigned int ignoreStone);
|
||||
inline void updateWarning(unsigned int firstStone, unsigned int secondStone);
|
||||
inline void setWarning(unsigned int stoneOne, unsigned int stoneTwo, unsigned int stoneThree);
|
||||
inline void removeStone(unsigned int from, Backup *backup);
|
||||
inline void setStone(unsigned int to, Backup *backup);
|
||||
inline void normalMove(unsigned int from, unsigned int to, Backup *backup);
|
||||
|
||||
// database functions
|
||||
unsigned int getLayerAndStateNumber(unsigned int &layerNum, unsigned int &stateNumber);
|
||||
void setWarningAndMill(unsigned int stone, unsigned int firstNeighbour, unsigned int secondNeighbour);
|
||||
bool fieldIntegrityOK(unsigned int numberOfMillsCurrentPlayer, unsigned int numberOfMillsOpponentPlayer, bool aStoneCanBeRemovedFromCurPlayer);
|
||||
void calcPossibleMoves(Player *player);
|
||||
void storePredecessor(unsigned int numberOfMillsCurrentPlayer, unsigned int numberOfMillsOpponentPlayer, unsigned int *amountOfPred, RetroAnalysisPredVars *predVars);
|
||||
};
|
||||
ThreadVars *threadVars;
|
||||
// database functions
|
||||
unsigned int getLayerAndStateNumber(unsigned int &layerNum, unsigned int &stateNumber);
|
||||
void setWarningAndMill(unsigned int stone, unsigned int firstNeighbour, unsigned int secondNeighbour);
|
||||
bool fieldIntegrityOK(unsigned int numberOfMillsCurrentPlayer, unsigned int numberOfMillsOpponentPlayer, bool aStoneCanBeRemovedFromCurPlayer);
|
||||
void calcPossibleMoves(Player *player);
|
||||
void storePredecessor(unsigned int numberOfMillsCurrentPlayer, unsigned int numberOfMillsOpponentPlayer, unsigned int *amountOfPred, RetroAnalysisPredVars *predVars);
|
||||
};
|
||||
ThreadVars *threadVars;
|
||||
|
||||
// database functions
|
||||
unsigned int getNumberOfLayers();
|
||||
unsigned int getNumberOfKnotsInLayer(unsigned int layerNum);
|
||||
long long mOverN_Function(unsigned int m, unsigned int n);
|
||||
void applySymmetrieOperationOnField(unsigned char symmetryOperationNumber, unsigned int *sourceField, unsigned int *destField);
|
||||
bool isSymOperationInvariantOnGroupCD(unsigned int symmetryOperation, int *theField);
|
||||
bool shallRetroAnalysisBeUsed(unsigned int layerNum);
|
||||
void getSuccLayers(unsigned int layerNum, unsigned int *amountOfSuccLayers, unsigned int *succLayers);
|
||||
void getPredecessors(unsigned int threadNo, unsigned int *amountOfPred, RetroAnalysisPredVars *predVars);
|
||||
bool setSituation(unsigned int threadNo, unsigned int layerNum, unsigned int stateNumber);
|
||||
unsigned int getLayerNumber(unsigned int threadNo);
|
||||
unsigned int getLayerAndStateNumber(unsigned int threadNo, unsigned int &layerNum, unsigned int &stateNumber);
|
||||
// database functions
|
||||
unsigned int getNumberOfLayers();
|
||||
unsigned int getNumberOfKnotsInLayer(unsigned int layerNum);
|
||||
long long mOverN_Function(unsigned int m, unsigned int n);
|
||||
void applySymmetrieOperationOnField(unsigned char symmetryOperationNumber, unsigned int *sourceField, unsigned int *destField);
|
||||
bool isSymOperationInvariantOnGroupCD(unsigned int symmetryOperation, int *theField);
|
||||
bool shallRetroAnalysisBeUsed(unsigned int layerNum);
|
||||
void getSuccLayers(unsigned int layerNum, unsigned int *amountOfSuccLayers, unsigned int *succLayers);
|
||||
void getPredecessors(unsigned int threadNo, unsigned int *amountOfPred, RetroAnalysisPredVars *predVars);
|
||||
bool setSituation(unsigned int threadNo, unsigned int layerNum, unsigned int stateNumber);
|
||||
unsigned int getLayerNumber(unsigned int threadNo);
|
||||
unsigned int getLayerAndStateNumber(unsigned int threadNo, unsigned int &layerNum, unsigned int &stateNumber);
|
||||
|
||||
// integrity test functions
|
||||
bool checkMoveAndSetSituation();
|
||||
bool checkGetPossThanGetPred();
|
||||
bool checkGetPredThanGetPoss();
|
||||
// integrity test functions
|
||||
bool checkMoveAndSetSituation();
|
||||
bool checkGetPossThanGetPred();
|
||||
bool checkGetPredThanGetPoss();
|
||||
|
||||
// Virtual Functions
|
||||
void prepareBestChoiceCalculation();
|
||||
void getValueOfSituation(unsigned int threadNo, float &floatValue, TwoBit &shortValue);
|
||||
void setOpponentLevel(unsigned int threadNo, bool isOpponentLevel);
|
||||
bool getOpponentLevel(unsigned int threadNo);
|
||||
void deletePossibilities(unsigned int threadNo, void *pPossibilities);
|
||||
unsigned int *getPossibilities(unsigned int threadNo, unsigned int *numPossibilities, bool *opponentsMove, void **pPossibilities);
|
||||
void undo(unsigned int threadNo, unsigned int idPossibility, bool opponentsMove, void *pBackup, void *pPossibilities);
|
||||
void move(unsigned int threadNo, unsigned int idPossibility, bool opponentsMove, void **pBackup, void *pPossibilities);
|
||||
void printMoveInformation(unsigned int threadNo, unsigned int idPossibility, void *pPossibilities);
|
||||
void storeValueOfMove(unsigned int threadNo, unsigned int idPossibility, void *pPossibilities, unsigned char value, unsigned int *freqValuesSubMoves, PlyInfoVarType plyInfo);
|
||||
void getSymStateNumWithDoubles(unsigned int threadNo, unsigned int *numSymmetricStates, unsigned int **symStateNumbers);
|
||||
void printBoard(unsigned int threadNo, unsigned char value);
|
||||
string getOutputInformation(unsigned int layerNum);
|
||||
unsigned int getPartnerLayer(unsigned int layerNum);
|
||||
void prepareDatabaseCalculation();
|
||||
void wrapUpDatabaseCalculation(bool calculationAborted);
|
||||
// Virtual Functions
|
||||
void prepareBestChoiceCalculation();
|
||||
void getValueOfSituation(unsigned int threadNo, float &floatValue, TwoBit &shortValue);
|
||||
void setOpponentLevel(unsigned int threadNo, bool isOpponentLevel);
|
||||
bool getOpponentLevel(unsigned int threadNo);
|
||||
void deletePossibilities(unsigned int threadNo, void *pPossibilities);
|
||||
unsigned int *getPossibilities(unsigned int threadNo, unsigned int *numPossibilities, bool *opponentsMove, void **pPossibilities);
|
||||
void undo(unsigned int threadNo, unsigned int idPossibility, bool opponentsMove, void *pBackup, void *pPossibilities);
|
||||
void move(unsigned int threadNo, unsigned int idPossibility, bool opponentsMove, void **pBackup, void *pPossibilities);
|
||||
void printMoveInformation(unsigned int threadNo, unsigned int idPossibility, void *pPossibilities);
|
||||
void storeValueOfMove(unsigned int threadNo, unsigned int idPossibility, void *pPossibilities, unsigned char value, unsigned int *freqValuesSubMoves, PlyInfoVarType plyInfo);
|
||||
void getSymStateNumWithDoubles(unsigned int threadNo, unsigned int *numSymmetricStates, unsigned int **symStateNumbers);
|
||||
void printBoard(unsigned int threadNo, unsigned char value);
|
||||
string getOutputInformation(unsigned int layerNum);
|
||||
unsigned int getPartnerLayer(unsigned int layerNum);
|
||||
void prepareDatabaseCalculation();
|
||||
void wrapUpDatabaseCalculation(bool calculationAborted);
|
||||
|
||||
public:
|
||||
// Constructor / destructor
|
||||
PerfectAI(const char *directory);
|
||||
~PerfectAI();
|
||||
// Constructor / destructor
|
||||
PerfectAI(const char *directory);
|
||||
~PerfectAI();
|
||||
|
||||
// Functions
|
||||
bool setDatabasePath(const char *directory);
|
||||
void play(fieldStruct *theField, unsigned int *pushFrom, unsigned int *pushTo);
|
||||
void getValueOfMoves(unsigned char *moveValue, unsigned int *freqValuesSubMoves, PlyInfoVarType *plyInfo, unsigned int *moveQuality, unsigned char &knotValue, PlyInfoVarType &bestAmountOfPlies);
|
||||
void getField(unsigned int layerNum, unsigned int stateNumber, fieldStruct *field, bool *gameHasFinished);
|
||||
void getLayerAndStateNumber(unsigned int &layerNum, unsigned int &stateNumber);
|
||||
// Functions
|
||||
bool setDatabasePath(const char *directory);
|
||||
void play(fieldStruct *theField, unsigned int *pushFrom, unsigned int *pushTo);
|
||||
void getValueOfMoves(unsigned char *moveValue, unsigned int *freqValuesSubMoves, PlyInfoVarType *plyInfo, unsigned int *moveQuality, unsigned char &knotValue, PlyInfoVarType &bestAmountOfPlies);
|
||||
void getField(unsigned int layerNum, unsigned int stateNumber, fieldStruct *field, bool *gameHasFinished);
|
||||
void getLayerAndStateNumber(unsigned int &layerNum, unsigned int &stateNumber);
|
||||
|
||||
// Testing functions
|
||||
bool testLayers(unsigned int startTestFromLayer, unsigned int endTestAtLayer);
|
||||
// Testing functions
|
||||
bool testLayers(unsigned int startTestFromLayer, unsigned int endTestAtLayer);
|
||||
};
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -1,9 +1,9 @@
|
|||
/*********************************************************************\
|
||||
Position.h
|
||||
Copyright (c) Thomas Weber. All rights reserved.
|
||||
Copyright (C) 2021 The Sanmill developers (see AUTHORS file)
|
||||
Licensed under the MIT License.
|
||||
https://github.com/madweasel/madweasels-cpp
|
||||
Position.h
|
||||
Copyright (c) Thomas Weber. All rights reserved.
|
||||
Copyright (C) 2021 The Sanmill developers (see AUTHORS file)
|
||||
Licensed under the MIT License.
|
||||
https://github.com/madweasel/madweasels-cpp
|
||||
\*********************************************************************/
|
||||
|
||||
#ifndef MUEHLE_H
|
||||
|
@ -45,95 +45,95 @@ using namespace std;
|
|||
class Position
|
||||
{
|
||||
private:
|
||||
// Variables
|
||||
unsigned int *moveLogFrom, *moveLogTo, movesDone; // array containing the history of moves done
|
||||
MillAI *playerOneAI; // class-pointer to the AI of player one
|
||||
MillAI *playerTwoAI; // class-pointer to the AI of player two
|
||||
fieldStruct field; // current board
|
||||
fieldStruct initialField; // undo of the last move is done by setting the initial board und performing all moves saved in history
|
||||
int winner; // playerId of the player who has won the game. zero if game is still running.
|
||||
int beginningPlayer; // playerId of the player who makes the first move
|
||||
// Variables
|
||||
unsigned int *moveLogFrom, *moveLogTo, movesDone; // array containing the history of moves done
|
||||
MillAI *playerOneAI; // class-pointer to the AI of player one
|
||||
MillAI *playerTwoAI; // class-pointer to the AI of player two
|
||||
fieldStruct field; // current board
|
||||
fieldStruct initialField; // undo of the last move is done by setting the initial board und performing all moves saved in history
|
||||
int winner; // playerId of the player who has won the game. zero if game is still running.
|
||||
int beginningPlayer; // playerId of the player who makes the first move
|
||||
|
||||
// Functions
|
||||
void exit();
|
||||
void setNextPlayer();
|
||||
void calcPossibleMoves(Player *player);
|
||||
void updateMillsAndWarnings(unsigned int newStone);
|
||||
bool isNormalMovePossible(unsigned int from, unsigned int to, Player *player);
|
||||
void setWarningAndMill(unsigned int stone, unsigned int firstNeighbour, unsigned int secondNeighbour, bool isNewStone);
|
||||
// Functions
|
||||
void exit();
|
||||
void setNextPlayer();
|
||||
void calcPossibleMoves(Player *player);
|
||||
void updateMillsAndWarnings(unsigned int newStone);
|
||||
bool isNormalMovePossible(unsigned int from, unsigned int to, Player *player);
|
||||
void setWarningAndMill(unsigned int stone, unsigned int firstNeighbour, unsigned int secondNeighbour, bool isNewStone);
|
||||
|
||||
public:
|
||||
// Constructor / destructor
|
||||
Position();
|
||||
~Position();
|
||||
// Constructor / destructor
|
||||
Position();
|
||||
~Position();
|
||||
|
||||
// Functions
|
||||
void undo_move();
|
||||
void beginNewGame(MillAI *firstPlayerAI, MillAI *secondPlayerAI, int currentPlayer);
|
||||
void setAI(int player, MillAI *AI);
|
||||
bool do_move(unsigned int pushFrom, unsigned int pushTo);
|
||||
void getComputersChoice(unsigned int *pushFrom, unsigned int *pushTo);
|
||||
bool setCurrentGameState(fieldStruct *curState);
|
||||
bool compareWithField(fieldStruct *compareField);
|
||||
bool comparePlayers(Player *playerA, Player *playerB);
|
||||
void printBoard();
|
||||
bool startSettingPhase(MillAI *firstPlayerAI, MillAI *secondPlayerAI, int currentPlayer, bool settingPhase);
|
||||
bool put_piece(unsigned int pos, int player);
|
||||
bool settingPhaseHasFinished();
|
||||
void getChoiceOfSpecialAI(MillAI *AI, unsigned int *pushFrom, unsigned int *pushTo);
|
||||
void setUpCalcPossibleMoves(Player *player);
|
||||
void setUpSetWarningAndMill(unsigned int stone, unsigned int firstNeighbour, unsigned int secondNeighbour);
|
||||
void calcNumberOfRestingStones(int &numWhiteStonesResting, int &numBlackStonesResting);
|
||||
// Functions
|
||||
void undo_move();
|
||||
void beginNewGame(MillAI *firstPlayerAI, MillAI *secondPlayerAI, int currentPlayer);
|
||||
void setAI(int player, MillAI *AI);
|
||||
bool do_move(unsigned int pushFrom, unsigned int pushTo);
|
||||
void getComputersChoice(unsigned int *pushFrom, unsigned int *pushTo);
|
||||
bool setCurrentGameState(fieldStruct *curState);
|
||||
bool compareWithField(fieldStruct *compareField);
|
||||
bool comparePlayers(Player *playerA, Player *playerB);
|
||||
void printBoard();
|
||||
bool startSettingPhase(MillAI *firstPlayerAI, MillAI *secondPlayerAI, int currentPlayer, bool settingPhase);
|
||||
bool put_piece(unsigned int pos, int player);
|
||||
bool settingPhaseHasFinished();
|
||||
void getChoiceOfSpecialAI(MillAI *AI, unsigned int *pushFrom, unsigned int *pushTo);
|
||||
void setUpCalcPossibleMoves(Player *player);
|
||||
void setUpSetWarningAndMill(unsigned int stone, unsigned int firstNeighbour, unsigned int secondNeighbour);
|
||||
void calcNumberOfRestingStones(int &numWhiteStonesResting, int &numBlackStonesResting);
|
||||
|
||||
// getter
|
||||
void getLog(unsigned int &numMovesDone, unsigned int *from, unsigned int *to);
|
||||
bool getField(int *pField);
|
||||
bool isCurrentPlayerHuman();
|
||||
bool isOpponentPlayerHuman();
|
||||
bool inSettingPhase()
|
||||
{
|
||||
return field.settingPhase;
|
||||
}
|
||||
unsigned int mustStoneBeRemoved()
|
||||
{
|
||||
return field.stoneMustBeRemoved;
|
||||
}
|
||||
int getWinner()
|
||||
{
|
||||
return winner;
|
||||
}
|
||||
int getCurrentPlayer()
|
||||
{
|
||||
return field.curPlayer->id;
|
||||
}
|
||||
unsigned int getLastMoveFrom()
|
||||
{
|
||||
return (movesDone ? moveLogFrom[movesDone - 1] : field.size);
|
||||
}
|
||||
unsigned int getLastMoveTo()
|
||||
{
|
||||
return (movesDone ? moveLogTo[movesDone - 1] : field.size);
|
||||
}
|
||||
unsigned int getMovesDone()
|
||||
{
|
||||
return movesDone;
|
||||
}
|
||||
unsigned int getNumStonesSet()
|
||||
{
|
||||
return field.stonesSet;
|
||||
}
|
||||
int getBeginningPlayer()
|
||||
{
|
||||
return beginningPlayer;
|
||||
}
|
||||
unsigned int getNumStonOfCurPlayer()
|
||||
{
|
||||
return field.curPlayer->numStones;
|
||||
}
|
||||
unsigned int getNumStonOfOppPlayer()
|
||||
{
|
||||
return field.oppPlayer->numStones;
|
||||
}
|
||||
// getter
|
||||
void getLog(unsigned int &numMovesDone, unsigned int *from, unsigned int *to);
|
||||
bool getField(int *pField);
|
||||
bool isCurrentPlayerHuman();
|
||||
bool isOpponentPlayerHuman();
|
||||
bool inSettingPhase()
|
||||
{
|
||||
return field.settingPhase;
|
||||
}
|
||||
unsigned int mustStoneBeRemoved()
|
||||
{
|
||||
return field.stoneMustBeRemoved;
|
||||
}
|
||||
int getWinner()
|
||||
{
|
||||
return winner;
|
||||
}
|
||||
int getCurrentPlayer()
|
||||
{
|
||||
return field.curPlayer->id;
|
||||
}
|
||||
unsigned int getLastMoveFrom()
|
||||
{
|
||||
return (movesDone ? moveLogFrom[movesDone - 1] : field.size);
|
||||
}
|
||||
unsigned int getLastMoveTo()
|
||||
{
|
||||
return (movesDone ? moveLogTo[movesDone - 1] : field.size);
|
||||
}
|
||||
unsigned int getMovesDone()
|
||||
{
|
||||
return movesDone;
|
||||
}
|
||||
unsigned int getNumStonesSet()
|
||||
{
|
||||
return field.stonesSet;
|
||||
}
|
||||
int getBeginningPlayer()
|
||||
{
|
||||
return beginningPlayer;
|
||||
}
|
||||
unsigned int getNumStonOfCurPlayer()
|
||||
{
|
||||
return field.curPlayer->numStones;
|
||||
}
|
||||
unsigned int getNumStonOfOppPlayer()
|
||||
{
|
||||
return field.oppPlayer->numStones;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
/*********************************************************************
|
||||
RandomAI.cpp
|
||||
Copyright (c) Thomas Weber. All rights reserved.
|
||||
Copyright (C) 2021 The Sanmill developers (see AUTHORS file)
|
||||
Licensed under the MIT License.
|
||||
https://github.com/madweasel/madweasels-cpp
|
||||
RandomAI.cpp
|
||||
Copyright (c) Thomas Weber. All rights reserved.
|
||||
Copyright (C) 2021 The Sanmill developers (see AUTHORS file)
|
||||
Licensed under the MIT License.
|
||||
https://github.com/madweasel/madweasels-cpp
|
||||
\*********************************************************************/
|
||||
|
||||
#include "randomAI.h"
|
||||
|
@ -14,8 +14,8 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
RandomAI::RandomAI()
|
||||
{
|
||||
// Init
|
||||
srand((unsigned)time(nullptr));
|
||||
// Init
|
||||
srand((unsigned)time(nullptr));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -24,7 +24,7 @@ RandomAI::RandomAI()
|
|||
//-----------------------------------------------------------------------------
|
||||
RandomAI::~RandomAI()
|
||||
{
|
||||
// Locals
|
||||
// Locals
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -33,68 +33,54 @@ RandomAI::~RandomAI()
|
|||
//-----------------------------------------------------------------------------
|
||||
void RandomAI::play(fieldStruct *theField, unsigned int *pushFrom, unsigned int *pushTo)
|
||||
{
|
||||
// locals
|
||||
unsigned int from, to, direction;
|
||||
bool allowedToSpring = (theField->curPlayer->numStones == 3) ? true : false;
|
||||
// locals
|
||||
unsigned int from, to, direction;
|
||||
bool allowedToSpring = (theField->curPlayer->numStones == 3) ? true : false;
|
||||
|
||||
// must stone be removed ?
|
||||
if (theField->stoneMustBeRemoved)
|
||||
{
|
||||
// must stone be removed ?
|
||||
if (theField->stoneMustBeRemoved) {
|
||||
|
||||
// search a stone from the enemy
|
||||
do
|
||||
{
|
||||
from = rand() % theField->size;
|
||||
to = theField->size;
|
||||
} while (theField->board[from] != theField->oppPlayer->id || theField->stonePartOfMill[from]);
|
||||
// search a stone from the enemy
|
||||
do {
|
||||
from = rand() % theField->size;
|
||||
to = theField->size;
|
||||
} while (theField->board[from] != theField->oppPlayer->id || theField->stonePartOfMill[from]);
|
||||
|
||||
// still in setting phase ?
|
||||
}
|
||||
else if (theField->settingPhase)
|
||||
{
|
||||
// still in setting phase ?
|
||||
} else if (theField->settingPhase) {
|
||||
|
||||
// search a free square
|
||||
do
|
||||
{
|
||||
from = theField->size;
|
||||
to = rand() % theField->size;
|
||||
} while (theField->board[to] != theField->squareIsFree);
|
||||
// search a free square
|
||||
do {
|
||||
from = theField->size;
|
||||
to = rand() % theField->size;
|
||||
} while (theField->board[to] != theField->squareIsFree);
|
||||
|
||||
// try to push randomly
|
||||
}
|
||||
else
|
||||
{
|
||||
// try to push randomly
|
||||
} else {
|
||||
|
||||
do
|
||||
{
|
||||
// search an own stone
|
||||
do
|
||||
{
|
||||
from = rand() % theField->size;
|
||||
} while (theField->board[from] != theField->curPlayer->id);
|
||||
do {
|
||||
// search an own stone
|
||||
do {
|
||||
from = rand() % theField->size;
|
||||
} while (theField->board[from] != theField->curPlayer->id);
|
||||
|
||||
// select a free square
|
||||
if (allowedToSpring)
|
||||
{
|
||||
do
|
||||
{
|
||||
to = rand() % theField->size;
|
||||
} while (theField->board[to] != theField->squareIsFree);
|
||||
// select a free square
|
||||
if (allowedToSpring) {
|
||||
do {
|
||||
to = rand() % theField->size;
|
||||
} while (theField->board[to] != theField->squareIsFree);
|
||||
|
||||
// select a connected square
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
direction = rand() % 4;
|
||||
to = theField->connectedSquare[from][direction];
|
||||
} while (to == theField->size);
|
||||
}
|
||||
// select a connected square
|
||||
} else {
|
||||
do {
|
||||
direction = rand() % 4;
|
||||
to = theField->connectedSquare[from][direction];
|
||||
} while (to == theField->size);
|
||||
}
|
||||
|
||||
} while (theField->board[to] != theField->squareIsFree);
|
||||
}
|
||||
} while (theField->board[to] != theField->squareIsFree);
|
||||
}
|
||||
|
||||
*pushFrom = from;
|
||||
*pushTo = to;
|
||||
*pushFrom = from;
|
||||
*pushTo = to;
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
/*********************************************************************\
|
||||
RandomAI.h
|
||||
Copyright (c) Thomas Weber. All rights reserved.
|
||||
Copyright (C) 2021 The Sanmill developers (see AUTHORS file)
|
||||
Licensed under the MIT License.
|
||||
https://github.com/madweasel/madweasels-cpp
|
||||
RandomAI.h
|
||||
Copyright (c) Thomas Weber. All rights reserved.
|
||||
Copyright (C) 2021 The Sanmill developers (see AUTHORS file)
|
||||
Licensed under the MIT License.
|
||||
https://github.com/madweasel/madweasels-cpp
|
||||
\*********************************************************************/
|
||||
|
||||
#ifndef RANDOM_AI_H
|
||||
|
@ -18,12 +18,12 @@
|
|||
class RandomAI : public MillAI
|
||||
{
|
||||
public:
|
||||
// Constructor / destructor
|
||||
RandomAI();
|
||||
~RandomAI();
|
||||
// Constructor / destructor
|
||||
RandomAI();
|
||||
~RandomAI();
|
||||
|
||||
// Functions
|
||||
void play(fieldStruct *theField, unsigned int *pushFrom, unsigned int *pushTo);
|
||||
// Functions
|
||||
void play(fieldStruct *theField, unsigned int *pushFrom, unsigned int *pushTo);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
/*********************************************************************
|
||||
strLib.cpp
|
||||
Copyright (c) Thomas Weber. All rights reserved.
|
||||
Copyright (C) 2021 The Sanmill developers (see AUTHORS file)
|
||||
Licensed under the MIT License.
|
||||
https://github.com/madweasel/madweasels-cpp
|
||||
strLib.cpp
|
||||
Copyright (c) Thomas Weber. All rights reserved.
|
||||
Copyright (C) 2021 The Sanmill developers (see AUTHORS file)
|
||||
Licensed under the MIT License.
|
||||
https://github.com/madweasel/madweasels-cpp
|
||||
\*********************************************************************/
|
||||
|
||||
#include "strLib.h"
|
||||
|
@ -14,12 +14,12 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
int MyString::hibit(unsigned int n)
|
||||
{
|
||||
n |= (n >> 1);
|
||||
n |= (n >> 2);
|
||||
n |= (n >> 4);
|
||||
n |= (n >> 8);
|
||||
n |= (n >> 16);
|
||||
return n - (n >> 1);
|
||||
n |= (n >> 1);
|
||||
n |= (n >> 2);
|
||||
n |= (n >> 4);
|
||||
n |= (n >> 8);
|
||||
n |= (n >> 16);
|
||||
return n - (n >> 1);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -36,7 +36,7 @@ MyString::MyString()
|
|||
//-----------------------------------------------------------------------------
|
||||
MyString::MyString(const char *cStr)
|
||||
{
|
||||
assign(cStr);
|
||||
assign(cStr);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -45,7 +45,7 @@ MyString::MyString(const char *cStr)
|
|||
//-----------------------------------------------------------------------------
|
||||
MyString::MyString(const WCHAR *cStr)
|
||||
{
|
||||
assign(cStr);
|
||||
assign(cStr);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -54,20 +54,18 @@ MyString::MyString(const WCHAR *cStr)
|
|||
//-----------------------------------------------------------------------------
|
||||
MyString::~MyString()
|
||||
{
|
||||
if (strA != nullptr)
|
||||
{
|
||||
delete[] strA;
|
||||
strA = nullptr;
|
||||
}
|
||||
if (strW != nullptr)
|
||||
{
|
||||
delete[] strW;
|
||||
strW = nullptr;
|
||||
}
|
||||
strW = nullptr;
|
||||
strA = nullptr;
|
||||
length = 0;
|
||||
reserved = 0;
|
||||
if (strA != nullptr) {
|
||||
delete[] strA;
|
||||
strA = nullptr;
|
||||
}
|
||||
if (strW != nullptr) {
|
||||
delete[] strW;
|
||||
strW = nullptr;
|
||||
}
|
||||
strW = nullptr;
|
||||
strA = nullptr;
|
||||
length = 0;
|
||||
reserved = 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -76,7 +74,7 @@ MyString::~MyString()
|
|||
//-----------------------------------------------------------------------------
|
||||
const char *MyString::c_strA()
|
||||
{
|
||||
return strA;
|
||||
return strA;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -85,7 +83,7 @@ const char *MyString::c_strA()
|
|||
//-----------------------------------------------------------------------------
|
||||
const WCHAR *MyString::c_strW()
|
||||
{
|
||||
return strW;
|
||||
return strW;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -94,25 +92,25 @@ const WCHAR *MyString::c_strW()
|
|||
//-----------------------------------------------------------------------------
|
||||
MyString &MyString::assign(const char *cStr)
|
||||
{
|
||||
// locals
|
||||
size_t convertedChars = 0;
|
||||
size_t newLength = strlen(cStr);
|
||||
size_t newReserved = (size_t)hibit((unsigned int)newLength) * 2;
|
||||
// locals
|
||||
size_t convertedChars = 0;
|
||||
size_t newLength = strlen(cStr);
|
||||
size_t newReserved = (size_t)hibit((unsigned int)newLength) * 2;
|
||||
|
||||
if (reserved < newReserved)
|
||||
this->~MyString();
|
||||
if (strA == nullptr)
|
||||
strA = new char[newReserved];
|
||||
if (strW == nullptr)
|
||||
strW = new WCHAR[newReserved];
|
||||
if (reserved < newReserved)
|
||||
this->~MyString();
|
||||
if (strA == nullptr)
|
||||
strA = new char[newReserved];
|
||||
if (strW == nullptr)
|
||||
strW = new WCHAR[newReserved];
|
||||
|
||||
reserved = newReserved;
|
||||
length = newLength;
|
||||
reserved = newReserved;
|
||||
length = newLength;
|
||||
|
||||
strcpy_s(strA, newReserved, cStr);
|
||||
mbstowcs_s(&convertedChars, strW, newLength + 1, cStr, _TRUNCATE);
|
||||
strcpy_s(strA, newReserved, cStr);
|
||||
mbstowcs_s(&convertedChars, strW, newLength + 1, cStr, _TRUNCATE);
|
||||
|
||||
return *this;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -121,25 +119,25 @@ MyString &MyString::assign(const char *cStr)
|
|||
//-----------------------------------------------------------------------------
|
||||
MyString &MyString::assign(const WCHAR *cStr)
|
||||
{
|
||||
// locals
|
||||
size_t returnValue;
|
||||
size_t newLength = wcslen(cStr);
|
||||
size_t newReserved = (size_t)hibit((unsigned int)newLength) * 2;
|
||||
// locals
|
||||
size_t returnValue;
|
||||
size_t newLength = wcslen(cStr);
|
||||
size_t newReserved = (size_t)hibit((unsigned int)newLength) * 2;
|
||||
|
||||
if (reserved < newReserved)
|
||||
this->~MyString();
|
||||
if (strA == nullptr)
|
||||
strA = new char[newReserved];
|
||||
if (strW == nullptr)
|
||||
strW = new WCHAR[newReserved];
|
||||
if (reserved < newReserved)
|
||||
this->~MyString();
|
||||
if (strA == nullptr)
|
||||
strA = new char[newReserved];
|
||||
if (strW == nullptr)
|
||||
strW = new WCHAR[newReserved];
|
||||
|
||||
reserved = newReserved;
|
||||
length = newLength;
|
||||
reserved = newReserved;
|
||||
length = newLength;
|
||||
|
||||
wcscpy_s(strW, newReserved, cStr);
|
||||
wcstombs_s(&returnValue, strA, newLength + 1, cStr, newLength + 1);
|
||||
wcscpy_s(strW, newReserved, cStr);
|
||||
wcstombs_s(&returnValue, strA, newLength + 1, cStr, newLength + 1);
|
||||
|
||||
return *this;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -148,313 +146,248 @@ MyString &MyString::assign(const WCHAR *cStr)
|
|||
//-----------------------------------------------------------------------------
|
||||
bool readAsciiData(HANDLE hFile, double *pData, unsigned int numValues, unsigned char decimalSeperator, unsigned char columnSeparator)
|
||||
{
|
||||
// constants
|
||||
const unsigned int maxValueLengthInBytes = 32;
|
||||
const unsigned int bufferSize = 1000;
|
||||
// constants
|
||||
const unsigned int maxValueLengthInBytes = 32;
|
||||
const unsigned int bufferSize = 1000;
|
||||
|
||||
// locals
|
||||
DWORD dwBytesRead;
|
||||
unsigned char buffer[bufferSize];
|
||||
unsigned char *curByte = &buffer[0];
|
||||
unsigned int curReadValue = 0;
|
||||
unsigned int actualBufferSize = 0;
|
||||
unsigned int curBufferPos = bufferSize;
|
||||
unsigned int decimalPos = 0;
|
||||
int integralValue = 0; // ACHTUNG: Erlaubt nur 8 Vorkommastellen
|
||||
int fractionalValue = 0; // ACHTUNG: Erlaubt nur 8 Nachkommastellen
|
||||
int exponentialValue = 1;
|
||||
bool valIsNegativ = false;
|
||||
bool expIsNegativ = false;
|
||||
bool decimalPlace = false;
|
||||
bool exponent = false;
|
||||
double fractionalFactor[] = {0,
|
||||
0.1,
|
||||
0.01,
|
||||
0.001,
|
||||
0.0001,
|
||||
0.00001,
|
||||
0.000001,
|
||||
0.0000001,
|
||||
0.00000001,
|
||||
0.000000001,
|
||||
0.0000000001};
|
||||
// locals
|
||||
DWORD dwBytesRead;
|
||||
unsigned char buffer[bufferSize];
|
||||
unsigned char *curByte = &buffer[0];
|
||||
unsigned int curReadValue = 0;
|
||||
unsigned int actualBufferSize = 0;
|
||||
unsigned int curBufferPos = bufferSize;
|
||||
unsigned int decimalPos = 0;
|
||||
int integralValue = 0; // ACHTUNG: Erlaubt nur 8 Vorkommastellen
|
||||
int fractionalValue = 0; // ACHTUNG: Erlaubt nur 8 Nachkommastellen
|
||||
int exponentialValue = 1;
|
||||
bool valIsNegativ = false;
|
||||
bool expIsNegativ = false;
|
||||
bool decimalPlace = false;
|
||||
bool exponent = false;
|
||||
double fractionalFactor[] = { 0,
|
||||
0.1,
|
||||
0.01,
|
||||
0.001,
|
||||
0.0001,
|
||||
0.00001,
|
||||
0.000001,
|
||||
0.0000001,
|
||||
0.00000001,
|
||||
0.000000001,
|
||||
0.0000000001 };
|
||||
|
||||
// read each value
|
||||
do
|
||||
{
|
||||
// read each value
|
||||
do {
|
||||
|
||||
// read from buffer if necessary
|
||||
if (curBufferPos >= bufferSize - maxValueLengthInBytes)
|
||||
{
|
||||
memcpy(&buffer[0], &buffer[curBufferPos], bufferSize - curBufferPos);
|
||||
ReadFile(hFile, &buffer[bufferSize - curBufferPos], curBufferPos, &dwBytesRead, nullptr);
|
||||
actualBufferSize = bufferSize - curBufferPos + dwBytesRead;
|
||||
curBufferPos = 0;
|
||||
curByte = &buffer[curBufferPos];
|
||||
}
|
||||
// read from buffer if necessary
|
||||
if (curBufferPos >= bufferSize - maxValueLengthInBytes) {
|
||||
memcpy(&buffer[0], &buffer[curBufferPos], bufferSize - curBufferPos);
|
||||
ReadFile(hFile, &buffer[bufferSize - curBufferPos], curBufferPos, &dwBytesRead, nullptr);
|
||||
actualBufferSize = bufferSize - curBufferPos + dwBytesRead;
|
||||
curBufferPos = 0;
|
||||
curByte = &buffer[curBufferPos];
|
||||
}
|
||||
|
||||
// process current byte
|
||||
switch (*curByte)
|
||||
{
|
||||
case '-':
|
||||
if (exponent)
|
||||
{
|
||||
expIsNegativ = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
valIsNegativ = true;
|
||||
}
|
||||
break;
|
||||
case '+': /* ignore */
|
||||
break;
|
||||
case 'e':
|
||||
case 'E':
|
||||
exponent = true;
|
||||
decimalPlace = false;
|
||||
break;
|
||||
case '0':
|
||||
if (decimalPlace)
|
||||
{
|
||||
fractionalValue *= 10;
|
||||
fractionalValue += 0;
|
||||
decimalPos++;
|
||||
}
|
||||
else if (exponent)
|
||||
{
|
||||
exponentialValue *= 10;
|
||||
exponentialValue += 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
integralValue *= 10;
|
||||
integralValue += 0;
|
||||
}
|
||||
break;
|
||||
case '1':
|
||||
if (decimalPlace)
|
||||
{
|
||||
fractionalValue *= 10;
|
||||
fractionalValue += 1;
|
||||
decimalPos++;
|
||||
}
|
||||
else if (exponent)
|
||||
{
|
||||
exponentialValue *= 10;
|
||||
exponentialValue += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
integralValue *= 10;
|
||||
integralValue += 1;
|
||||
}
|
||||
break;
|
||||
case '2':
|
||||
if (decimalPlace)
|
||||
{
|
||||
fractionalValue *= 10;
|
||||
fractionalValue += 2;
|
||||
decimalPos++;
|
||||
}
|
||||
else if (exponent)
|
||||
{
|
||||
exponentialValue *= 10;
|
||||
exponentialValue += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
integralValue *= 10;
|
||||
integralValue += 2;
|
||||
}
|
||||
break;
|
||||
case '3':
|
||||
if (decimalPlace)
|
||||
{
|
||||
fractionalValue *= 10;
|
||||
fractionalValue += 3;
|
||||
decimalPos++;
|
||||
}
|
||||
else if (exponent)
|
||||
{
|
||||
exponentialValue *= 10;
|
||||
exponentialValue += 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
integralValue *= 10;
|
||||
integralValue += 3;
|
||||
}
|
||||
break;
|
||||
case '4':
|
||||
if (decimalPlace)
|
||||
{
|
||||
fractionalValue *= 10;
|
||||
fractionalValue += 4;
|
||||
decimalPos++;
|
||||
}
|
||||
else if (exponent)
|
||||
{
|
||||
exponentialValue *= 10;
|
||||
exponentialValue += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
integralValue *= 10;
|
||||
integralValue += 4;
|
||||
}
|
||||
break;
|
||||
case '5':
|
||||
if (decimalPlace)
|
||||
{
|
||||
fractionalValue *= 10;
|
||||
fractionalValue += 5;
|
||||
decimalPos++;
|
||||
}
|
||||
else if (exponent)
|
||||
{
|
||||
exponentialValue *= 10;
|
||||
exponentialValue += 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
integralValue *= 10;
|
||||
integralValue += 5;
|
||||
}
|
||||
break;
|
||||
case '6':
|
||||
if (decimalPlace)
|
||||
{
|
||||
fractionalValue *= 10;
|
||||
fractionalValue += 6;
|
||||
decimalPos++;
|
||||
}
|
||||
else if (exponent)
|
||||
{
|
||||
exponentialValue *= 10;
|
||||
exponentialValue += 6;
|
||||
}
|
||||
else
|
||||
{
|
||||
integralValue *= 10;
|
||||
integralValue += 6;
|
||||
}
|
||||
break;
|
||||
case '7':
|
||||
if (decimalPlace)
|
||||
{
|
||||
fractionalValue *= 10;
|
||||
fractionalValue += 7;
|
||||
decimalPos++;
|
||||
}
|
||||
else if (exponent)
|
||||
{
|
||||
exponentialValue *= 10;
|
||||
exponentialValue += 7;
|
||||
}
|
||||
else
|
||||
{
|
||||
integralValue *= 10;
|
||||
integralValue += 7;
|
||||
}
|
||||
break;
|
||||
case '8':
|
||||
if (decimalPlace)
|
||||
{
|
||||
fractionalValue *= 10;
|
||||
fractionalValue += 8;
|
||||
decimalPos++;
|
||||
}
|
||||
else if (exponent)
|
||||
{
|
||||
exponentialValue *= 10;
|
||||
exponentialValue += 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
integralValue *= 10;
|
||||
integralValue += 8;
|
||||
}
|
||||
break;
|
||||
case '9':
|
||||
if (decimalPlace)
|
||||
{
|
||||
fractionalValue *= 10;
|
||||
fractionalValue += 9;
|
||||
decimalPos++;
|
||||
}
|
||||
else if (exponent)
|
||||
{
|
||||
exponentialValue *= 10;
|
||||
exponentialValue += 9;
|
||||
}
|
||||
else
|
||||
{
|
||||
integralValue *= 10;
|
||||
integralValue += 9;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (*curByte == decimalSeperator)
|
||||
{
|
||||
decimalPlace = true;
|
||||
exponent = false;
|
||||
}
|
||||
else if (*curByte == columnSeparator)
|
||||
{
|
||||
// process current byte
|
||||
switch (*curByte) {
|
||||
case '-':
|
||||
if (exponent) {
|
||||
expIsNegativ = true;
|
||||
} else {
|
||||
valIsNegativ = true;
|
||||
}
|
||||
break;
|
||||
case '+': /* ignore */
|
||||
break;
|
||||
case 'e':
|
||||
case 'E':
|
||||
exponent = true;
|
||||
decimalPlace = false;
|
||||
break;
|
||||
case '0':
|
||||
if (decimalPlace) {
|
||||
fractionalValue *= 10;
|
||||
fractionalValue += 0;
|
||||
decimalPos++;
|
||||
} else if (exponent) {
|
||||
exponentialValue *= 10;
|
||||
exponentialValue += 0;
|
||||
} else {
|
||||
integralValue *= 10;
|
||||
integralValue += 0;
|
||||
}
|
||||
break;
|
||||
case '1':
|
||||
if (decimalPlace) {
|
||||
fractionalValue *= 10;
|
||||
fractionalValue += 1;
|
||||
decimalPos++;
|
||||
} else if (exponent) {
|
||||
exponentialValue *= 10;
|
||||
exponentialValue += 1;
|
||||
} else {
|
||||
integralValue *= 10;
|
||||
integralValue += 1;
|
||||
}
|
||||
break;
|
||||
case '2':
|
||||
if (decimalPlace) {
|
||||
fractionalValue *= 10;
|
||||
fractionalValue += 2;
|
||||
decimalPos++;
|
||||
} else if (exponent) {
|
||||
exponentialValue *= 10;
|
||||
exponentialValue += 2;
|
||||
} else {
|
||||
integralValue *= 10;
|
||||
integralValue += 2;
|
||||
}
|
||||
break;
|
||||
case '3':
|
||||
if (decimalPlace) {
|
||||
fractionalValue *= 10;
|
||||
fractionalValue += 3;
|
||||
decimalPos++;
|
||||
} else if (exponent) {
|
||||
exponentialValue *= 10;
|
||||
exponentialValue += 3;
|
||||
} else {
|
||||
integralValue *= 10;
|
||||
integralValue += 3;
|
||||
}
|
||||
break;
|
||||
case '4':
|
||||
if (decimalPlace) {
|
||||
fractionalValue *= 10;
|
||||
fractionalValue += 4;
|
||||
decimalPos++;
|
||||
} else if (exponent) {
|
||||
exponentialValue *= 10;
|
||||
exponentialValue += 4;
|
||||
} else {
|
||||
integralValue *= 10;
|
||||
integralValue += 4;
|
||||
}
|
||||
break;
|
||||
case '5':
|
||||
if (decimalPlace) {
|
||||
fractionalValue *= 10;
|
||||
fractionalValue += 5;
|
||||
decimalPos++;
|
||||
} else if (exponent) {
|
||||
exponentialValue *= 10;
|
||||
exponentialValue += 5;
|
||||
} else {
|
||||
integralValue *= 10;
|
||||
integralValue += 5;
|
||||
}
|
||||
break;
|
||||
case '6':
|
||||
if (decimalPlace) {
|
||||
fractionalValue *= 10;
|
||||
fractionalValue += 6;
|
||||
decimalPos++;
|
||||
} else if (exponent) {
|
||||
exponentialValue *= 10;
|
||||
exponentialValue += 6;
|
||||
} else {
|
||||
integralValue *= 10;
|
||||
integralValue += 6;
|
||||
}
|
||||
break;
|
||||
case '7':
|
||||
if (decimalPlace) {
|
||||
fractionalValue *= 10;
|
||||
fractionalValue += 7;
|
||||
decimalPos++;
|
||||
} else if (exponent) {
|
||||
exponentialValue *= 10;
|
||||
exponentialValue += 7;
|
||||
} else {
|
||||
integralValue *= 10;
|
||||
integralValue += 7;
|
||||
}
|
||||
break;
|
||||
case '8':
|
||||
if (decimalPlace) {
|
||||
fractionalValue *= 10;
|
||||
fractionalValue += 8;
|
||||
decimalPos++;
|
||||
} else if (exponent) {
|
||||
exponentialValue *= 10;
|
||||
exponentialValue += 8;
|
||||
} else {
|
||||
integralValue *= 10;
|
||||
integralValue += 8;
|
||||
}
|
||||
break;
|
||||
case '9':
|
||||
if (decimalPlace) {
|
||||
fractionalValue *= 10;
|
||||
fractionalValue += 9;
|
||||
decimalPos++;
|
||||
} else if (exponent) {
|
||||
exponentialValue *= 10;
|
||||
exponentialValue += 9;
|
||||
} else {
|
||||
integralValue *= 10;
|
||||
integralValue += 9;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (*curByte == decimalSeperator) {
|
||||
decimalPlace = true;
|
||||
exponent = false;
|
||||
} else if (*curByte == columnSeparator) {
|
||||
|
||||
// everything ok?
|
||||
if (decimalPos > 8)
|
||||
{
|
||||
cout << "ERROR in function readAsciiData(): Too many digits on decimal place. Maximum is 8 !" << endl;
|
||||
return false;
|
||||
}
|
||||
// everything ok?
|
||||
if (decimalPos > 8) {
|
||||
cout << "ERROR in function readAsciiData(): Too many digits on decimal place. Maximum is 8 !" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// calc final value
|
||||
(*pData) = integralValue;
|
||||
if (decimalPos)
|
||||
{
|
||||
(*pData) += fractionalValue * fractionalFactor[decimalPos];
|
||||
}
|
||||
if (valIsNegativ)
|
||||
{
|
||||
(*pData) *= -1;
|
||||
}
|
||||
if (exponent)
|
||||
{
|
||||
(*pData) *= pow(10, expIsNegativ ? -1 * exponentialValue : 1);
|
||||
}
|
||||
// calc final value
|
||||
(*pData) = integralValue;
|
||||
if (decimalPos) {
|
||||
(*pData) += fractionalValue * fractionalFactor[decimalPos];
|
||||
}
|
||||
if (valIsNegativ) {
|
||||
(*pData) *= -1;
|
||||
}
|
||||
if (exponent) {
|
||||
(*pData) *= pow(10, expIsNegativ ? -1 * exponentialValue : 1);
|
||||
}
|
||||
|
||||
// init
|
||||
valIsNegativ = false;
|
||||
expIsNegativ = false;
|
||||
decimalPlace = false;
|
||||
exponent = false;
|
||||
integralValue = 0;
|
||||
fractionalValue = 0;
|
||||
exponentialValue = 1;
|
||||
decimalPos = 0;
|
||||
// init
|
||||
valIsNegativ = false;
|
||||
expIsNegativ = false;
|
||||
decimalPlace = false;
|
||||
exponent = false;
|
||||
integralValue = 0;
|
||||
fractionalValue = 0;
|
||||
exponentialValue = 1;
|
||||
decimalPos = 0;
|
||||
|
||||
// save value
|
||||
pData++;
|
||||
curReadValue++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
break;
|
||||
}
|
||||
// save value
|
||||
pData++;
|
||||
curReadValue++;
|
||||
} else {
|
||||
// do nothing
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// consider next byte
|
||||
curBufferPos++;
|
||||
curByte++;
|
||||
// consider next byte
|
||||
curBufferPos++;
|
||||
curByte++;
|
||||
|
||||
// buffer overrun?
|
||||
if (curBufferPos >= actualBufferSize)
|
||||
return false;
|
||||
// buffer overrun?
|
||||
if (curBufferPos >= actualBufferSize)
|
||||
return false;
|
||||
|
||||
} while (curReadValue < numValues);
|
||||
} while (curReadValue < numValues);
|
||||
|
||||
// quit
|
||||
return true;
|
||||
// quit
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
/*********************************************************************\
|
||||
strLib.h
|
||||
Copyright (c) Thomas Weber. All rights reserved.
|
||||
Copyright (C) 2021 The Sanmill developers (see AUTHORS file)
|
||||
Licensed under the MIT License.
|
||||
https://github.com/madweasel/madweasels-cpp
|
||||
strLib.h
|
||||
Copyright (c) Thomas Weber. All rights reserved.
|
||||
Copyright (C) 2021 The Sanmill developers (see AUTHORS file)
|
||||
Licensed under the MIT License.
|
||||
https://github.com/madweasel/madweasels-cpp
|
||||
\*********************************************************************/
|
||||
|
||||
#ifndef STRLIB_H
|
||||
|
@ -24,27 +24,27 @@ bool readAsciiData(HANDLE hFile, double *pData, unsigned int numValues, unsigned
|
|||
class MyString
|
||||
{
|
||||
private:
|
||||
// variables
|
||||
WCHAR *strW = nullptr;
|
||||
char *strA = nullptr;
|
||||
size_t length = 0;
|
||||
size_t reserved = 0;
|
||||
// variables
|
||||
WCHAR *strW = nullptr;
|
||||
char *strA = nullptr;
|
||||
size_t length = 0;
|
||||
size_t reserved = 0;
|
||||
|
||||
// functions
|
||||
// functions
|
||||
|
||||
public:
|
||||
// functions
|
||||
MyString();
|
||||
MyString(const char *cStr);
|
||||
MyString(const WCHAR *cStr);
|
||||
~MyString();
|
||||
// functions
|
||||
MyString();
|
||||
MyString(const char *cStr);
|
||||
MyString(const WCHAR *cStr);
|
||||
~MyString();
|
||||
|
||||
const char *c_strA();
|
||||
const WCHAR *c_strW();
|
||||
MyString &assign(const char *cStr);
|
||||
MyString &assign(const WCHAR *cStr);
|
||||
const char *c_strA();
|
||||
const WCHAR *c_strW();
|
||||
MyString &assign(const char *cStr);
|
||||
MyString &assign(const WCHAR *cStr);
|
||||
|
||||
static int hibit(unsigned int n);
|
||||
static int hibit(unsigned int n);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
/*********************************************************************
|
||||
threadManager.cpp
|
||||
Copyright (c) Thomas Weber. All rights reserved.
|
||||
Copyright (C) 2021 The Sanmill developers (see AUTHORS file)
|
||||
Licensed under the MIT License.
|
||||
https://github.com/madweasel/madweasels-cpp
|
||||
threadManager.cpp
|
||||
Copyright (c) Thomas Weber. All rights reserved.
|
||||
Copyright (C) 2021 The Sanmill developers (see AUTHORS file)
|
||||
Licensed under the MIT License.
|
||||
https://github.com/madweasel/madweasels-cpp
|
||||
\*********************************************************************/
|
||||
|
||||
#include "threadManager.h"
|
||||
|
@ -14,30 +14,29 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
ThreadManager::ThreadManager()
|
||||
{
|
||||
// locals
|
||||
unsigned int curThreadNo;
|
||||
SYSTEM_INFO m_si = {0};
|
||||
// locals
|
||||
unsigned int curThreadNo;
|
||||
SYSTEM_INFO m_si = { 0 };
|
||||
|
||||
GetSystemInfo(&m_si);
|
||||
GetSystemInfo(&m_si);
|
||||
|
||||
// init default values
|
||||
executionPaused = false;
|
||||
executionCancelled = false;
|
||||
numThreads = m_si.dwNumberOfProcessors;
|
||||
hThread = new HANDLE[numThreads];
|
||||
threadId = new DWORD[numThreads];
|
||||
hBarrier = new HANDLE[numThreads];
|
||||
numThreadsPassedBarrier = 0;
|
||||
// init default values
|
||||
executionPaused = false;
|
||||
executionCancelled = false;
|
||||
numThreads = m_si.dwNumberOfProcessors;
|
||||
hThread = new HANDLE[numThreads];
|
||||
threadId = new DWORD[numThreads];
|
||||
hBarrier = new HANDLE[numThreads];
|
||||
numThreadsPassedBarrier = 0;
|
||||
|
||||
InitializeCriticalSection(&csBarrier);
|
||||
hEventBarrierPassedByEveryBody = CreateEvent(nullptr, true, false, nullptr);
|
||||
InitializeCriticalSection(&csBarrier);
|
||||
hEventBarrierPassedByEveryBody = CreateEvent(nullptr, true, false, nullptr);
|
||||
|
||||
for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++)
|
||||
{
|
||||
hThread[curThreadNo] = nullptr;
|
||||
threadId[curThreadNo] = 0;
|
||||
hBarrier[curThreadNo] = CreateEvent(nullptr, false, false, nullptr);
|
||||
}
|
||||
for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) {
|
||||
hThread[curThreadNo] = nullptr;
|
||||
threadId[curThreadNo] = 0;
|
||||
hBarrier[curThreadNo] = CreateEvent(nullptr, false, false, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -46,26 +45,25 @@ ThreadManager::ThreadManager()
|
|||
//-----------------------------------------------------------------------------
|
||||
ThreadManager::~ThreadManager()
|
||||
{
|
||||
// locals
|
||||
unsigned int curThreadNo;
|
||||
// locals
|
||||
unsigned int curThreadNo;
|
||||
|
||||
for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++)
|
||||
{
|
||||
CloseHandle(hBarrier[curThreadNo]);
|
||||
}
|
||||
for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) {
|
||||
CloseHandle(hBarrier[curThreadNo]);
|
||||
}
|
||||
|
||||
DeleteCriticalSection(&csBarrier);
|
||||
CloseHandle(hEventBarrierPassedByEveryBody);
|
||||
DeleteCriticalSection(&csBarrier);
|
||||
CloseHandle(hEventBarrierPassedByEveryBody);
|
||||
|
||||
if (hBarrier != nullptr)
|
||||
delete[] hBarrier;
|
||||
hBarrier = nullptr;
|
||||
if (hThread != nullptr)
|
||||
delete[] hThread;
|
||||
hThread = nullptr;
|
||||
if (threadId != nullptr)
|
||||
delete[] threadId;
|
||||
threadId = nullptr;
|
||||
if (hBarrier != nullptr)
|
||||
delete[] hBarrier;
|
||||
hBarrier = nullptr;
|
||||
if (hThread != nullptr)
|
||||
delete[] hThread;
|
||||
hThread = nullptr;
|
||||
if (threadId != nullptr)
|
||||
delete[] threadId;
|
||||
threadId = nullptr;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -74,45 +72,42 @@ ThreadManager::~ThreadManager()
|
|||
//-----------------------------------------------------------------------------
|
||||
void ThreadManager::waitForOtherThreads(unsigned int threadNo)
|
||||
{
|
||||
// wait if other threads are still waiting at the barrier
|
||||
//cout << endl << "thread=" << threadNo << ", numThreadsPassedBarrier= " << numThreadsPassedBarrier << ": " << "while (numThreadsPassedBarrier>0)";
|
||||
if (numThreadsPassedBarrier > 0)
|
||||
{
|
||||
WaitForSingleObject(hEventBarrierPassedByEveryBody, INFINITE);
|
||||
}
|
||||
// wait if other threads are still waiting at the barrier
|
||||
//cout << endl << "thread=" << threadNo << ", numThreadsPassedBarrier= " << numThreadsPassedBarrier << ": " << "while (numThreadsPassedBarrier>0)";
|
||||
if (numThreadsPassedBarrier > 0) {
|
||||
WaitForSingleObject(hEventBarrierPassedByEveryBody, INFINITE);
|
||||
}
|
||||
|
||||
// a simple while (numThreadsPassedBarrier>0) {}; does not work, since the variable 'numThreadsPassedBarrier' is not updated, due to compiler optimizations
|
||||
// a simple while (numThreadsPassedBarrier>0) {}; does not work, since the variable 'numThreadsPassedBarrier' is not updated, due to compiler optimizations
|
||||
|
||||
// set signal that barrier is reached
|
||||
//cout << endl << "thread=" << threadNo << ", numThreadsPassedBarrier= " << numThreadsPassedBarrier << ": " << "SetEvent()";
|
||||
SetEvent(hBarrier[threadNo]);
|
||||
// set signal that barrier is reached
|
||||
//cout << endl << "thread=" << threadNo << ", numThreadsPassedBarrier= " << numThreadsPassedBarrier << ": " << "SetEvent()";
|
||||
SetEvent(hBarrier[threadNo]);
|
||||
|
||||
// enter the barrier one by one
|
||||
//cout << endl << "thread=" << threadNo << ", numThreadsPassedBarrier= " << numThreadsPassedBarrier << ": " << "EnterCriticalSection()";
|
||||
EnterCriticalSection(&csBarrier);
|
||||
// enter the barrier one by one
|
||||
//cout << endl << "thread=" << threadNo << ", numThreadsPassedBarrier= " << numThreadsPassedBarrier << ": " << "EnterCriticalSection()";
|
||||
EnterCriticalSection(&csBarrier);
|
||||
|
||||
// if the first one which entered, then wait until other threads
|
||||
if (numThreadsPassedBarrier == 0)
|
||||
{
|
||||
//cout << endl << "thread=" << threadNo << ", numThreadsPassedBarrier= " << numThreadsPassedBarrier << ": " << "WaitForMultipleObjects()";
|
||||
WaitForMultipleObjects(numThreads, hBarrier, TRUE, INFINITE);
|
||||
ResetEvent(hEventBarrierPassedByEveryBody);
|
||||
}
|
||||
// if the first one which entered, then wait until other threads
|
||||
if (numThreadsPassedBarrier == 0) {
|
||||
//cout << endl << "thread=" << threadNo << ", numThreadsPassedBarrier= " << numThreadsPassedBarrier << ": " << "WaitForMultipleObjects()";
|
||||
WaitForMultipleObjects(numThreads, hBarrier, TRUE, INFINITE);
|
||||
ResetEvent(hEventBarrierPassedByEveryBody);
|
||||
}
|
||||
|
||||
// count threads which passed the barrier
|
||||
//cout << endl << "thread=" << threadNo << ", numThreadsPassedBarrier= " << numThreadsPassedBarrier << ": " << "numThreadsPassedBarrier++";
|
||||
numThreadsPassedBarrier++;
|
||||
// count threads which passed the barrier
|
||||
//cout << endl << "thread=" << threadNo << ", numThreadsPassedBarrier= " << numThreadsPassedBarrier << ": " << "numThreadsPassedBarrier++";
|
||||
numThreadsPassedBarrier++;
|
||||
|
||||
// the last one closes the door
|
||||
//cout << endl << "thread=" << threadNo << ", numThreadsPassedBarrier= " << numThreadsPassedBarrier << ": " << "if (numThreadsPassedBarrier == numThreads) numThreadsPassedBarrier = 0";
|
||||
if (numThreadsPassedBarrier == numThreads)
|
||||
{
|
||||
numThreadsPassedBarrier = 0;
|
||||
SetEvent(hEventBarrierPassedByEveryBody);
|
||||
}
|
||||
// the last one closes the door
|
||||
//cout << endl << "thread=" << threadNo << ", numThreadsPassedBarrier= " << numThreadsPassedBarrier << ": " << "if (numThreadsPassedBarrier == numThreads) numThreadsPassedBarrier = 0";
|
||||
if (numThreadsPassedBarrier == numThreads) {
|
||||
numThreadsPassedBarrier = 0;
|
||||
SetEvent(hEventBarrierPassedByEveryBody);
|
||||
}
|
||||
|
||||
//cout << endl << "thread=" << threadNo << ", numThreadsPassedBarrier= " << numThreadsPassedBarrier << ": " << "LeaveCriticalSection()";
|
||||
LeaveCriticalSection(&csBarrier);
|
||||
//cout << endl << "thread=" << threadNo << ", numThreadsPassedBarrier= " << numThreadsPassedBarrier << ": " << "LeaveCriticalSection()";
|
||||
LeaveCriticalSection(&csBarrier);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -121,7 +116,7 @@ void ThreadManager::waitForOtherThreads(unsigned int threadNo)
|
|||
//-----------------------------------------------------------------------------
|
||||
unsigned int ThreadManager::getNumThreads()
|
||||
{
|
||||
return numThreads;
|
||||
return numThreads;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -130,24 +125,21 @@ unsigned int ThreadManager::getNumThreads()
|
|||
//-----------------------------------------------------------------------------
|
||||
bool ThreadManager::setNumThreads(unsigned int newNumThreads)
|
||||
{
|
||||
// cancel if any thread running
|
||||
EnterCriticalSection(&csBarrier);
|
||||
for (unsigned int curThreadNo = 0; curThreadNo < numThreads; curThreadNo++)
|
||||
{
|
||||
if (hThread[curThreadNo])
|
||||
return false;
|
||||
}
|
||||
for (unsigned int curThreadNo = 0; curThreadNo < numThreads; curThreadNo++)
|
||||
{
|
||||
CloseHandle(hBarrier[curThreadNo]);
|
||||
}
|
||||
numThreads = newNumThreads;
|
||||
for (unsigned int curThreadNo = 0; curThreadNo < numThreads; curThreadNo++)
|
||||
{
|
||||
hBarrier[curThreadNo] = CreateEvent(nullptr, false, false, nullptr);
|
||||
}
|
||||
LeaveCriticalSection(&csBarrier);
|
||||
return true;
|
||||
// cancel if any thread running
|
||||
EnterCriticalSection(&csBarrier);
|
||||
for (unsigned int curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) {
|
||||
if (hThread[curThreadNo])
|
||||
return false;
|
||||
}
|
||||
for (unsigned int curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) {
|
||||
CloseHandle(hBarrier[curThreadNo]);
|
||||
}
|
||||
numThreads = newNumThreads;
|
||||
for (unsigned int curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) {
|
||||
hBarrier[curThreadNo] = CreateEvent(nullptr, false, false, nullptr);
|
||||
}
|
||||
LeaveCriticalSection(&csBarrier);
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -156,21 +148,17 @@ bool ThreadManager::setNumThreads(unsigned int newNumThreads)
|
|||
//-----------------------------------------------------------------------------
|
||||
void ThreadManager::pauseExecution()
|
||||
{
|
||||
for (unsigned int curThread = 0; curThread < numThreads; curThread++)
|
||||
{
|
||||
for (unsigned int curThread = 0; curThread < numThreads; curThread++) {
|
||||
|
||||
// unsuspend all threads
|
||||
if (!executionPaused)
|
||||
{
|
||||
SuspendThread(hThread[curThread]);
|
||||
// suspend all threads
|
||||
}
|
||||
else
|
||||
{
|
||||
ResumeThread(hThread[curThread]);
|
||||
}
|
||||
}
|
||||
executionPaused = (!executionPaused);
|
||||
// unsuspend all threads
|
||||
if (!executionPaused) {
|
||||
SuspendThread(hThread[curThread]);
|
||||
// suspend all threads
|
||||
} else {
|
||||
ResumeThread(hThread[curThread]);
|
||||
}
|
||||
}
|
||||
executionPaused = (!executionPaused);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -180,12 +168,11 @@ void ThreadManager::pauseExecution()
|
|||
//-----------------------------------------------------------------------------
|
||||
void ThreadManager::cancelExecution()
|
||||
{
|
||||
termineAllThreads = true;
|
||||
executionCancelled = true;
|
||||
if (executionPaused)
|
||||
{
|
||||
pauseExecution();
|
||||
}
|
||||
termineAllThreads = true;
|
||||
executionCancelled = true;
|
||||
if (executionPaused) {
|
||||
pauseExecution();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -194,7 +181,7 @@ void ThreadManager::cancelExecution()
|
|||
//-----------------------------------------------------------------------------
|
||||
void ThreadManager::uncancelExecution()
|
||||
{
|
||||
executionCancelled = false;
|
||||
executionCancelled = false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -203,7 +190,7 @@ void ThreadManager::uncancelExecution()
|
|||
//-----------------------------------------------------------------------------
|
||||
bool ThreadManager::wasExecutionCancelled()
|
||||
{
|
||||
return executionCancelled;
|
||||
return executionCancelled;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -212,18 +199,16 @@ bool ThreadManager::wasExecutionCancelled()
|
|||
//-----------------------------------------------------------------------------
|
||||
unsigned int ThreadManager::getThreadNumber()
|
||||
{
|
||||
// locals
|
||||
DWORD curThreadId = GetCurrentThreadId();
|
||||
unsigned int curThreadNo;
|
||||
// locals
|
||||
DWORD curThreadId = GetCurrentThreadId();
|
||||
unsigned int curThreadNo;
|
||||
|
||||
for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++)
|
||||
{
|
||||
if (curThreadId == threadId[curThreadNo])
|
||||
{
|
||||
return curThreadNo;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) {
|
||||
if (curThreadId == threadId[curThreadNo]) {
|
||||
return curThreadNo;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -232,62 +217,54 @@ unsigned int ThreadManager::getThreadNumber()
|
|||
//-----------------------------------------------------------------------------
|
||||
unsigned int ThreadManager::executeInParallel(DWORD threadProc(void *pParameter), void *pParameter, unsigned int parameterStructSize)
|
||||
{
|
||||
// locals
|
||||
unsigned int curThreadNo;
|
||||
SIZE_T dwStackSize = 0;
|
||||
// locals
|
||||
unsigned int curThreadNo;
|
||||
SIZE_T dwStackSize = 0;
|
||||
|
||||
// parameters ok?
|
||||
if (pParameter == nullptr)
|
||||
return TM_RETURN_VALUE_INVALID_PARAM;
|
||||
// parameters ok?
|
||||
if (pParameter == nullptr)
|
||||
return TM_RETURN_VALUE_INVALID_PARAM;
|
||||
|
||||
// globals
|
||||
termineAllThreads = false;
|
||||
// globals
|
||||
termineAllThreads = false;
|
||||
|
||||
// create threads
|
||||
for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++)
|
||||
{
|
||||
// create threads
|
||||
for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) {
|
||||
|
||||
hThread[curThreadNo] = CreateThread(nullptr, dwStackSize, (LPTHREAD_START_ROUTINE)threadProc, (void *)(((char *)pParameter) + curThreadNo * parameterStructSize), CREATE_SUSPENDED, &threadId[curThreadNo]);
|
||||
SetThreadPriority(hThread[curThreadNo], THREAD_PRIORITY_BELOW_NORMAL);
|
||||
hThread[curThreadNo] = CreateThread(nullptr, dwStackSize, (LPTHREAD_START_ROUTINE)threadProc, (void *)(((char *)pParameter) + curThreadNo * parameterStructSize), CREATE_SUSPENDED, &threadId[curThreadNo]);
|
||||
SetThreadPriority(hThread[curThreadNo], THREAD_PRIORITY_BELOW_NORMAL);
|
||||
|
||||
if (hThread[curThreadNo] == nullptr)
|
||||
{
|
||||
for (curThreadNo; curThreadNo > 0; curThreadNo--)
|
||||
{
|
||||
CloseHandle(hThread[curThreadNo - 1]);
|
||||
hThread[curThreadNo - 1] = nullptr;
|
||||
}
|
||||
return TM_RETURN_VALUE_UNEXPECTED_ERROR;
|
||||
}
|
||||
}
|
||||
if (hThread[curThreadNo] == nullptr) {
|
||||
for (curThreadNo; curThreadNo > 0; curThreadNo--) {
|
||||
CloseHandle(hThread[curThreadNo - 1]);
|
||||
hThread[curThreadNo - 1] = nullptr;
|
||||
}
|
||||
return TM_RETURN_VALUE_UNEXPECTED_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
// start threads
|
||||
for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++)
|
||||
{
|
||||
if (!executionPaused)
|
||||
ResumeThread(hThread[curThreadNo]);
|
||||
}
|
||||
// start threads
|
||||
for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) {
|
||||
if (!executionPaused)
|
||||
ResumeThread(hThread[curThreadNo]);
|
||||
}
|
||||
|
||||
// wait for every thread to end
|
||||
WaitForMultipleObjects(numThreads, hThread, TRUE, INFINITE);
|
||||
// wait for every thread to end
|
||||
WaitForMultipleObjects(numThreads, hThread, TRUE, INFINITE);
|
||||
|
||||
// Close all thread handles upon completion.
|
||||
for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++)
|
||||
{
|
||||
CloseHandle(hThread[curThreadNo]);
|
||||
hThread[curThreadNo] = nullptr;
|
||||
threadId[curThreadNo] = 0;
|
||||
}
|
||||
// Close all thread handles upon completion.
|
||||
for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) {
|
||||
CloseHandle(hThread[curThreadNo]);
|
||||
hThread[curThreadNo] = nullptr;
|
||||
threadId[curThreadNo] = 0;
|
||||
}
|
||||
|
||||
// everything ok
|
||||
if (executionCancelled)
|
||||
{
|
||||
return TM_RETURN_VALUE_EXECUTION_CANCELLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
return TM_RETURN_VALUE_OK;
|
||||
}
|
||||
// everything ok
|
||||
if (executionCancelled) {
|
||||
return TM_RETURN_VALUE_EXECUTION_CANCELLED;
|
||||
} else {
|
||||
return TM_RETURN_VALUE_OK;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -297,114 +274,102 @@ unsigned int ThreadManager::executeInParallel(DWORD threadProc(void *pParameter)
|
|||
// finalValue - this value is part of the iteration, meaning that index ranges from initialValue to finalValue including both border values
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned int ThreadManager::executeParallelLoop(DWORD threadProc(void *pParameter, int index),
|
||||
void *pParameter,
|
||||
unsigned int parameterStructSize,
|
||||
unsigned int scheduleType,
|
||||
int initialValue,
|
||||
int finalValue,
|
||||
int inkrement)
|
||||
void *pParameter,
|
||||
unsigned int parameterStructSize,
|
||||
unsigned int scheduleType,
|
||||
int initialValue,
|
||||
int finalValue,
|
||||
int inkrement)
|
||||
{
|
||||
// parameters ok?
|
||||
if (executionCancelled == true)
|
||||
return TM_RETURN_VALUE_EXECUTION_CANCELLED;
|
||||
if (pParameter == nullptr)
|
||||
return TM_RETURN_VALUE_INVALID_PARAM;
|
||||
if (scheduleType >= TM_SCHEDULE_NUM_TYPES)
|
||||
return TM_RETURN_VALUE_INVALID_PARAM;
|
||||
if (inkrement == 0)
|
||||
return TM_RETURN_VALUE_INVALID_PARAM;
|
||||
if (abs(finalValue - initialValue) == abs(inkrement))
|
||||
return TM_RETURN_VALUE_INVALID_PARAM;
|
||||
// parameters ok?
|
||||
if (executionCancelled == true)
|
||||
return TM_RETURN_VALUE_EXECUTION_CANCELLED;
|
||||
if (pParameter == nullptr)
|
||||
return TM_RETURN_VALUE_INVALID_PARAM;
|
||||
if (scheduleType >= TM_SCHEDULE_NUM_TYPES)
|
||||
return TM_RETURN_VALUE_INVALID_PARAM;
|
||||
if (inkrement == 0)
|
||||
return TM_RETURN_VALUE_INVALID_PARAM;
|
||||
if (abs(finalValue - initialValue) == abs(inkrement))
|
||||
return TM_RETURN_VALUE_INVALID_PARAM;
|
||||
|
||||
// locals
|
||||
unsigned int curThreadNo; // the threads are enumerated from 0 to numThreads-1
|
||||
int numIterations = (finalValue - initialValue) / inkrement + 1; // total number of iterations
|
||||
int chunkSize = 0; // number of iterations per chunk
|
||||
SIZE_T dwStackSize = 0; // initital stack size of each thread. 0 means default size ~1MB
|
||||
ForLoop *forLoopParameters = new ForLoop[numThreads]; //
|
||||
// locals
|
||||
unsigned int curThreadNo; // the threads are enumerated from 0 to numThreads-1
|
||||
int numIterations = (finalValue - initialValue) / inkrement + 1; // total number of iterations
|
||||
int chunkSize = 0; // number of iterations per chunk
|
||||
SIZE_T dwStackSize = 0; // initital stack size of each thread. 0 means default size ~1MB
|
||||
ForLoop *forLoopParameters = new ForLoop[numThreads]; //
|
||||
|
||||
// globals
|
||||
termineAllThreads = false;
|
||||
// globals
|
||||
termineAllThreads = false;
|
||||
|
||||
// create threads
|
||||
for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++)
|
||||
{
|
||||
// create threads
|
||||
for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) {
|
||||
|
||||
forLoopParameters[curThreadNo].pParameter = (pParameter != nullptr ? (void *)(((char *)pParameter) + curThreadNo * parameterStructSize) : nullptr);
|
||||
forLoopParameters[curThreadNo].threadManager = this;
|
||||
forLoopParameters[curThreadNo].threadProc = threadProc;
|
||||
forLoopParameters[curThreadNo].inkrement = inkrement;
|
||||
forLoopParameters[curThreadNo].scheduleType = scheduleType;
|
||||
forLoopParameters[curThreadNo].pParameter = (pParameter != nullptr ? (void *)(((char *)pParameter) + curThreadNo * parameterStructSize) : nullptr);
|
||||
forLoopParameters[curThreadNo].threadManager = this;
|
||||
forLoopParameters[curThreadNo].threadProc = threadProc;
|
||||
forLoopParameters[curThreadNo].inkrement = inkrement;
|
||||
forLoopParameters[curThreadNo].scheduleType = scheduleType;
|
||||
|
||||
switch (scheduleType)
|
||||
{
|
||||
case TM_SCHEDULE_STATIC:
|
||||
chunkSize = numIterations / numThreads + (curThreadNo < numIterations % numThreads ? 1 : 0);
|
||||
if (curThreadNo == 0)
|
||||
{
|
||||
forLoopParameters[curThreadNo].initialValue = initialValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
forLoopParameters[curThreadNo].initialValue = forLoopParameters[curThreadNo - 1].finalValue + 1;
|
||||
}
|
||||
forLoopParameters[curThreadNo].finalValue = forLoopParameters[curThreadNo].initialValue + chunkSize - 1;
|
||||
break;
|
||||
case TM_SCHEDULE_DYNAMIC:
|
||||
return TM_RETURN_VALUE_INVALID_PARAM;
|
||||
break;
|
||||
case TM_SCHEDULE_GUIDED:
|
||||
return TM_RETURN_VALUE_INVALID_PARAM;
|
||||
break;
|
||||
case TM_SCHEDULE_RUNTIME:
|
||||
return TM_RETURN_VALUE_INVALID_PARAM;
|
||||
break;
|
||||
}
|
||||
switch (scheduleType) {
|
||||
case TM_SCHEDULE_STATIC:
|
||||
chunkSize = numIterations / numThreads + (curThreadNo < numIterations %numThreads ? 1 : 0);
|
||||
if (curThreadNo == 0) {
|
||||
forLoopParameters[curThreadNo].initialValue = initialValue;
|
||||
} else {
|
||||
forLoopParameters[curThreadNo].initialValue = forLoopParameters[curThreadNo - 1].finalValue + 1;
|
||||
}
|
||||
forLoopParameters[curThreadNo].finalValue = forLoopParameters[curThreadNo].initialValue + chunkSize - 1;
|
||||
break;
|
||||
case TM_SCHEDULE_DYNAMIC:
|
||||
return TM_RETURN_VALUE_INVALID_PARAM;
|
||||
break;
|
||||
case TM_SCHEDULE_GUIDED:
|
||||
return TM_RETURN_VALUE_INVALID_PARAM;
|
||||
break;
|
||||
case TM_SCHEDULE_RUNTIME:
|
||||
return TM_RETURN_VALUE_INVALID_PARAM;
|
||||
break;
|
||||
}
|
||||
|
||||
// create suspended thread
|
||||
hThread[curThreadNo] = CreateThread(nullptr, dwStackSize, threadForLoop, (LPVOID)(&forLoopParameters[curThreadNo]), CREATE_SUSPENDED, &threadId[curThreadNo]);
|
||||
SetThreadPriority(hThread[curThreadNo], THREAD_PRIORITY_BELOW_NORMAL);
|
||||
if (hThread[curThreadNo] == nullptr)
|
||||
{
|
||||
for (curThreadNo; curThreadNo > 0; curThreadNo--)
|
||||
{
|
||||
CloseHandle(hThread[curThreadNo - 1]);
|
||||
hThread[curThreadNo - 1] = nullptr;
|
||||
}
|
||||
return TM_RETURN_VALUE_UNEXPECTED_ERROR;
|
||||
}
|
||||
//DWORD dwThreadAffinityMask = 1 << curThreadNo;
|
||||
//SetThreadAffinityMask(hThread[curThreadNo], &dwThreadAffinityMask);
|
||||
}
|
||||
// create suspended thread
|
||||
hThread[curThreadNo] = CreateThread(nullptr, dwStackSize, threadForLoop, (LPVOID)(&forLoopParameters[curThreadNo]), CREATE_SUSPENDED, &threadId[curThreadNo]);
|
||||
SetThreadPriority(hThread[curThreadNo], THREAD_PRIORITY_BELOW_NORMAL);
|
||||
if (hThread[curThreadNo] == nullptr) {
|
||||
for (curThreadNo; curThreadNo > 0; curThreadNo--) {
|
||||
CloseHandle(hThread[curThreadNo - 1]);
|
||||
hThread[curThreadNo - 1] = nullptr;
|
||||
}
|
||||
return TM_RETURN_VALUE_UNEXPECTED_ERROR;
|
||||
}
|
||||
//DWORD dwThreadAffinityMask = 1 << curThreadNo;
|
||||
//SetThreadAffinityMask(hThread[curThreadNo], &dwThreadAffinityMask);
|
||||
}
|
||||
|
||||
// start threads, but don't resume if in pause mode
|
||||
for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++)
|
||||
{
|
||||
if (!executionPaused)
|
||||
ResumeThread(hThread[curThreadNo]);
|
||||
}
|
||||
// start threads, but don't resume if in pause mode
|
||||
for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) {
|
||||
if (!executionPaused)
|
||||
ResumeThread(hThread[curThreadNo]);
|
||||
}
|
||||
|
||||
// wait for every thread to end
|
||||
WaitForMultipleObjects(numThreads, hThread, TRUE, INFINITE);
|
||||
// wait for every thread to end
|
||||
WaitForMultipleObjects(numThreads, hThread, TRUE, INFINITE);
|
||||
|
||||
// Close all thread handles upon completion.
|
||||
for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++)
|
||||
{
|
||||
CloseHandle(hThread[curThreadNo]);
|
||||
hThread[curThreadNo] = nullptr;
|
||||
threadId[curThreadNo] = 0;
|
||||
}
|
||||
delete[] forLoopParameters;
|
||||
// Close all thread handles upon completion.
|
||||
for (curThreadNo = 0; curThreadNo < numThreads; curThreadNo++) {
|
||||
CloseHandle(hThread[curThreadNo]);
|
||||
hThread[curThreadNo] = nullptr;
|
||||
threadId[curThreadNo] = 0;
|
||||
}
|
||||
delete[] forLoopParameters;
|
||||
|
||||
// everything ok
|
||||
if (executionCancelled)
|
||||
{
|
||||
return TM_RETURN_VALUE_EXECUTION_CANCELLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
return TM_RETURN_VALUE_OK;
|
||||
}
|
||||
// everything ok
|
||||
if (executionCancelled) {
|
||||
return TM_RETURN_VALUE_EXECUTION_CANCELLED;
|
||||
} else {
|
||||
return TM_RETURN_VALUE_OK;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -413,44 +378,41 @@ unsigned int ThreadManager::executeParallelLoop(DWORD threadProc(void *pParamete
|
|||
//-----------------------------------------------------------------------------
|
||||
DWORD WINAPI ThreadManager::threadForLoop(LPVOID lpParameter)
|
||||
{
|
||||
// locals
|
||||
ForLoop *forLoopParameters = (ForLoop *)lpParameter;
|
||||
int index;
|
||||
// locals
|
||||
ForLoop *forLoopParameters = (ForLoop *)lpParameter;
|
||||
int index;
|
||||
|
||||
switch (forLoopParameters->scheduleType)
|
||||
{
|
||||
case TM_SCHEDULE_STATIC:
|
||||
for (index = forLoopParameters->initialValue; (forLoopParameters->inkrement < 0) ? index >= forLoopParameters->finalValue : index <= forLoopParameters->finalValue; index += forLoopParameters->inkrement)
|
||||
{
|
||||
switch (forLoopParameters->threadProc(forLoopParameters->pParameter, index))
|
||||
{
|
||||
case TM_RETURN_VALUE_OK:
|
||||
break;
|
||||
case TM_RETURN_VALUE_TERMINATE_ALL_THREADS:
|
||||
forLoopParameters->threadManager->termineAllThreads = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (forLoopParameters->threadManager->termineAllThreads)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case TM_SCHEDULE_DYNAMIC:
|
||||
return TM_RETURN_VALUE_INVALID_PARAM;
|
||||
break;
|
||||
case TM_SCHEDULE_GUIDED:
|
||||
return TM_RETURN_VALUE_INVALID_PARAM;
|
||||
break;
|
||||
case TM_SCHEDULE_RUNTIME:
|
||||
return TM_RETURN_VALUE_INVALID_PARAM;
|
||||
break;
|
||||
}
|
||||
switch (forLoopParameters->scheduleType) {
|
||||
case TM_SCHEDULE_STATIC:
|
||||
for (index = forLoopParameters->initialValue; (forLoopParameters->inkrement < 0) ? index >= forLoopParameters->finalValue : index <= forLoopParameters->finalValue; index += forLoopParameters->inkrement) {
|
||||
switch (forLoopParameters->threadProc(forLoopParameters->pParameter, index)) {
|
||||
case TM_RETURN_VALUE_OK:
|
||||
break;
|
||||
case TM_RETURN_VALUE_TERMINATE_ALL_THREADS:
|
||||
forLoopParameters->threadManager->termineAllThreads = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (forLoopParameters->threadManager->termineAllThreads)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case TM_SCHEDULE_DYNAMIC:
|
||||
return TM_RETURN_VALUE_INVALID_PARAM;
|
||||
break;
|
||||
case TM_SCHEDULE_GUIDED:
|
||||
return TM_RETURN_VALUE_INVALID_PARAM;
|
||||
break;
|
||||
case TM_SCHEDULE_RUNTIME:
|
||||
return TM_RETURN_VALUE_INVALID_PARAM;
|
||||
break;
|
||||
}
|
||||
|
||||
return TM_RETURN_VALUE_OK;
|
||||
return TM_RETURN_VALUE_OK;
|
||||
}
|
||||
|
||||
/*** To Do's ********************************************************************************
|
||||
- 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
|
||||
*********************************************************************************************/
|
|
@ -1,9 +1,9 @@
|
|||
/*********************************************************************\
|
||||
threadManager.h
|
||||
Copyright (c) Thomas Weber. All rights reserved.
|
||||
Copyright (C) 2021 The Sanmill developers (see AUTHORS file)
|
||||
Licensed under the MIT License.
|
||||
https://github.com/madweasel/madweasels-cpp
|
||||
threadManager.h
|
||||
Copyright (c) Thomas Weber. All rights reserved.
|
||||
Copyright (C) 2021 The Sanmill developers (see AUTHORS file)
|
||||
Licensed under the MIT License.
|
||||
https://github.com/madweasel/madweasels-cpp
|
||||
\*********************************************************************/
|
||||
|
||||
#ifndef THREADMANAGER_H
|
||||
|
@ -39,114 +39,117 @@ using namespace std; // use standard library namespace
|
|||
class ThreadManager
|
||||
{
|
||||
private:
|
||||
// structures
|
||||
struct ForLoop
|
||||
{
|
||||
unsigned int scheduleType;
|
||||
int inkrement;
|
||||
int initialValue;
|
||||
int finalValue;
|
||||
void *pParameter;
|
||||
DWORD (*threadProc)
|
||||
(void *pParameter, int index); // pointer to the user function to be executed by the threads
|
||||
ThreadManager *threadManager;
|
||||
};
|
||||
// structures
|
||||
struct ForLoop
|
||||
{
|
||||
unsigned int scheduleType;
|
||||
int inkrement;
|
||||
int initialValue;
|
||||
int finalValue;
|
||||
void *pParameter;
|
||||
DWORD(*threadProc)
|
||||
(void *pParameter, int index); // pointer to the user function to be executed by the threads
|
||||
ThreadManager *threadManager;
|
||||
};
|
||||
|
||||
// Variables
|
||||
unsigned int numThreads; // number of threads
|
||||
HANDLE *hThread; // array of size 'numThreads' containing the thread handles
|
||||
DWORD *threadId; // array of size 'numThreads' containing the thread ids
|
||||
bool termineAllThreads;
|
||||
bool executionPaused; // switch for the
|
||||
bool executionCancelled; // true when cancelExecution() was called
|
||||
// Variables
|
||||
unsigned int numThreads; // number of threads
|
||||
HANDLE *hThread; // array of size 'numThreads' containing the thread handles
|
||||
DWORD *threadId; // array of size 'numThreads' containing the thread ids
|
||||
bool termineAllThreads;
|
||||
bool executionPaused; // switch for the
|
||||
bool executionCancelled; // true when cancelExecution() was called
|
||||
|
||||
// barier stuff
|
||||
HANDLE hEventBarrierPassedByEveryBody;
|
||||
HANDLE *hBarrier; // array of size 'numThreads' containing the event handles for the barrier
|
||||
unsigned int numThreadsPassedBarrier;
|
||||
CRITICAL_SECTION csBarrier;
|
||||
// barier stuff
|
||||
HANDLE hEventBarrierPassedByEveryBody;
|
||||
HANDLE *hBarrier; // array of size 'numThreads' containing the event handles for the barrier
|
||||
unsigned int numThreadsPassedBarrier;
|
||||
CRITICAL_SECTION csBarrier;
|
||||
|
||||
// functions
|
||||
static DWORD WINAPI threadForLoop(LPVOID lpParameter);
|
||||
// functions
|
||||
static DWORD WINAPI threadForLoop(LPVOID lpParameter);
|
||||
|
||||
public:
|
||||
class ThreadVarsArrayItem
|
||||
{
|
||||
public:
|
||||
unsigned int curThreadNo;
|
||||
class ThreadVarsArrayItem
|
||||
{
|
||||
public:
|
||||
unsigned int curThreadNo;
|
||||
|
||||
virtual void initializeElement(){};
|
||||
virtual void destroyElement(){};
|
||||
virtual void reduce(){};
|
||||
};
|
||||
virtual void initializeElement()
|
||||
{
|
||||
};
|
||||
virtual void destroyElement()
|
||||
{
|
||||
};
|
||||
virtual void reduce()
|
||||
{
|
||||
};
|
||||
};
|
||||
|
||||
template <class varType>
|
||||
class ThreadVarsArray
|
||||
{
|
||||
public:
|
||||
unsigned int numberOfThreads;
|
||||
varType *item;
|
||||
template <class varType>
|
||||
class ThreadVarsArray
|
||||
{
|
||||
public:
|
||||
unsigned int numberOfThreads;
|
||||
varType *item;
|
||||
|
||||
ThreadVarsArray(unsigned int numberOfThreads, varType &master)
|
||||
{
|
||||
this->numberOfThreads = numberOfThreads;
|
||||
this->item = new varType[numberOfThreads];
|
||||
ThreadVarsArray(unsigned int numberOfThreads, varType &master)
|
||||
{
|
||||
this->numberOfThreads = numberOfThreads;
|
||||
this->item = new varType[numberOfThreads];
|
||||
|
||||
for (unsigned int threadCounter = 0; threadCounter < numberOfThreads; threadCounter++)
|
||||
{
|
||||
item[threadCounter].curThreadNo = threadCounter;
|
||||
item[threadCounter].initializeElement(master);
|
||||
item[threadCounter].curThreadNo = threadCounter; // if 'curThreadNo' is overwritten in 'initializeElement()'
|
||||
}
|
||||
};
|
||||
for (unsigned int threadCounter = 0; threadCounter < numberOfThreads; threadCounter++) {
|
||||
item[threadCounter].curThreadNo = threadCounter;
|
||||
item[threadCounter].initializeElement(master);
|
||||
item[threadCounter].curThreadNo = threadCounter; // if 'curThreadNo' is overwritten in 'initializeElement()'
|
||||
}
|
||||
};
|
||||
|
||||
~ThreadVarsArray()
|
||||
{
|
||||
for (unsigned int threadCounter = 0; threadCounter < numberOfThreads; threadCounter++)
|
||||
{
|
||||
item[threadCounter].destroyElement();
|
||||
}
|
||||
delete[] item;
|
||||
};
|
||||
~ThreadVarsArray()
|
||||
{
|
||||
for (unsigned int threadCounter = 0; threadCounter < numberOfThreads; threadCounter++) {
|
||||
item[threadCounter].destroyElement();
|
||||
}
|
||||
delete[] item;
|
||||
};
|
||||
|
||||
void *getPointerToArray()
|
||||
{
|
||||
return (void *)item;
|
||||
};
|
||||
void *getPointerToArray()
|
||||
{
|
||||
return (void *)item;
|
||||
};
|
||||
|
||||
unsigned int getSizeOfArray()
|
||||
{
|
||||
return sizeof(varType);
|
||||
};
|
||||
unsigned int getSizeOfArray()
|
||||
{
|
||||
return sizeof(varType);
|
||||
};
|
||||
|
||||
void reduce()
|
||||
{
|
||||
for (unsigned int threadCounter = 0; threadCounter < numberOfThreads; threadCounter++)
|
||||
{
|
||||
item[threadCounter].reduce();
|
||||
}
|
||||
};
|
||||
};
|
||||
void reduce()
|
||||
{
|
||||
for (unsigned int threadCounter = 0; threadCounter < numberOfThreads; threadCounter++) {
|
||||
item[threadCounter].reduce();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// Constructor / destructor
|
||||
ThreadManager();
|
||||
~ThreadManager();
|
||||
// Constructor / destructor
|
||||
ThreadManager();
|
||||
~ThreadManager();
|
||||
|
||||
// Functions
|
||||
unsigned int getThreadNumber();
|
||||
unsigned int getNumThreads();
|
||||
// Functions
|
||||
unsigned int getThreadNumber();
|
||||
unsigned int getNumThreads();
|
||||
|
||||
bool setNumThreads(unsigned int newNumThreads);
|
||||
void waitForOtherThreads(unsigned int threadNo);
|
||||
void pauseExecution(); // un-/suspend all threads
|
||||
void cancelExecution(); // termineAllThreads auf true
|
||||
bool wasExecutionCancelled();
|
||||
void uncancelExecution(); // sets executionCancelled to false, otherwise executeParellelLoop returns immediatelly
|
||||
//... void setCallBackFunction (void userFunction(void* pUser), void* pUser, DWORD milliseconds); // a user function which is called every x-milliseconds during execution between two iterations
|
||||
bool setNumThreads(unsigned int newNumThreads);
|
||||
void waitForOtherThreads(unsigned int threadNo);
|
||||
void pauseExecution(); // un-/suspend all threads
|
||||
void cancelExecution(); // termineAllThreads auf true
|
||||
bool wasExecutionCancelled();
|
||||
void uncancelExecution(); // sets executionCancelled to false, otherwise executeParellelLoop returns immediatelly
|
||||
//... void setCallBackFunction (void userFunction(void* pUser), void* pUser, DWORD milliseconds); // a user function which is called every x-milliseconds during execution between two iterations
|
||||
|
||||
// execute
|
||||
unsigned int executeInParallel(DWORD threadProc(void *pParameter), void *pParameter, unsigned int parameterStructSize);
|
||||
unsigned int executeParallelLoop(DWORD threadProc(void *pParameter, int index), void *pParameter, unsigned int parameterStructSize, unsigned int scheduleType, int initialValue, int finalValue, int inkrement);
|
||||
// execute
|
||||
unsigned int executeInParallel(DWORD threadProc(void *pParameter), void *pParameter, unsigned int parameterStructSize);
|
||||
unsigned int executeParallelLoop(DWORD threadProc(void *pParameter, int index), void *pParameter, unsigned int parameterStructSize, unsigned int scheduleType, int initialValue, int finalValue, int inkrement);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue