5
\$\begingroup\$

I have written this simple code for Tic Tac Toe.

#include <iostream>
#include <vector>

void draw_board(const std::vector< std::vector<char> >& vec)
{
    std::cout << "    0   1   2  \n";
    std::cout << "  +---+---+---+\n";
    for (int i = 0; i < vec.size(); i++)
    {
        std::cout << i << " " ;
        for (int j = 0; j < vec[i].size(); j++)
        {
            std::cout << "| " << vec[i][j] << " ";
        }
        std::cout << "|";
        std::cout << '\n';
        std::cout << "  +---+---+---+\n";
    }
}

void enter(int row, int col, char ch, std::vector< std::vector<char> >& vec)
{
    vec[row][col] = ch;
}

bool check(const std::vector< std::vector<char> >& vec)
{
    //to check diagonals
    if ((vec[0][0] == 'X' && vec[1][1] == 'X' && vec[2][2] == 'X')
        || (vec[0][2] == 'X' && vec[1][1] == 'X' && vec[2][0] == 'X'))
        {
            std::cout << "Player X won this game\n";
            return true;
        }
    else if ((vec[0][0] == 'O' && vec[1][1] == 'O' && vec[2][2] == 'O')
             || (vec[0][2] == 'O' && vec[1][1] == 'O' && vec[2][0] == 'O'))
             {
                std::cout << "Player O won this game\n";
                return true;
             }

    //to check horizonatal and vertical
    for (int i = 0; i < vec.size(); i++)
    {
        if ((vec[i][0] == 'X' && vec[i][1] == 'X' && vec[i][2] == 'X')
              || (vec[0][i] == 'X' && vec[1][i] == 'X' && vec[2][i] == 'X'))
              {
                  std::cout << "Player X won this game\n";
                  return true;
              }
        else if((vec[i][0] == 'O' && vec[i][1] == 'O' && vec[i][2] == 'O')
              || (vec[0][i] == 'O' && vec[1][i] == 'O' && vec[2][i] == 'O'))
              {
                  std::cout << "Player O won this game\n";
                  return true;
              }
    }
}

void start(std::vector< std::vector<char> >& vec)
{
    int row, col, res = 0;
    char ch;

    std::vector<int> index = {0, 1, 2};

    for (int i = 0; i < vec.size(); i++)
    {
        for (int j = 0; j < vec[i].size(); j++)
        {
            vec[i][j] = ' ';
        }
    }

    for (int i = 0; i < 9;)
    {
        if (i == 0 || i%2 == 0)
        {
            ch = 'X';
            std::cout << "Chance to enter X\n";
        }
        else
        {
            ch = 'O';
            std::cout << "Chance to enter O\n";
        }
        std::cout << "Enter row number ";
        std::cin >> row;
        std::cout << "Enter column number ";
        std::cin >> col;
        if (vec[row][col] == ' ' || vec[row][col] == ' ')
        {
            enter(row, col, ch, vec);
            draw_board(vec);
            if ( i >= 2)
            {
                res = check(vec);
                if (res == 1)
                {
                    break;
                }
            }
            i++;
        }
        else
        {
            std::cerr << "This position already contains a character\n";
        }

    }
    if (res == 0)
    {
        std::cout << "This game draws\n";
    }
}

int main()
{
    std::vector< std::vector<char> > board(3, std::vector<char>(3));
    draw_board(board);
    start(board);
}
\$\endgroup\$

2 Answers 2

4
\$\begingroup\$

Check your inputs in enter()

You don't check that the user entered a valid vector index. For example, if I enter a 3 as the row and/or column number the program crashes. You should reject an input if the user enters an invalid row and/or column number (like you do if the user selects a space that is already taken).

All control paths of check() should return a value

You only ever return true in check(). If none of the check conditions are true then you should explicitly return false at the end of the function.

Use the correct type for indexing

You have for loops like for (int i = 0; i < vec.size(); i++), which compare the signed integer i to the unsigned integer vec.size(). Use std::vector< std::vector<char> >::size_type.

Use a type alias / type definition for the std::vector< std::vector<char> > container

Use a type alias like using container = std::vector< std::vector<char> >; if your compiler supports it, otherwise use a type definition like typedef std::vector< std::vector<char> > container;. You can put it after the #include statements so you can use it for all your functions. This is useful for a couple of reasons:

  1. It's a shorter name for the container. This comes in handy when referring to the container and/or its size_type, for example: container::size_type is shorter and easier to read than std::vector< std::vector<char> >::size_type.
  2. It's easier to change the container. You may decide later to use a std::array instead, in which case you only need to modify the using statement rather than all instances of std::vector< std::vector<char> >.
\$\endgroup\$
4
\$\begingroup\$
  • Don't declare more than one variable per line

  • You can skip your initialization code for the vector and just do it when you declare it: std::vector< std::vector<char> > board(3, std::vector<char>(3, ' '));

  • You confused rows and columns

  • You don't return false at the end of your check function which makes the game end after 3 turns.

  • index does not seem to be used?

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.