perfect: Format code with msvc

This commit is contained in:
Calcitem 2021-01-20 01:38:08 +08:00
parent 5c71717a9c
commit f74762d2c7
29 changed files with 7717 additions and 8545 deletions

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
};

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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
*********************************************************************************************/

View File

@ -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