Issue with push_back

Hello, I'm new both to this forum and C++. I hope someday I can contribute here somehow, but for now I'm asking for help.

So I'm making a program which is a swiss-system tournament manager.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
#include <algorithm>

using namespace std;

struct Player {

   string name;

   int points;
   vector<int> gameswon;
   int oppmatchwinpercentage;
   int gameswinpercentage;
   int oppgameswinpercentage;
   vector<Player***> opponents;
   bool paired;

};

bool areYouDone();

int main() {

    vector<Player> participant;

    int NumPlayersJoined = 0;

    do {

        participant.push_back(Player());

        cout << "Enter name: " << endl;
        getline (cin,participant[NumPlayersJoined].name);

        participant[NumPlayersJoined].points=0;
        participant[NumPlayersJoined].paired=0;

        NumPlayersJoined++;

    } while ( areYouDone() );

    cout << endl;

    int round;

    vector<vector<Player*> > pod;

    round=1; // Temporary

    int rem;

    for (int total = 3*round; total >= 0 ; total -= rem) {

        if (total == 3*round) {

           rem = 2;

        } else {rem = 1;} 

        vector<Player*> level;

        for (int i = 0; i < NumPlayersJoined; i++) {

            if (participant[i].points == total) {

               level.push_back( &(participant[i]) );

            }

        }

        if (level.size() != 0 ) {

           pod.push_back(level);

        } //If there are any players with i points, that level gets added.
    }

    srand ( time(NULL) );

    vector<vector<Player**> > pairings;

    bool PairDown = 0;
    bool PairUp;

    for (int i = 0; i < pod.size(); i++) {

        PairUp = PairDown; 

        if ( (pod[i].size() - PairUp) % 2 == 0) {

           PairDown = 0;

        } else { PairDown = 1; }
        
        int seed;

        int select = i;

        int NumPlayersPaired = 0;

        do {

            vector<Player**> match;

            for (int j = 0; j < 2; j++) {

                do {

                    if ( ( NumPlayersPaired == (pod[i].size() - PairUp) ) && (PairDown == 1) ) {

                       seed = rand() %pod[i+1].size();

                       match.push_back( new Player*() );
                       match[j] = &(pod[i+1][seed]);

                       NumPlayersPaired++;

                       select = i+1;

                    } else { seed = rand() %pod[i].size(); }

                    if ( (*pod[i][seed]).paired == 0 ) {

                       match.push_back( new Player*() );
                       match[j] = &(pod[i][seed]);

                       NumPlayersPaired++;

                    }

                } while ( ( (*pod[select][seed]).paired != 0 ) );

                (**match[j]).paired = 1;

            }

            bool valid;

            if ( find( (**match[0]).opponents.begin(), (**match[0]).opponents.end(), (**match[1]) ) != (**match[0]).opponents.end() ) {

               valid = 0;

            } else { valid = 1; }

            if (valid) {

               //HERE COMES THE ISSUE
               (**match[0]).opponents.push_back( &(match[1]) );
               (**match[1]).opponents.push_back( &(match[0]) );

               pairings.push_back(match);

            } else {

                NumPlayersPaired -= 2;
                (**match[0]).paired = 0;
                (**match[1]).paired = 0;

            }

      } while ( NumPlayersPaired < (pod[i].size() - PairUp + PairDown) );

    }

    cout << endl;

    for (int i = 0; i < pairings.size(); i++) {

        cout << i+1 << ".\t" << (**pairings[i][0]).name << " vs " << (**pairings[i][1]).name << endl;

    }

.
.
.


I'm not pasting the whole thing, just what it's relevant. The compiler complains at:

1
2
(**match[0]).opponents.push_back( &(match[1]) );
(**match[1]).opponents.push_back( &(match[0]) );


It says: "error: no match for 'operator==' (operand types are 'Player***' and 'const Player')".

I have another version of this program where vector 'opponents' has the type 'vector<string>' instead of 'vector<Player***>', and it works perfectly fine.

1
2
(**match[0]).opponents.push_back( (**match[1]).name );
(**match[1]).opponents.push_back( (**match[0]).name );


However, I really need to create this 'vector<Player***>' type vector, so this is just a functional workaround for now. The reason why I need this type of vector is because in the future I will need something like this:

1
2
3
4
5
6
7
8
9
for (int j = 0; i < round; j++) {

    for (int i = 0; i < round ; i++) {

        participant[j].oppgameswinpercentage += participant[j].(***opponents).gameswinpercentage / round; //CREATE THIS

    }

}
Hi,

Two or three levels of pointer indirection gets tricky. Wanting to use them sounds like a better design is needed.

This is a 4 dimensional thing:
vector<vector<Player**> > pairings;

Why does Player have vector<Player***> opponents; ? That's a 4 dimensional list of opponents !

Try to do everything with better combinations of C++ STL containers instead. I gather you have pairs of things (pairings) , the STL has std::pair<>.

Also, try to avoid new. The problem with new is that if an exception is thrown by anything, delete is never reached. Although I guess you are using it here because you wanted pointers.

I think you need to make better use of functions. A function should only do 1 conceptual thing, so they should be short - less than 40 LOC say, usually less. The main function should call a series of functions.
Thanks for the reply. I will definitely organize everything in functions, I had that planned.

Player has vector<Player***> opponents; because every player will have fields that need to take data from all their opponents. After every round, this vector will add a pointer at the opponent a player has played against. This way, you keep track of all the opponents that a player has faced. With my limited knowledge I don't know any other way to do that.

For the pairings thing, it seems like I'd like to use std::pair. It should be easy, I'll figure out the way to do that.

If you planned to save your data into a database, those pointers would become a pain in the neck.
Let me come up with a different idea:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <algorithm>
#include <iostream>
#include <set>
#include <vector>

class Player {
public:
    Player() { id = ++auto_increment; }
    int id;
    std::set<int> met_id;
    friend std::ostream& operator<<(std::ostream& os, const Player& out);
    friend bool operator==(const Player& one, const Player& two);
private:
    static int auto_increment;
};


int Player::auto_increment {0};


std::ostream& operator<<(std::ostream& os, const Player& out)
{
    os << "Player " << out.id << " have already met: ";
    for(int i : out.met_id) { os << "Player " << i << "; "; }
    return os << '\n';
}


bool operator==(const Player& one, const Player& two)
{ return one.id == two.id; }


void waitForEnter();


int main()
{
    std::vector<Player> partecipants(5);
    std::cout << "Competition starts...\n";
    for(auto& a : partecipants) {
        for(auto& b : partecipants) {
            if(a == b) { continue; }
            std::cout << "Player " << a.id << " is going to meet "
                      << " player " << b.id << '\n';
            a.met_id.insert(b.id); // no need to check if succeed
            b.met_id.insert(a.id); // no need to check if succeed
        }
    }
    std::cout << "Let's verify if all data have been put down.\n";
    for(const auto& a : partecipants) { std::cout << a; }
    
    waitForEnter();
    return 0;
}


void waitForEnter()
{
    std::cout << "\nPress ENTER to continue...\n";
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}


Output:
Competition starts...
Player 1 is going to meet  player 2
Player 1 is going to meet  player 3
Player 1 is going to meet  player 4
Player 1 is going to meet  player 5
Player 2 is going to meet  player 1
Player 2 is going to meet  player 3
Player 2 is going to meet  player 4
Player 2 is going to meet  player 5
Player 3 is going to meet  player 1
Player 3 is going to meet  player 2
Player 3 is going to meet  player 4
Player 3 is going to meet  player 5
Player 4 is going to meet  player 1
Player 4 is going to meet  player 2
Player 4 is going to meet  player 3
Player 4 is going to meet  player 5
Player 5 is going to meet  player 1
Player 5 is going to meet  player 2
Player 5 is going to meet  player 3
Player 5 is going to meet  player 4
Let's verify if all data have been put down.
Player 1 have already met: Player 2; Player 3; Player 4; Player 5;
Player 2 have already met: Player 1; Player 3; Player 4; Player 5;
Player 3 have already met: Player 1; Player 2; Player 4; Player 5;
Player 4 have already met: Player 1; Player 2; Player 3; Player 5;
Player 5 have already met: Player 1; Player 2; Player 3; Player 4;

Press ENTER to continue...

Topic archived. No new replies allowed.