Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C ++ std::map with custom comparer for keeping tournament of matches

Tags:

c++

stdmap

I would like to save results of tournament in some container. For every match I need to store names of players and a number of points. For example:

map["player1:player2"] = {2,4};

I want to retrieve from this container not only by key "player1:player2", but even by the inverse key "player2:player1" and I would like to get the inverse results.

I am about to use std::map and make some smart wrapper around it. Maybe there is some trick using custom comparer, custom retrieve and save functions.

Is std::map a good choice for this or is something else better?

EDIT:

I summarized these comments into solution which looks like this:

struct Match
{
    std::string player1;
    std::string player2;

    int pointsPlayer1;
    int pointsPlayer2;

    std::string getKey()
    {
        return player1 + ":" + player2;
    }

    Match reverse()
    {
        Match reversed;
        reversed.player1 = player2;
        reversed.player2 = player1;
        reversed.pointsPlayer1 = pointsPlayer2;
        reversed.pointsPlayer2 = pointsPlayer1;
        return reversed;
    }
};

class Tournament
{   
    std::map<std::string, Match> _games;
public: 
    void insert(Match match);
};

void Tournament::insert(Match match)
{
    _games.insert({ match.getKey(), match });
    Match reversed = match.reverse();
    _games.insert({ reversed.getKey(), reversed });
}

I choose more simple approach and I don't mind that every results is there twice, because insert function replaces both matched every time and encapsulation can guarantee this (it does not expose pointer, just struct).

like image 477
Tomas Kubes Avatar asked May 03 '15 04:05

Tomas Kubes


1 Answers

Firstly, using a std::map can't work. The simple reason is that you want to insert map["player1:player2"] = {2, 4}; into it, but from then on you need it to return {4, 2} when you ask it for map["player2:player1"]. So, not only do you need different keys to reference the same data (which std::map can give you with a custom comparator), but you also need the same data in different format depending on the order in the keys, which std::map can't do.

Now, how to solve this? Firstly, think about the interface that you need. At the moment, you have functions to insert and query tournament results. My crystal ball also tells me you will want to iterate over all results in the tournament, query whether a match already took place and perhaps reset the content of the table. So, go and write down the interfaces to those functions first and document their behaviour, especially for cornercases.

Then, think about how to implement that. The most straightforward way is probably to use a map<pair<string,string>, pair<int,int>> to store the scores. Now, when inserting, you either store the results redundantly (i.e. store both the score for "player1:player2" and "player2:player1") which would then give the proper results on retrieval with either variant. Alternatively, normalize the order (sort the players lexicographically) and on retrieval, optionally invert the order of both the key before lookup and the results afterwards to get the right order.

Notes:

  • There is an alternative approach: If you map how many points player X scored against player Y, you have the same information. The according data structure is map<string, map<string, int>>. To insert a match result, you just do res["player1"]["player2"] = 2; and res["player2"]["player1"] = 4;. I wouldn't do that, except maybe as implementation behind above described interface.
  • I prefer a pair over the string "player1:player2" even if I usually had to display it like the string. The simple reason is that it doesn't mix up representation with the data, which gives you cleaner code. For the same reason, I wouldn't for example store e.g. 3% as a string or as integer value 3, but rather as floating point value 0.03, as it lends itself to according calculations much better (leaving aside floating point inaccuracy issues).
like image 160
Ulrich Eckhardt Avatar answered Oct 11 '22 06:10

Ulrich Eckhardt