// forvingrad.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <windows.h>
#include <cassert>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/system/error_code.hpp>
#include <boost/system/system_error.hpp>
#include <set>
#include <string>
#include <conio.h>
class UserInterface
{
public:
void Write(const std::set<int> packets, int hooligan, int sweep)
{
std::string field(60, ' ');
for (std::set<int>::const_iterator i = packets.begin(); i != packets.end(); ++i)
{
assert(*i > -1);
assert(*i < 60);
field[*i] = 'P';
}
if (sweep != -1)
{
field[sweep] = 'O';
field[sweep + 1] = 'O';
field[sweep + 2] = 'O';
}
if (hooligan != -1)
field[hooligan] = 'X';
std::cout << field << std::endl;
}
};
class Workfield
{
enum
{
position_status,
drop_bag_status,
sweep_status,
hide_status
};
struct PositionEvent : OVERLAPPED
{
int index;
PositionEvent(int ix)
: index(ix)
{
ZeroMemory(this, sizeof(OVERLAPPED));
Offset = position_status;
}
};
struct DropBagEvent : OVERLAPPED
{
DropBagEvent()
{
ZeroMemory(this, sizeof(OVERLAPPED));
Offset = drop_bag_status;
}
};
struct SweepEvent : OVERLAPPED
{
int first;
SweepEvent(int ix)
: first(ix)
{
ZeroMemory(this, sizeof(OVERLAPPED));
Offset = sweep_status;
}
};
struct HideEvent : OVERLAPPED
{
HideEvent()
{
ZeroMemory(this, sizeof(OVERLAPPED));
Offset = hide_status;
}
};
HANDLE cport_;
volatile LONG done_;
public:
enum
{
hooligan_wins = 1,
janitor_wins = 2
};
Workfield()
: cport_(CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 0))
, done_(0)
{
if (!cport_)
{
DWORD last_error = ::GetLastError();
boost::system::system_error e(boost::system::error_code(last_error, boost::system::get_system_category()), __FUNCTION__": CreateCompletionPort failed");
boost::throw_exception(e);
}
}
int IsDone()
{
return InterlockedExchangeAdd(&done_, 0);
}
void Done(int who_wins)
{
InterlockedExchange(&done_, who_wins);
}
void StepTo(int ix)
{
PositionEvent* pos_evt = new PositionEvent(ix);
if(!PostQueuedCompletionStatus(cport_, 0, 0, pos_evt))
{
DWORD last_error = ::GetLastError();
boost::system::system_error e(boost::system::error_code(last_error, boost::system::get_system_category()), __FUNCTION__": PostQueuedCompletionStatus failed");
boost::throw_exception(e);
}
}
void Hide()
{
HideEvent* hide_evt = new HideEvent();
if(!PostQueuedCompletionStatus(cport_, 0, 0, hide_evt))
{
DWORD last_error = ::GetLastError();
boost::system::system_error e(boost::system::error_code(last_error, boost::system::get_system_category()), __FUNCTION__": PostQueuedCompletionStatus failed");
boost::throw_exception(e);
}
}
void Sweep(int first)
{
SweepEvent* sweep_evt = new SweepEvent(first);
if(!PostQueuedCompletionStatus(cport_, 0, 0, sweep_evt))
{
DWORD last_error = ::GetLastError();
boost::system::system_error e(boost::system::error_code(last_error, boost::system::get_system_category()), __FUNCTION__": PostQueuedCompletionStatus failed");
boost::throw_exception(e);
}
}
void DropBag()
{
DropBagEvent* drop_evt = new DropBagEvent();
if(!PostQueuedCompletionStatus(cport_, 0, 0, drop_evt))
{
DWORD last_error = ::GetLastError();
boost::system::system_error e(boost::system::error_code(last_error, boost::system::get_system_category()), __FUNCTION__": PostQueuedCompletionStatus failed");
boost::throw_exception(e);
}
}
void ProcessQueue(UserInterface& ui)
{
OVERLAPPED *event;
ULONG_PTR ck;
DWORD bytes_tr;
std::set<int> packets;
int hooligan_state = -1;
int janitor_state = -1;
while(!IsDone())
{
BOOL res = GetQueuedCompletionStatus(cport_, &bytes_tr, &ck, &event, INFINITE);
if(!res)
{
DWORD last_error = ::GetLastError();
boost::system::system_error e(boost::system::error_code(last_error, boost::system::get_system_category()), __FUNCTION__": GetQueuedCompletionStatus failed");
boost::throw_exception(e);
}
if(event)
{
int type = event->Offset;
switch(type)
{
case position_status:
{
PositionEvent* pos_evt = (PositionEvent*)event;
hooligan_state = pos_evt->index;
delete pos_evt;
}
break;
case drop_bag_status:
{
DropBagEvent* drop_evt = (DropBagEvent*)event;
packets.insert(hooligan_state);
delete drop_evt;
}
break;
case sweep_status:
{
SweepEvent* sweep_evt = (SweepEvent*)event;
janitor_state = sweep_evt->first;
delete sweep_evt;
for(int i = 0; i < 3; ++i)
packets.erase(i + janitor_state);
if(hooligan_state != -1)
{
int dp = hooligan_state - janitor_state;
if (dp < 3 && dp >= 0)
{
//caught
Done(janitor_wins);
}
}
}
break;
case hide_status:
{
HideEvent* hide_evt = (HideEvent*)event;
hooligan_state = -1;
delete hide_evt;
}
break;
default:
throw std::runtime_error(__FUNCTION__"Queue error");
};
ui.Write(packets, hooligan_state, janitor_state);
}
}
}
};
class Hooligan
{
Workfield& field_;
public:
void ThreadProc()
{
for(int i = 0; i < 22; ++i)
{
int pos = rand() % 60;
field_.StepTo(pos);
field_.DropBag();
Sleep(60);
field_.Hide();
Sleep(300);
if(field_.IsDone()) return;
}
field_.Done(Workfield::hooligan_wins);
}
Hooligan(Workfield& f)
: field_(f)
{
}
};
class Janitor
{
Workfield& field_;
public:
void ThreadProc()
{
int i = 0;
for (;"Ever";)
{
for(; i < 20; ++i)
{
Sleep(400);
field_.Sweep(i*3);
if (field_.IsDone()) return;
}
for(;i;--i)
{
Sleep(400);
field_.Sweep(i*3 - 3);
if (field_.IsDone()) return;
}
}
}
Janitor(Workfield& f)
: field_(f)
{
}
};
int main(int argc, char* argv[])
{
srand((unsigned int)time(NULL));
UserInterface ui;
Workfield field;
Hooligan h(field);
Janitor j(field);
boost::thread hthread( boost::bind(&Hooligan::ThreadProc, &h) );
boost::thread jthread( boost::bind(&Janitor::ThreadProc, &j) );
field.ProcessQueue(ui);
hthread.join();
jthread.join();
if(field.IsDone() == Workfield::hooligan_wins)
std::cout << "Hooligan Wins" << std::endl;
else
std::cout << "Janitor Wins" << std::endl;
system("pause");
return 0;
}