#include <time.h>
#include <limits.h>
#include <cstdio>
#include "othello.h"
#include "minimax.h"
#include <windows.h>
#include "workqueue.h"
#include "ConditionVarible.h"
const float max_time = 9.9f;
WorkQueue mWork;
ConditionVarible restart;
HANDLE* threads = 0;
DWORD ThreadCount = 0;
unsigned int _stdcall
do_minimax_parallel(void* param)
{
#pragma warning(push)
#pragma warning(disable: 4311)
unsigned int threadID = reinterpret_cast<unsigned int>(param);
#pragma warning(pop)
mWork.AddThread(threadID);
do
{
Work work;
int level;
EnterCriticalSection(mWork.getQueueAccessLock());
do
{
level = mWork.Pop(&work);
if (work.valid == Work::VAL_Sicken)
restart.Wait(mWork.getQueueAccessLock());
else if (work.valid == Work::VAL_Kill)
{
LeaveCriticalSection(mWork.getQueueAccessLock());
return 0;
}
} while (work.valid != Work::VAL_Food);
LeaveCriticalSection(mWork.getQueueAccessLock());
if (work.original_board.full())
continue;
othello::move_iterator iter = work.original_board.get_available_moves(work.player);
if (work.base_move.col != 255)
mWork.UpdateMove(level, evaluate_board(work.original_board, iter, work.basePlayer), (work.player == work.basePlayer), work.base_move);
else
mWork.UpdateMove(level, evaluate_board(work.original_board, iter, work.basePlayer), (work.player == work.basePlayer), iter.get());
if (!iter.valid()) {
if (work.last_was_empty)
continue;
else
mWork.Push(Work(work.original_board, work.base_move, 1 - work.player, work.basePlayer, true), level + 1);
}
while (iter.valid()) {
const othello::move this_move = iter.get();
othello::board updated_board(work.original_board);
updated_board.place_piece(this_move, work.player);
if (work.base_move.col < 255)
mWork.Push(Work(updated_board, work.base_move, 1 - work.player, work.basePlayer, false), level + 1);
else
mWork.Push(Work(updated_board, this_move, 1 - work.player, work.basePlayer, false), level + 1);
iter.next();
if (mWork.checkPoison())
break;
}
} while (true);
return 1;
}
void exitMinimax()
{
mWork.Poison(Work::VAL_Kill);
DWORD err = WaitForMultipleObjects(ThreadCount, threads, TRUE, INFINITE);
if (err != 0)
{
DWORD num = GetLastError();
printf("WaitForMultipleObjects() returned with error #%i.\n", num);
}
delete [] threads;
}
void get_move_parallel(const othello::board &b, unsigned player,
struct othello::move &m)
{
clock_t before[2];
clock_t after;
clock_t elapsed;
float seconds;
before[0] = clock();
printf("\n\nClearing Old Data.\n");
mWork.Clear();
before[1] = clock();
othello::move tMove;
tMove.col = ~0;
tMove.row = ~0;
mWork.Push(Work(b, tMove, player, player, false), 0);
if (threads == 0)
{
{
SYSTEM_INFO info;
GetSystemInfo(&info);
ThreadCount = info.dwNumberOfProcessors;
printf("Using %i worker threads.\n", ThreadCount);
}
mWork.setThreadCount(ThreadCount);
threads = new HANDLE[ThreadCount];
#pragma warning(push)
#pragma warning(disable: 4312)
for (unsigned int x = 0; x < ThreadCount; x++)
threads[x] = HANDLE(_beginthreadex(0, 0, do_minimax_parallel, reinterpret_cast<void*>(x), 0, 0));
#pragma warning(pop)
}
else
{
printf("Beginning.\n");
restart.Broadcast();
}
do
{
Sleep(100);
after = clock();
elapsed = after - before[0];
seconds = float(elapsed) / float(CLOCKS_PER_SEC);
} while ((seconds <= max_time) && (!mWork.isPoisoned()));
printf("Poisoning.\n");
mWork.Poison();
printf("Poisoned.\n");
printf("Got to level: %u\n", mWork.getBaseLevel());
m = mWork.GetBestMove();
after = clock();
elapsed = after - before[0];
seconds = float(elapsed) / float(CLOCKS_PER_SEC);
printf("%.2f seconds from before clear\n", seconds);
elapsed = after - before[1];
seconds = float(elapsed) / float(CLOCKS_PER_SEC);
printf("%.2f seconds from after clear\n\n", seconds);
}