299 lines
8.5 KiB
C++
299 lines
8.5 KiB
C++
#include "StdAfx.h"
|
||
|
||
#include "qualification_final.h"
|
||
|
||
#include "meos_util.h"
|
||
#include "meosexception.h"
|
||
#include <set>
|
||
#include <algorithm>
|
||
#include "xmlparser.h"
|
||
|
||
pair<int, int> QualificationFinal::getNextFinal(int instance, int orderPlace, int numSharedPlaceNext) const {
|
||
pair<int, int> key(instance, orderPlace);
|
||
int iter = 0;
|
||
while (numSharedPlaceNext >= 0) {
|
||
auto res = sourcePlaceToFinalOrder.find(key);
|
||
if (res != sourcePlaceToFinalOrder.end()) {
|
||
if (iter >= 2) { // For three in a shared last place
|
||
pair<int, int> key2 = key;
|
||
int extraSub = ((iter + 1) % 2);
|
||
key2.second -= extraSub;
|
||
auto res2 = sourcePlaceToFinalOrder.find(key2);
|
||
if (res2 != sourcePlaceToFinalOrder.end()) {
|
||
auto ans = res2->second;
|
||
ans.second += iter + extraSub;
|
||
return ans;
|
||
}
|
||
}
|
||
|
||
|
||
auto ans = res->second;
|
||
ans.second += iter;
|
||
return ans;
|
||
}
|
||
--key.second;
|
||
--numSharedPlaceNext;
|
||
++iter;
|
||
}
|
||
|
||
return make_pair(0, -1);
|
||
}
|
||
|
||
bool QualificationFinal::noQualification(int instance) const {
|
||
if (size_t(instance) >= classDefinition.size())
|
||
return false;
|
||
|
||
return classDefinition[instance].qualificationMap.empty() &&
|
||
classDefinition[instance].timeQualifications.empty();
|
||
}
|
||
|
||
|
||
void QualificationFinal::getBaseClassInstances(set<int> &base) const {
|
||
for (size_t k = 0; k < classDefinition.size(); k++) {
|
||
if (noQualification(k))
|
||
base.insert(k+1);
|
||
else break;
|
||
}
|
||
|
||
}
|
||
|
||
void QualificationFinal::import(const wstring &file) {
|
||
xmlparser xml;
|
||
xml.read(file);
|
||
|
||
auto qr = xml.getObject("QualificationRules");
|
||
xmlList levels;
|
||
qr.getObjects("Level", levels);
|
||
map<int, int> idToIndex;
|
||
map<int, set<int> > qualificationRelations;
|
||
int numBaseLevels = 0;
|
||
int iLevel = 0;
|
||
for (size_t iLevel = 0; iLevel < levels.size(); iLevel++) {
|
||
auto &level = levels[iLevel];
|
||
xmlList classes;
|
||
level.getObjects("Class", classes);
|
||
for (auto &cls : classes) {
|
||
wstring name;
|
||
cls.getObjectString("Name", name);
|
||
if (name.empty())
|
||
throw meosException("Klassen m<>ste ha ett namn.");
|
||
int classId = cls.getObjectInt("id");
|
||
if (!(classId>0))
|
||
throw meosException("Id must be a positive integer.");
|
||
if (idToIndex.count(classId))
|
||
throw meosException("Duplicate class with id " + itos(classId));
|
||
|
||
xmlList rules;
|
||
cls.getObjects("Qualification", rules);
|
||
if (rules.empty())
|
||
numBaseLevels = 1; // Instance zero is not used as qualification,
|
||
|
||
idToIndex[classId] = classDefinition.size() + numBaseLevels;
|
||
classDefinition.push_back(Class());
|
||
classDefinition.back().name = name;
|
||
|
||
for (auto &qf : rules) {
|
||
int place = qf.getObjectInt("place");
|
||
if (place > 0) {
|
||
int id = qf.getObjectInt("id");
|
||
if (id == 0 && iLevel == 0)
|
||
classDefinition.back().qualificationMap.push_back(make_pair(0, place));
|
||
else if (idToIndex.count(id)) {
|
||
classDefinition.back().qualificationMap.push_back(make_pair(idToIndex[id], place));
|
||
qualificationRelations[classId].insert(id);
|
||
}
|
||
else
|
||
throw meosException("Unknown class with id " + itos(id));
|
||
}
|
||
else {
|
||
string time;
|
||
qf.getObjectString("place", time);
|
||
if (time == "time") {
|
||
string ids;
|
||
qf.getObjectString("id", ids);
|
||
vector<string> vid;
|
||
split(ids, ",;", vid);
|
||
vector<int> ivid;
|
||
for (auto &s : vid) {
|
||
int i = atoi(s.c_str());
|
||
if (!idToIndex.count(i))
|
||
throw meosException("Unknown class with id " + itos(i));
|
||
ivid.push_back(idToIndex[i]);
|
||
}
|
||
|
||
if (ivid.empty())
|
||
throw meosException(L"Empty time qualification for " + name);
|
||
classDefinition.back().timeQualifications.push_back(ivid);
|
||
}
|
||
else throw meosException("Unknown classification rule " + time);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
/*classDefinition.resize(3);
|
||
classDefinition[0].name = L"Semi A";
|
||
classDefinition[1].name = L"Semi B";
|
||
classDefinition[2].name = L"Final";
|
||
|
||
for (int i = 0; i < 4; i++) {
|
||
classDefinition[0].qualificationMap.push_back(make_pair(0, i * 2 + 1));
|
||
classDefinition[1].qualificationMap.push_back(make_pair(0, i * 2 + 2));
|
||
classDefinition[2].qualificationMap.push_back(make_pair(i%2+1, i/2 + 1));
|
||
}
|
||
*/
|
||
initgmap(true);
|
||
}
|
||
|
||
void QualificationFinal::init(const wstring &def) {
|
||
vector <wstring> races, rtdef, rdef;
|
||
split(def, L"|", races);
|
||
classDefinition.resize(races.size());
|
||
bool valid = true;
|
||
bool first = true;
|
||
for (size_t k = 0; k < races.size(); k++) {
|
||
split(races[k], L"T", rtdef);
|
||
classDefinition[k].qualificationMap.clear();
|
||
classDefinition[k].timeQualifications.clear();
|
||
|
||
if (first && rtdef.empty())
|
||
continue;
|
||
|
||
valid = rtdef.size() > 0;
|
||
if (!valid)
|
||
break;
|
||
first = false;
|
||
|
||
split(rtdef[0], L";", rdef);
|
||
valid = rdef.size() > 0 && rdef.size()%2 == 0;
|
||
if (!valid)
|
||
break;
|
||
|
||
for (size_t j = 0; j < rdef.size(); j+=2) {
|
||
size_t src = _wtoi(rdef[j].c_str());
|
||
if (src > k) {
|
||
valid = false;
|
||
break;
|
||
}
|
||
const wstring &rd = rdef[j + 1];
|
||
size_t d1 = _wtoi(rd.c_str());
|
||
size_t d2 = d1;
|
||
size_t range = rd.find_first_of('-', 0);
|
||
if (range < rd.size())
|
||
d2 = _wtoi(rd.c_str()+range+1);
|
||
|
||
if (d1 > d2) {
|
||
valid = false;
|
||
break;
|
||
}
|
||
|
||
while (d1 <= d2) {
|
||
classDefinition[k].qualificationMap.push_back(make_pair(int(src), int(d1)));
|
||
d1++;
|
||
}
|
||
}
|
||
|
||
for (size_t i = 1; valid && i < rtdef.size(); i++) {
|
||
split(rtdef[i], L";", rdef);
|
||
classDefinition[k].timeQualifications.push_back(vector<int>());
|
||
for (size_t j = 0; valid && j < rdef.size(); j += 2) {
|
||
size_t src = _wtoi(rdef[j].c_str());
|
||
if (src > k) {
|
||
valid = false;
|
||
break;
|
||
}
|
||
classDefinition[k].timeQualifications.back().push_back(src);
|
||
}
|
||
}
|
||
}
|
||
|
||
if (!valid)
|
||
classDefinition.clear();
|
||
|
||
initgmap(false);
|
||
}
|
||
|
||
void QualificationFinal::encode(wstring &output) const {
|
||
output.clear();
|
||
|
||
for (size_t k = 0; k < classDefinition.size(); k++) {
|
||
if (k > 0)
|
||
output.append(L"|");
|
||
|
||
auto &qm = classDefinition[k].qualificationMap;
|
||
|
||
for (size_t j = 0; j < qm.size(); j++) {
|
||
if (j > 0)
|
||
output.append(L";");
|
||
|
||
size_t i = j;
|
||
while ((i + 1) < qm.size() && qm[i + 1].first == qm[i].first
|
||
&& qm[i + 1].second == qm[i].second+1) {
|
||
i++;
|
||
}
|
||
output.append(itow(qm[j].first) + L";");
|
||
if (i <= j + 1) {
|
||
output.append(itow(qm[j].second));
|
||
}
|
||
else {
|
||
output.append(itow(qm[j].second) + L"-" + itow(qm[i].second));
|
||
j = i;
|
||
}
|
||
}
|
||
|
||
auto &tqm = classDefinition[k].timeQualifications;
|
||
for (auto &source : tqm) {
|
||
output.append(L"T");
|
||
for (size_t i = 0; i < source.size(); i++) {
|
||
if (i > 0)
|
||
output.append(L";");
|
||
output.append(itow(source[i]));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
int QualificationFinal::getNumStages(int stage) const {
|
||
if (stage == 0 || classDefinition[stage-1].qualificationMap.empty())
|
||
return 1;
|
||
|
||
set<int> races;
|
||
for (auto &qm : classDefinition[stage - 1].qualificationMap) {
|
||
if (qm.first == stage)
|
||
throw meosException("Invalid qualification scheme");
|
||
races.insert(qm.first);
|
||
}
|
||
|
||
int def = 0;
|
||
for (int r : races)
|
||
def = max(def, 1 + getNumStages(r));
|
||
|
||
return def;
|
||
}
|
||
|
||
void QualificationFinal::initgmap(bool check) {
|
||
sourcePlaceToFinalOrder.clear();
|
||
|
||
for (int ix = 0; ix < (int)classDefinition.size(); ix++) {
|
||
auto &c = classDefinition[ix];
|
||
|
||
for (int k = 0; k < (int)c.qualificationMap.size(); k++) {
|
||
const pair<int, int> &sd = c.qualificationMap[k];
|
||
if (check && sourcePlaceToFinalOrder.count(sd))
|
||
throw meosException(L"Inconsistent qualification rule, X#" + c.name + + L"/" + itow(sd.first));
|
||
|
||
sourcePlaceToFinalOrder[sd] = make_pair(ix+1, k);
|
||
}
|
||
}
|
||
}
|
||
|
||
int QualificationFinal::getHeatFromClass(int finalClassId, int baseClassId) const {
|
||
if (baseClassId == baseId) {
|
||
int fci = (finalClassId - baseId) / maxClassId;
|
||
|
||
if (fci * maxClassId + baseClassId == finalClassId)
|
||
return fci;
|
||
}
|
||
|
||
return 0;
|
||
}
|