diff options
Diffstat (limited to 'src/discipline')
| -rw-r--r-- | src/discipline/Sport.cpp | 423 | ||||
| -rw-r--r-- | src/discipline/Sport.h | 92 | 
2 files changed, 0 insertions, 515 deletions
| diff --git a/src/discipline/Sport.cpp b/src/discipline/Sport.cpp deleted file mode 100644 index 21b9b9f..0000000 --- a/src/discipline/Sport.cpp +++ /dev/null @@ -1,423 +0,0 @@ - -#include "Sport.h" - -// categories -#include <set> - -// sorting and filtering -#include <map> -#include <algorithm> -#include <regex> - -// float to string formatting -#include <iostream> -#include <iomanip> - -#include <QJsonObject> -#include <QJsonArray> -#include <QJsonValueRef> -#include <QString> - -// QJsonArray filter function, provide with input array and evaluation function -QJsonArray filter(QJsonArray input, function<bool (QJsonObject)> 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<bool (const QJsonValue &left, const QJsonValue &right)> genCompare(QString attribute) { -    return [attribute](const QJsonValue &left, const QJsonValue &right) { -        QString l = left.toObject()[attribute].toString(); -        QString r = right.toObject()[attribute].toString(); -        return l.compare(r) < 0; -    }; -} - -// 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; - -    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) { -    // validate competitors -    if (competitors.isEmpty() || !competitors[0].toObject().contains("name")) return; - -    for (int i = 0; i < competitors.size(); ++i) { -        string fullName = competitors[i].toObject()["name"].toString().toUtf8().constData(); - -        // regex to identify names, written in CAPS -        regex r("[A-Z']{2,}"); -        smatch m; - -        regex_search(fullName, m, r); - -        // combine found names again -        string lastName = ""; -        for (string s : m) lastName = lastName + s + " "; - -        // remove last space -        QJsonValue nameValue = QJsonValue(QString(lastName.substr(0, lastName.size() - 1).c_str())); - -        // create new object with replaced name -        QJsonObject comp(competitors[i].toObject()); -        comp.remove("name"); -        comp.insert("name", nameValue); - -        // replace competitor in array -        competitors.replace(i, comp); -    } -} - -/** - * @brief Sport::validateDiscipline Validates the discipline object. Checks for the units attribute. - * @return True, if discipline contains units. - */ -bool Sport::validateDiscipline() { -    return this->discipline.contains("units"); -} - -/** - * @brief Sport::getCategories Reads all possible categories (also called units). - * @return A set of all category names. - */ -set<QString> Sport::getCategories() { -    set<QString> categoryNames; - -    if (!validateDiscipline()) return categoryNames; - -    // search in each unit for the category (named "eventUnitName") -    for (const QJsonValueRef &unitRef : this->discipline["units"].toArray()) { -        QJsonObject unit = unitRef.toObject(); - -        // validate unit -        if (!unit.contains("eventUnitName")) continue; - -        categoryNames.insert(unit["eventUnitName"].toString()); -    } - -    return categoryNames; -} - -/** - * @brief Sport::getCompetitorsByCategory Searches for all competitors, who took part in the given category. - * @param category The category to search in. - * @return An QJsonArray with all competitors as QJsonValueRef, which can be casted to QJsonObject. - */ -QJsonArray Sport::getCompetitorsByCategory(QString category) { -    QJsonArray competitors; - -    if (!validateDiscipline()) return competitors; - -    for (const QJsonValueRef &unitRef : this->discipline["units"].toArray()) { -        QJsonObject unit = unitRef.toObject(); - -        // validate unit -        if (!unit.contains("eventUnitName") || !unit.contains("competitors")) continue; - -        // search all units with the same category -        if (unit["eventUnitName"].toString().compare(category, Qt::CaseSensitive) != 0) continue; - -        // add all competitors from one unit -        for (const QJsonValueRef &compRef : unit["competitors"].toArray()) { -            competitors.push_back(compRef.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<QString, QJsonObject> competitors; - -    if (!validateDiscipline()) return QJsonArray(); - -    // 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(); - -        // validate unit -        if (!unit.contains("competitors")) continue; - -        // filter all competitors, who won medals -        QJsonArray medalComps = filter(unit["competitors"].toArray(), [](QJsonObject comp) { -            if (!comp.contains("results")) return false; - -            QString medalType = comp["results"].toObject()["medalType"].toString(); -            return !medalType.isEmpty(); -        }); - -        for (const QJsonValueRef &medalCompRef : medalComps) { -            QJsonObject medalComp = medalCompRef.toObject(); - -            // validate competitor (with medal) -            if (!medalComp.contains("name") -                || !medalComp.contains("results") -                || !medalComp["results"].toObject().contains("medalType")) continue; - -            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; -        } -    } - -    // convert map to QJsonArray -    QJsonArray output; -    for (const pair<QString, QJsonObject> &competitor : competitors) { -        output.append(competitor.second); -    } - -    return output; -} - -/** - * @brief Sport::createCompetitorWithMedals Creates a competitor QJsonObject with the following attributes: code, name, noc, medals{ME_GOLD, ME_SILVER, ME_BRONZE} - * @param comp The original competitor object. - * @return A competitor object with medal counts. - */ -QJsonObject Sport::createCompetitorWithMedals(QJsonObject comp) { -    // repair competitor if something is missing -    if (!comp.contains("code")) comp.insert("code", "0"); -    if (!comp.contains("name")) comp.insert("code", ""); -    if (!comp.contains("noc")) comp.insert("code", ""); - -    // 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; -} - -/** - * @brief Sport::filterByName Filter the competitors by name (case insensitive). - * @param competitors The competitors of one category. - * @param name The (part of the) name to search for. - */ -void Sport::filterByName(QJsonArray &competitors, QString name) { -    filterCompetitors(competitors, QString("name"), name); -} - -/** - * @brief Sport::filterByCountry Filter the competitors by their national olympics comittee (case insensitive, short form). - * @param competitors The competitors of one category. - * @param nocShort The (part of the) national olympics comittee short name to search for. - */ -void Sport::filterByCountry(QJsonArray &competitors, QString nocShort) { -    filterCompetitors(competitors, QString("noc"), nocShort); -} - -/** - * @brief Sport::filterCompetitors Filters the given QJsonArray by comparing the value of a certain attribute with the given filter string. - * @param competitors The competitors of one category. - * @param attribute The attribute to filter by. - * @param filter The string, which should be contained. - */ -void Sport::filterCompetitors(QJsonArray &competitors, QString attribute, QString filter) { -    for (int i = 0; i < competitors.size(); i++) { -        QJsonObject comp = competitors[i].toObject(); - -        if (!comp.contains(attribute) || !comp[attribute].toString().contains(filter, Qt::CaseInsensitive)) { -            // remove the competitor, if the attribute does not fit the filter string -            competitors.removeAt(i); -            i--; -        } - -    } -} - -/** - * @brief Sport::sortByName Sort the competitors by their name (alphabetical, ascending). - * @param competitors The competitors of one category. - */ -void Sport::sortByName(QJsonArray &competitors) { -    sortCompetitors(competitors, genCompare( QString("name") )); -} - -/** - * @brief Sport::sortByCountry Sort the competitors by their national olympic comittee short name (alphabetical, ascending). - * @param competitors The competitors of one category. - */ -void Sport::sortByCountry(QJsonArray &competitors) { -    sortCompetitors(competitors, genCompare( QString("noc") )); -} - -/** - * @brief Sport::sortByResult Sort the competitors by their results in one specific category (numerical, ascending). - * @param competitors The competitors of one category. - */ -void Sport::sortByResult(QJsonArray &competitors) { -    if (competitors.isEmpty()) return; - -    QJsonObject comp = competitors[0].toObject(); - -    if (comp.contains("results")) sortCompetitors(competitors, compareMark); -    else if (comp.contains("medals")) sortCompetitors(competitors, compareMedals); -} - -/** - * @brief Sport::sortCompetitors Sorts the given QJsonArray according to the compare function. - * @param competitors The competitors of one category. - * @param compare A function to compare two competitors with each other. This defines the order. - */ -void Sport::sortCompetitors(QJsonArray &competitors, function<bool (const QJsonValue &left, const QJsonValue &right)> compare) { -    make_heap(competitors.begin(), competitors.end(), compare); -    sort_heap(competitors.begin(), competitors.end(), compare); -} - -/** - * @brief Sport::reverseOrder Reverses the order of the competitors. - * @param competitors The competitors of one category. - */ -void Sport::reverseOrder(QJsonArray &competitors) { -    int iterations = competitors.size() / 2; // automatically rounds down - -    for (int i = 0; i < iterations; i++) { -        QJsonObject temp = competitors[i].toObject(); -        competitors[i] = competitors[competitors.size() - 1 - i].toObject(); -        competitors[competitors.size() - 1 - i] = temp; -    } -} - -/** - * @brief Sport::addRelativeToFirst Adds a relative value to the result of all competitors. Relative to the first competitor in the QJsonArray. - * Stores the statistic in obj->results->stat for each competitor. - * @param competitors The competitors of one category. - */ -void Sport::addRelativeToFirst(QJsonArray &competitors) { -    if (competitors.isEmpty()) return; - -    QJsonObject reference = competitors[0].toObject(); - -    // validate competitors -    if (!reference.contains("results")) return; - -    QString refVal = reference["results"].toObject()["mark"].toString(); - -    for (int i = 0; i < competitors.size(); i++) { -        QJsonObject competitor = competitors[i].toObject(); -        QJsonObject results = competitor["results"].toObject(); - -        if (results.contains("stat")) results.remove("stat"); - -        // format relative float value to string with 2 digits after decimal point and sign -        stringstream sstream; -        sstream << fixed << setprecision(2) << calcRelativeStat(refVal, results["mark"].toString()); -        QString stat(sstream.str().c_str()); -        stat.append("%"); -        if (stat.at(0).isNumber()) stat = QString("+").append(stat); - -        results.insert("stat", stat); - -        competitor.remove("results"); -        competitor.insert("results", results); - -        competitors.replace(i, competitor); -    } - -} - -/** - * @brief Sport::calcRelativeStat Calculates the relative deviation of val from ref in percent. - * @param ref The reference value. - * @param val The value to calculate the deviation from. - * @return The deviation from ref to val in percent. - */ -float Sport::calcRelativeStat(QString ref, QString val) { -    // check if the value is not a time -    if (!ref.contains(":") && !val.contains(":")) { -        float fRef = ref.toFloat(); - -        if (fRef == 0) return 0.0; -        return ((val.toFloat() * 100)/ fRef) - 100; -    } - -    regex r("\\d+"); -    smatch mref, mval; -    string sref = ref.toUtf8().constData(); -    string sval = val.toUtf8().constData(); - -    regex_search(sref, mref, r); -    regex_search(sval, mval, r); - -    float timeRef = stof(mref.str(1)) * 60 * 100 + stof(mref.str(2)) * 100 + stof(mref.str(3)); -    float timeVal = stof(mval.str(1)) * 60 * 100 + stof(mval.str(2)) * 100 + stof(mval.str(3)); - -    return ((timeVal * 100) / timeRef) - 100; -} diff --git a/src/discipline/Sport.h b/src/discipline/Sport.h deleted file mode 100644 index 147f6e8..0000000 --- a/src/discipline/Sport.h +++ /dev/null @@ -1,92 +0,0 @@ - -#ifndef ITAT_CHALLANGE_OLYMPICS_SPORT_H -#define ITAT_CHALLANGE_OLYMPICS_SPORT_H - - -#include <set> - -#include <QJsonObject> -#include <QJsonDocument> -#include <QString> - -using namespace std; - - -class Sport { - -public: - -    Sport(QJsonObject discipline) { -        this->discipline = discipline; -    } - -    set<QString> 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); - -    // sort functions to change the order of the current competitor array -    void sortByName(QJsonArray &competitors); -    void sortByCountry(QJsonArray &competitors); -    void sortByResult(QJsonArray &competitors); -    void reverseOrder(QJsonArray &competitors); - -    // statistic function(s) -    void addRelativeToFirst(QJsonArray &competitors); - -    void setDiscipline(QJsonObject discipline) { -        this->discipline = QJsonObject(discipline); -    } - -private: - -    /* -     * Analysis of provided competitor objects: -     * -     * Attributes: -     * - code -     * - noc (national olympics comittee) -     * - name (sometimes the country name? mostly the competitors name) -     * - order -     * [- results] (only if the results are out!) -     * -     * -     * Analysis of provided result objects: -     * -     * Attributes: -     * - position -     * - mark -     * - 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 sortCompetitors(QJsonArray &competitors,  function<bool (const QJsonValue &left, const QJsonValue &right)> compare); - -    bool validateDiscipline(); -    QJsonObject createCompetitorWithMedals(QJsonObject medalComp); - -    float calcRelativeStat(QString ref, QString val); - -}; - - -#endif //ITAT_CHALLANGE_OLYMPICS_SPORT_H | 
