From 77f8836508a4c28c7c6c1352ff891c5d36d00237 Mon Sep 17 00:00:00 2001 From: Steru Date: Sun, 4 Aug 2024 22:56:15 +0200 Subject: Added method to get medal winners. Adjusted sort result method to also work with the medal winners. --- src/api/OlympicsAPI.cpp | 28 ++++----- src/discipline/Sport.cpp | 144 +++++++++++++++++++++++++++++++++++++++++++---- src/discipline/Sport.h | 22 ++++++-- 3 files changed, 164 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/api/OlympicsAPI.cpp b/src/api/OlympicsAPI.cpp index 4fe9701..0334800 100644 --- a/src/api/OlympicsAPI.cpp +++ b/src/api/OlympicsAPI.cpp @@ -121,20 +121,20 @@ string OlympicsAPI::getDisciplineShort(OlympicsAPI::Disciplines sport) { case OlympicsAPI::Disciplines::ModernPentathlon: return "MPN"; case OlympicsAPI::Disciplines::Rowing: return "ROW"; case OlympicsAPI::Disciplines::Rugby7: return "RU7"; - case OlympicsAPI::Disciplines::Sailing: return "SAL"; break; - case OlympicsAPI::Disciplines::Shooting: return "SHO"; break; - case OlympicsAPI::Disciplines::Skateboarding: return "SKB"; break; - case OlympicsAPI::Disciplines::SportClimbing: return "CLB"; break; - case OlympicsAPI::Disciplines::Surfing: return "SRF"; break; - case OlympicsAPI::Disciplines::TableTennis: return "TTE"; break; - case OlympicsAPI::Disciplines::Taekwondo: return "TKW"; break; - case OlympicsAPI::Disciplines::Tennis: return "TEN"; break; - case OlympicsAPI::Disciplines::Triathlon: return "TRI"; break; - case OlympicsAPI::Disciplines::VolleyballBeach: return "VBV"; break; - case OlympicsAPI::Disciplines::VolleyballIndoor: return "VVO"; break; - case OlympicsAPI::Disciplines::Weightlifting: return "WLF"; break; - case OlympicsAPI::Disciplines::WrestlingFreestyle: return "WRE"; break; - case OlympicsAPI::Disciplines::WrestlingGrecoRoman: return "WRG"; break; + case OlympicsAPI::Disciplines::Sailing: return "SAL"; + case OlympicsAPI::Disciplines::Shooting: return "SHO"; + case OlympicsAPI::Disciplines::Skateboarding: return "SKB"; + case OlympicsAPI::Disciplines::SportClimbing: return "CLB"; + case OlympicsAPI::Disciplines::Surfing: return "SRF"; + case OlympicsAPI::Disciplines::TableTennis: return "TTE"; + case OlympicsAPI::Disciplines::Taekwondo: return "TKW"; + case OlympicsAPI::Disciplines::Tennis: return "TEN"; + case OlympicsAPI::Disciplines::Triathlon: return "TRI"; + case OlympicsAPI::Disciplines::VolleyballBeach: return "VBV"; + case OlympicsAPI::Disciplines::VolleyballIndoor: return "VVO"; + case OlympicsAPI::Disciplines::Weightlifting: return "WLF"; + case OlympicsAPI::Disciplines::WrestlingFreestyle: return "WRE"; + case OlympicsAPI::Disciplines::WrestlingGrecoRoman: return "WRG"; default: return "ARC"; // default, which should not be possible, because of enum } } diff --git a/src/discipline/Sport.cpp b/src/discipline/Sport.cpp index 42e82aa..1ea8019 100644 --- a/src/discipline/Sport.cpp +++ b/src/discipline/Sport.cpp @@ -1,6 +1,7 @@ #include "Sport.h" #include +#include #include #include @@ -8,6 +9,21 @@ #include #include #include +#include + +// QJsonArray filter function, provide with input array and evaluation function +QJsonArray filter(QJsonArray input, function eval) { + QJsonArray output; + + for (const QJsonValueRef &elemRef :input) { + QJsonObject elem = elemRef.toObject(); + if(eval(elem)) { + output.append(elem); + } + } + + return output; +} // static compare function for specific attribute in competitors function genCompare(QString attribute) { @@ -20,21 +36,44 @@ function genCompare(QStr // static compare function for the results of a competitor in a specific competition (also called mark) bool compareMark(const QJsonValue &left, const QJsonValue &right) { + // check if one competitor has no mark QJsonObject l = left.toObject(); if (!l.contains("results")) return true; QJsonObject r = right.toObject(); if (!r.contains("results")) return false; - float lMark = l["results"].toObject()["mark"].toString().toFloat(); - float rMark = r["results"].toObject()["mark"].toString().toFloat(); - return lMark < rMark; + QString lMark = l["results"].toObject()["mark"].toString(); + QString rMark = r["results"].toObject()["mark"].toString(); + + // check if the marks are numerical values + if (!lMark.contains(":") && !rMark.contains(":")) return lMark.toFloat() < rMark.toFloat(); + + // compare time values if not numerical + QString lTime(""), rTime(""); + + for (QChar c : lMark) if (c.isDigit()) lTime.append(c); + for (QChar c : rMark) if (c.isDigit()) rTime.append(c); + + return lTime.compare(rTime) < 0; +} + +// static compare function for the amount of medals a competitor has gotten +bool compareMedals(const QJsonValue &left, const QJsonValue &right) { + QJsonObject lMedals = left.toObject()["medals"].toObject(); + QJsonObject rMedals = right.toObject()["medals"].toObject(); + + int gold = lMedals["ME_GOLD"].toInt() - rMedals["ME_GOLD"].toInt(); + int silver = lMedals["ME_SILVER"].toInt() - rMedals["ME_SILVER"].toInt(); + int bronze = lMedals["ME_BRONZE"].toInt() - rMedals["ME_BRONZE"].toInt(); + + return gold < 0 || (gold == 0 && (silver < 0 || (silver == 0 && bronze < 0))); } /** * @brief Sport::lastName Reduce the full name to the part that is marked in capital letters (probably last name). * @param competitors The competitors of one category. */ -void Sport::lastName(QJsonArray& competitors) { +void Sport::lastName(QJsonArray &competitors) { for (int i = 0; i < competitors.size(); ++i) { string fullName = competitors[i].toObject()["name"].toString().toUtf8().constData(); @@ -64,7 +103,7 @@ void Sport::lastName(QJsonArray& competitors) { set Sport::getCategories() { set categoryNames; - for (const QJsonValueRef& unit : this->discipline["units"].toArray()) { + for (const QJsonValueRef &unit : this->discipline["units"].toArray()) { categoryNames.insert(unit.toObject()["eventUnitName"].toString()); } @@ -79,21 +118,97 @@ set Sport::getCategories() { QJsonArray Sport::getCompetitorsByCategory(QString category) { QJsonArray competitors; - for (const QJsonValueRef& unitRef : this->discipline["units"].toArray()) { + for (const QJsonValueRef &unitRef : this->discipline["units"].toArray()) { QJsonObject unit = unitRef.toObject(); // search all units with the same category - if (QString::compare(unit["eventUnitName"].toString(), category, Qt::CaseSensitive) == 0) { + if (unit["eventUnitName"].toString().compare(category, Qt::CaseSensitive) != 0) continue; + + // add all competitors from one unit + for (const QJsonValueRef &comp : unit["competitors"].toArray()) { + competitors.push_back(comp.toObject()); + } + } + + return QJsonArray(competitors); +} + +/** + * @brief Sport::getCompetitorsWithMedal Filters all competitors, who have at least one medal. These objects are different from getCompetitorsByCategory !!! + * @return All competitors, who won at least one medal. Structure of one competitor: {code, name, noc, medals{ME_GOLD, ME_SILVER, ME_BRONZE}} + */ + +QJsonArray Sport::getCompetitorsWithMedal() { + map competitors; + + // filter all units, which have medal events + QJsonArray units = filter(this->discipline["units"].toArray(), [](QJsonObject unit){ + // search all units with Final, Gold or Bronze in their name, because these are the categories with the medal winners + QString unitName = unit["eventUnitName"].toString(); + return unitName.contains("Bronze", Qt::CaseSensitive) + || unitName.contains("Gold", Qt::CaseSensitive) + || unitName.contains("Final", Qt::CaseSensitive); + }); + + for (const QJsonValueRef &unitRef : units) { + QJsonObject unit = unitRef.toObject(); + + // filter all competitors, who won medals + QJsonArray medalComps = filter(unit["competitors"].toArray(), [](QJsonObject comp) { + if (!comp.contains("results")) return false; - // add all competitors from one unit - for (const QJsonValueRef& comp : unit["competitors"].toArray()) { - competitors.push_back(comp.toObject()); + QString medalType = comp["results"].toObject()["medalType"].toString(); + return !medalType.isEmpty(); + }); + + for (const QJsonValueRef &medalCompRef : medalComps) { + QJsonObject medalComp = medalCompRef.toObject(); + + QString name = medalComp["name"].toString(); + QString medalType = medalComp["results"].toObject()["medalType"].toString(); + + // check if competitor has other medal(s) + if (competitors.find(name) == competitors.end()) { + competitors.insert({name, createCompetitorWithMedals(medalComp)}); } + // update the medal count + QJsonObject updatedMedalCount = QJsonObject(competitors.find(name)->second["medals"].toObject()); + + int amount = updatedMedalCount[medalType].toInt() + 1; + updatedMedalCount.remove(medalType); + updatedMedalCount.insert(medalType, amount); + + // create new medals QJsonObject and set it in the map + competitors.find(name)->second["medals"] = updatedMedalCount; } } - return QJsonArray(competitors); + // convert map to QJsonArray + QJsonArray output; + for (const pair &competitor : competitors) { + output.append(competitor.second); + } + + return output; +} + +QJsonObject Sport::createCompetitorWithMedals(QJsonObject comp) { + // create new competitor QJsonObject and add it to the competitor map + QJsonObject medals { + {"ME_GOLD", 0}, + {"ME_SILVER", 0}, + {"ME_BRONZE", 0} + }; + + QJsonObject medalComp { + {"code", comp["code"].toString()}, + {"name", comp["name"].toString()}, + {"noc", comp["noc"].toString()}, + {"medals", medals} + }; + + return medalComp; } /** @@ -147,7 +262,12 @@ void Sport::sortByCountry(QJsonArray &competitors) { * @param competitors The competitors of one category. */ void Sport::sortByResult(QJsonArray &competitors) { - sortCompetitors(competitors, compareMark); + if (competitors.isEmpty()) return; + + QJsonObject comp = competitors[0].toObject(); + + if (comp.contains("results")) sortCompetitors(competitors, compareMark); + else if (comp.contains("medals")) sortCompetitors(competitors, compareMedals); } void Sport::sortCompetitors(QJsonArray &competitors, function compare) { diff --git a/src/discipline/Sport.h b/src/discipline/Sport.h index 78968fe..9156b82 100644 --- a/src/discipline/Sport.h +++ b/src/discipline/Sport.h @@ -22,11 +22,12 @@ public: set getCategories(); QJsonArray getCompetitorsByCategory(QString category); + QJsonArray getCompetitorsWithMedal(); // filter to change the current competitor array - void lastName(QJsonArray& competitors); - void filterByName(QJsonArray& competitors, QString name); - void filterByCountry(QJsonArray& competitors, QString nocShort); + void lastName(QJsonArray &competitors); + void filterByName(QJsonArray &competitors, QString name); + void filterByCountry(QJsonArray &competitors, QString nocShort); // sort functions to change the order of the current competitor array void sortByName(QJsonArray &competitors); @@ -58,11 +59,24 @@ private: * - medalType * - irk * [- winnerLoserTie] (only if provided in the discipline?) + * + * Analysis of where to find the medal winners: + * + * Search for ... in category name. + * - "Bronze" + * - "Gold" + * - "Final" + * + * ! ATTENTION ! + * When searching for "Final" there might be "Final A", "Final B", etc. + * The results will only be in ONE of these categories! + * -> which is good... cause then we can count occurences. */ QJsonObject discipline; - void filterCompetitors(QJsonArray& competitors, QString attribute, QString filter); + void filterCompetitors(QJsonArray &competitors, QString attribute, QString filter); void sortCompetitors(QJsonArray &competitors, function compare); + QJsonObject createCompetitorWithMedals(QJsonObject medalComp); }; -- cgit v1.2.3