Search code examples
c++tic-tac-toe

Test for possible wins in tictactoe game


I'm creating a tictactoe game, and every move I need to test whether a player has won or not, and it's giving me a lot of trouble. I have a 2d vector of all the possible win combinations:

vector<vector<int>> possibleWins {{1,2,3},{4,5,6},{7,8,9},{1,4,7},{2,5,8},{3,6,9},{1,5,9},{3,5,7}};

Every move I loop through the 2d vector and append player1 and player2 vectors with any cells they have marked:

vector<int> totalX {};
vector<int> totalO {};
int count = 1;
for(int i=0; i<3; i++) {
    for(int j=0; j<3; j++) {
        if(board[i][j] == 'x') {
            if(totalX.size() == 0) {
                totalX.push_back(count);
            }
            for(int k=0; k<totalX.size(); k++) {
                if(count == totalX[k]) {
                    break;
                }
                else {
                    totalX.push_back(count);
                }
            }
        }
        else if(board[i][j] == 'o') {
            if(totalO.size() == 0) {
                totalO.push_back(count);
            }
            for(int k=0; k<totalO.size(); k++) {
                if(count == totalO[k]) {
                    break;
                }
                else {
                    totalO.push_back(count);
                }
            }
        }
        count++;
    }
}

I then try to test whether the cells in each players cell vector is a winning combination of cells, and this is proving to be difficult for me:

int xInRow = 0;
for(int x=0; x<totalX.size(); x++) {
    for(int y=0; y<possibleWins.size(); y++) {
        xInRow = 0;
        for(int z=0; z<3; z++) {
            if(totalX[x] == possibleWins[y][z]) {
                xInRow++;
                if(xInRow == 3) {
                    return X_WON;
                }
            }
        }
    }
}

This does not work, and I've tried implementing it in numerous different ways, but I honestly have no idea how to enumerate through all the possible wins and test if a player has one of these combinations.

Is there a way I could structure this better to make it work? I'm pretty lost on this.


Solution

  • There are two approaches. Your code is a bit too complicated for what should be a simple operation so I'm not going to try to understand it.

    I agree with YSC that you don't need a std::vector. You know it's a 3x3 grid every time, so a 3x3 enum array should be much better. Something like

    enum TTTState {
        EMPTY=0,
        X,
        O
    }
    
    TTState board[3][3];
    

    would save you a lot of headache. You can say board[0][0] is the top left, and board[2][2] is the bottom right.

    Option 1

    I like your idea of possibleWins, so with the new board[3][3] data structure, you can store pair of numbers with int solutions[8][3][2] but this is already kind of messy.

    for each solution in solutions
        for each triplet in solution
            for each pair in triplet
                if board[pair[0]][pair[1]] matches all other pair in triplet
                    then whoever has pieces in the row has won
    

    Option 2

    This is probably cleaner. There are 3 possible ways to win. Horizontal, vertical, and diagonal. You can check these three ways separately.

    for i = 0 ; i != 3; i++
        type = board[i][0]
        won = true
        for ii = 1; ii != 3; ii++
            if board[i][ii] is not type
                won = false
        if won then you can return the function with who won
    
    for i = 0 ; i != 3; i++
        type = board[0][i]
        won = true
        for ii = 1; ii != 3; ii++
            if board[ii][i] is not type
                won = false
        if won then you can return the function with who won
    

    Diagonal can just be hard coded, since there are only two possible victory positions..