#include <iostream>
#include <string>
#include <list>
#include <vector>
#include <random>
#include <algorithm>
using namespace std;
enum eJob
{
eVillager = 1, // 마을사람
eSeer = 2, // 점쟁이
eMedium = 4, // 영매자
eGuard = 8, // 사냥꾼
eFreemasons = 16, // 초능
eWerewolf = 32, // 인랑
ePossessed = 64, // 광인
};
struct ObjDelete
{
template <typename T>
void operator () (T& Temp)
{
if (Temp)
{
delete Temp;
Temp = nullptr;
}
}
};
enum eMaxApply
{
eFirst,
eSecond,
eMaxApplyEnd
};
struct tagApply
{
int iApply;
int iWeight;
int iCoin;
tagApply() : iApply(0), iWeight(0), iCoin(0) {}
};
class CMentor
{
private:
string m_szMyName;
tagApply m_tApply[eMaxApplyEnd];
string m_szMenteeName;
private:
static bool m_bFreemasons; // 초능이 있는지 없는지
private:
static int countBit(int value);
public:
const string& GetMyName() { return m_szMyName; }
const tagApply& GetApply(eMaxApply _eType) { return m_tApply[_eType]; }
const string& GetMenteeName() { return m_szMenteeName; }
bool SetApply(const int _iJob, eMaxApply _eType);
void SetMenteeName(const string& _szName) { m_szMenteeName = _szName; }
public:
void static SetFreemason(bool _bFreemason) { m_bFreemasons = _bFreemason; }
public:
CMentor(const string& _szName, int _FirstJob = 0, int _SecondJob = 0);
~CMentor();
};
bool CMentor::m_bFreemasons = false;
CMentor::CMentor(const string& _szName, int _FirstJob /*= 0*/, int _SecondJob /*= 0*/)
: m_szMyName(_szName)
, m_szMenteeName("None")
{
if (_FirstJob)
SetApply(_FirstJob, eFirst);
if (_SecondJob)
SetApply(_SecondJob, eSecond);
}
CMentor::~CMentor()
{
}
bool CMentor::SetApply(const int _iJob, eMaxApply _eType)
{
// 2017/01/16 Moo : 초능이 없는 마을에서 초능 지원하면 뺌
if (m_bFreemasons == true)
{
m_tApply[_eType].iApply = _iJob & ~eFreemasons;
}
else
m_tApply[_eType].iApply = _iJob;
m_tApply[_eType].iWeight = countBit(_iJob);
// 2017/01/16 Moo : 100의 코인값을 비중으로 나눈다.
m_tApply[_eType].iCoin = 100 / m_tApply[_eType].iWeight;
return true;
}
int CMentor::countBit(int value)
{
int count = 0;
while (value)
{
count += (value & 1);
value = value >> 1;
}
return count;
}
struct tagMentee
{
string szMyName;
eJob eMyJob;
string szMentorName;
};
struct tagRandom
{
int iValue;
string szMentorName;
tagRandom(const int& _value, const string& _szName) : iValue(_value), szMentorName(_szName)
{}
};
class CMentor;
class CMenMenMgr
{
private:
static CMenMenMgr* m_pInst;
public:
static inline CMenMenMgr* GetInst()
{
if (m_pInst == nullptr)
m_pInst = new CMenMenMgr;
return m_pInst;
}
void inline Destroy()
{
if (m_pInst)
{
delete m_pInst;
m_pInst = nullptr;
}
}
private:
vector<CMentor*> m_vecReadyMentor;
vector<CMentor*> m_vecCompleteMentor;
vector<tagMentee*> m_vecReadyMentee;
vector<tagMentee*> m_vecCompleteMentee;
vector<tagRandom> m_vecRandom;
public:
bool Init();
void PreRender();
void Matching();
void Render();
private:
eJob GetMyJob(string _strJob);
string GetMyJob(const eJob _ejob);
private:
CMenMenMgr();
~CMenMenMgr();
};
int g_iSeed = 19880429;
int g_iSeed_second = 26;
CMenMenMgr* CMenMenMgr::m_pInst = nullptr;
string g_Mentee[15][2] =
{
{ "ㅇㅁㅈ", "인랑" },
{ "기다린", "인랑" },
{ "반월", "광인" },
{ "taewan", "초능력자" },
{ "닥터", "점쟁이" },
{ "맬리", "영매자" },
{ "piece", "사냥꾼" },
{ "지나가던 정신병자", "초능력자" },
{ "어린씨앗", "마을사람" },
{ "네르", "마을사람" },
{ "프리지아", "마을사람" },
{ "뤼넨", "마을사람" },
{ "짜장면", "마을사람" },
};
CMentor g_Mentor[] =
{
CMentor("필그림", eVillager, eFreemasons),
CMentor("믹형", eWerewolf, ePossessed),
CMentor("암흑시대", eFreemasons, eVillager),
CMentor("bandy", eVillager),
CMentor("빵글이", ePossessed, eWerewolf),
CMentor("아카유키", eGuard),
CMentor("앙팡", eGuard | eWerewolf | eFreemasons),
CMentor("루이", eVillager | eGuard | eFreemasons),
CMentor("자칼린", eVillager),
CMentor("월광", eWerewolf),
CMentor("크레센트", eWerewolf, eVillager),
CMentor("Splitmilk", eVillager | eGuard, eMedium),
CMentor("졸린개")
};
CMenMenMgr::CMenMenMgr()
{
}
CMenMenMgr::~CMenMenMgr()
{
for_each(m_vecReadyMentee.begin(), m_vecReadyMentee.end(), ObjDelete());
m_vecReadyMentee.clear();
for_each(m_vecReadyMentor.begin(), m_vecReadyMentor.end(), ObjDelete());
m_vecReadyMentor.clear();
for_each(m_vecCompleteMentee.begin(), m_vecCompleteMentee.end(), ObjDelete());
m_vecCompleteMentee.clear();
for_each(m_vecCompleteMentor.begin(), m_vecCompleteMentor.end(), ObjDelete());
m_vecCompleteMentor.clear();
}
bool CMenMenMgr::Init()
{
default_random_engine generator(g_iSeed);
for (int i = 0; i < 15; ++i)
{
if (g_Mentee[i][0] == "")
break;
tagMentee* pMentee = new tagMentee;
pMentee->szMyName = g_Mentee[i][0];
pMentee->eMyJob = GetMyJob(g_Mentee[i][1]);
m_vecReadyMentee.push_back(pMentee);
}
shuffle(m_vecReadyMentee.begin(), m_vecReadyMentee.end(), generator);
for (auto var : g_Mentor)
{
CMentor *pMentor = new CMentor(var);
m_vecReadyMentor.push_back(pMentor);
}
shuffle(m_vecReadyMentor.begin(), m_vecReadyMentor.end(), generator);
return true;
}
void CMenMenMgr::PreRender()
{
cout << "======ReadyMentee======" << endl;
for (auto var : m_vecReadyMentee)
{
cout << var->szMyName << "\t\t" << GetMyJob(var->eMyJob) << endl;
}
cout << "=================" << endl;
cout << "======ReadyMentor======" << endl;
for (auto var : m_vecReadyMentor)
{
cout << var->GetMyName() << "\t\t" << endl;
}
cout << "=================" << endl;
}
void CMenMenMgr::Matching()
{
default_random_engine generator(g_iSeed_second);
cout << "===============Matching===============" << endl;
for (int eCount = eFirst; eCount < eMaxApplyEnd; ++eCount)
{
for (auto Mentee = m_vecReadyMentee.begin(); Mentee != m_vecReadyMentee.end();)
{
m_vecRandom.clear();
int iCurrentCoin = 0;
eJob MenteeJob = (*Mentee)->eMyJob;
for (auto Mentor : m_vecReadyMentor)
{
// 2017/01/19 Moo : 밴...
if (Mentor->GetMyName() == "빵글이")
{
if ((*Mentee)->szMyName == "반월")
continue;
}
// 2017/01/17 Moo : 해당한다면 넣는다
if (Mentor->GetApply(eMaxApply(eCount)).iApply & MenteeJob)
{
tagRandom tempRandom(iCurrentCoin + Mentor->GetApply(eMaxApply(eCount)).iCoin, Mentor->GetMyName());
iCurrentCoin += Mentor->GetApply(eMaxApply(eCount)).iCoin;
m_vecRandom.push_back(tempRandom);
}
}
if (iCurrentCoin == 0)
{
++Mentee;
continue;
}
// 2017/01/17 Moo : 다 넣음.
int iRandom = generator() % iCurrentCoin;
string TargetString = "";
for (auto Random : m_vecRandom)
{
if (Random.iValue > iRandom)
{
TargetString = Random.szMentorName;
break;
}
}
if (TargetString != "")
{
(*Mentee)->szMentorName = TargetString;
for (auto iter = m_vecReadyMentor.begin(); iter != m_vecReadyMentor.end(); ++iter)
{
if ((*iter)->GetMyName() == TargetString)
{
(*iter)->SetMenteeName((*Mentee)->szMyName);
m_vecCompleteMentor.push_back(*iter);
m_vecReadyMentor.erase(iter);
break;
}
}
m_vecCompleteMentee.push_back(*Mentee);
Mentee = m_vecReadyMentee.erase(Mentee);
}
else
{
++Mentee;
}
}
}
// 2017/01/20 Moo : 다시 섞음
shuffle(m_vecReadyMentee.begin(), m_vecReadyMentee.end(), generator);
shuffle(m_vecReadyMentor.begin(), m_vecReadyMentor.end(), generator);
for (auto Mentee = m_vecReadyMentee.begin(); Mentee != m_vecReadyMentee.end();)
{
(*Mentee)->szMentorName = (m_vecReadyMentor[0])->GetMyName();
(m_vecReadyMentor[0])->SetMenteeName((*Mentee)->szMyName);
m_vecCompleteMentee.push_back(*Mentee);
m_vecCompleteMentor.push_back(m_vecReadyMentor[0]);
Mentee = m_vecReadyMentee.erase(Mentee);
m_vecReadyMentor.erase(m_vecReadyMentor.begin());
}
}
void CMenMenMgr::Render()
{
cout << "======CompleteMentee======" << endl;
for (auto var : m_vecCompleteMentee)
{
cout << var->szMyName << "\t\t" << GetMyJob(var->eMyJob) << "\t\t" << var->szMentorName << endl;
}
cout << "=================" << endl;
cout << "======CompleteMentor======" << endl;
for (auto var : m_vecCompleteMentor)
{
cout << var->GetMyName() << "\t\t" << var->GetMenteeName() << endl;
}
cout << "=================" << endl;
}
eJob CMenMenMgr::GetMyJob(string _strJob)
{
if (_strJob == "마을사람")
return eVillager;
else if (_strJob == "점쟁이")
return eSeer;
else if (_strJob == "영매자")
return eMedium;
else if (_strJob == "사냥꾼")
return eGuard;
else if (_strJob == "초능력자")
{
CMentor::SetFreemason(true);
return eFreemasons;
}
else if (_strJob == "인랑")
return eWerewolf;
else if (_strJob == "광인")
return ePossessed;
cout << "Error!" << endl;
return eVillager;
}
string CMenMenMgr::GetMyJob(const eJob _ejob)
{
string strName;
if (_ejob == eVillager)
strName = "마을사람";
else if (_ejob == eSeer)
strName = "점쟁이";
else if (_ejob == eMedium)
strName = "영매자";
else if (_ejob == eGuard)
strName = "사냥꾼";
else if (_ejob == eFreemasons)
strName = "초능력자";
else if (_ejob == eWerewolf)
strName = "인랑";
else if (_ejob == ePossessed)
strName = "광인";
return strName;
}
int main() {
// your code goes here
CMenMenMgr::GetInst()->Init();
CMenMenMgr::GetInst()->PreRender();
CMenMenMgr::GetInst()->Matching();
CMenMenMgr::GetInst()->PreRender();
CMenMenMgr::GetInst()->Render();
CMenMenMgr::GetInst()->Destroy();
return 0;
}