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).
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:
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.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With