299 lines
8.6 KiB
C++
299 lines
8.6 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;
|
|
}
|