#include "StdAfx.h" #include "qualification_final.h" #include "meos_util.h" #include "meosexception.h" #include #include #include "xmlparser.h" pair QualificationFinal::getNextFinal(int instance, int orderPlace, int numSharedPlaceNext) const { pair 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 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 &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 idToIndex; map > 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 vid; split(ids, ",;", vid); vector 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 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()); 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 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 &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; }