meos-2024/code/qualification_final.cpp
2018-05-23 21:50:19 +02:00

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;
}