Tic Tac Toe Program Errors

So I am trying to truck through a class using the book: "C++ Programming for the Absolute Beginner," by Mark Lee.

What I find so frustrating is the fact that his code often doesn't compile without errors. Even with a perfect copy and paste. What I also find frustrating is that he often uses things that aren't required which makes it difficult when trying to learn the code. An example is he always puts "using std::cout;" and "using std::cin" etc.. etc.. everywhere. When it is completely unnecessary as long as you have "using namespace std;" at the top. Is there something I am missing?

To the point... I have this code for a tic tac toe game that I am trying to learn. But its really difficult to learn when the author provided example doesn't even work... Whats wrong? What am I doing?

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
#include <iostream>
#include <string>
#include <cmath>
#include <cstdlib>
#include <errno.h>

using namespace std;

using std::string;

enum SquareState { blank = ' ', X = 'X', O='O'};

class GameBoard
{
private:
    const int WIDTH;
    const int HEIGHT;
    int* gameBoard;

public:
    GameBoard() : WIDTH(3),HEIGHT(3)
    {
        gameBoard = new int[9];
        for (int i = 0; i < 9; i++)
            *(gameBoard + i) = blank;
    }

    ~GameBoard() {delete[] gameBoard;}
    void setX(int h, int w);
    void set0(int h, int w);
    bool isTaken(int h, int w);
    SquareState isLine();
    void draw();
};

void GameBoard::setX(int h, int w)
{
    *(gameBoard + h*HEIGHT + w) = X;
}

void GameBoard::set0(int h, int w)
{
    *(gameBoard + h*HEIGHT + w) = O;
}

bool GameBoard::isTaken (int h, int w)
{
    return *(gameBoard + h*HEIGHT + w) != ' ';
}

SquareState GameBoard::isLine()

{
    if(*gameBoard==X && *(gameBoard +1)==X && *(gameBoard +2)==X)
        return X;
    if(*gameBoard==O && *(gameBoard +1)==O && *(gameBoard +2)==O)
        return O;
    if(*(gameBoard +3)==X && *(gameBoard +4)==X && *(gameBoard +5)==X)
        return X;
    if(*(gameBoard +3)==O && *(gameBoard +4)==O && *(gameBoard +5)==O)
        return O;
    if(*(gameBoard +6)==X && *(gameBoard +7)==X && *(gameBoard +8)==X)
        return X;
    if(*(gameBoard +6)==O && *(gameBoard +7)==O && *(gameBoard +8)==O)
        return O;
    if(*gameBoard==X && *(gameBoard +3)==X && *(gameBoard +6)==X)
        return X;
    if(*gameBoard==O && *(gameBoard +3)==O && *(gameBoard +6)==O)
        return O;
    if(*(gameBoard +1)==X && *(gameBoard +4)==X && *(gameBoard +7)==X)
        return X;
    if(*(gameBoard +1)==O && *(gameBoard +4)==O && *(gameBoard +7)==O)
        return O;
    if(*(gameBoard +2)==X && *(gameBoard +5)==X && *(gameBoard +8)==X)
        return X;
    if(*(gameBoard +2)==O && *(gameBoard +5)==O && *(gameBoard +8)==O)
        return O;
    if(*gameBoard==X && *(gameBoard +4)==X && *(gameBoard +8)==X)
        return X;
    if(*gameBoard==O && *(gameBoard +4)==O && *(gameBoard +8)==O)
        return O;
    if(*(gameBoard +2)==X && *(gameBoard +4)==X && *(gameBoard +6)==X)
        return X;
    if(*(gameBoard +2)==O && *(gameBoard +4)==O && *(gameBoard +6)==O)
        return O;
    return blank;
}

void GameBoard::draw()
{
    using std::cout;
    cout << "\n";
    for (int i=0; i < HEIGHT; i++)
    {
        cout << (char)*(gameBoard + i*HEIGHT);
        for(int c=1; c < WIDTH; c++)
            cout << " | " << (char)*(gameBoard + i*WIDTH + c);
        cout << "\n" << "-------" << "/n";
    }
}

class Game
{
public:
    GameBoard* doInput(string player, gameBoard* gb);
    bool inRange(int test);
};

GameBoard* Game::doInput(string player, GameBoard* gb)
{
    using std::cout;
    using std::cin;

    gb->draw();
    string letter;
    if (player.compare("one")==O)
        letter = "X";
    else if (player.compare("two")==O)
        letter = "O";
    else return gb;

    int input1, input2;
    do {
        do {
            cout << "\nPlayer " << player.c_str()
                << ", please enter a row number to put an "
                << letter.c_str() << ": ";
            cin >> input1;
        } while(!inRange(input1));
        do{
            cout << "\nPlease enter a column number to put an "
                << letter.c_str() << ": ";
            cin >> input2;
        } while(!inRange(input2));
    } while (gb->isTaken(input1, input2));

    if (player.compare("one") == O)
        gb->setX(input1, input2);
    else
        gb->setO(input1, input2);
    return gb;
}

bool Game::inRange(int test)
{
    return test > -1 && test < 3;
}

int main( void )
{
    using std::cout;
    using std::cin;

    GameBoard* gb = new GameBoard;
    Game g;
    string player1, player2;

    cout << "Welcome to Tic Tac Toe!"
        << "\nPlayer one, please enter your name: ";
        cin >> player1;
    cout << "\nPlayer two, please enter your name: ";
        cint >> player2;

    while (gb->isLine()==' ' )
    {
        gb = g.doInput("one",gb);
        gb = g.doInput("two",gb);
    }
    gb->draw();
    if(gb->isLine() == X)
        cout << "\nPlayer one, you win!\nGame Over.";
    else
        cout << "\nPlayer two, you win!\nGame Over.";
    return 0;
}


And it receives an error on line 105 saying "Gameboard" is not declared. And im like... "what do you think that 'void GameBoard::' up top is...??" I am stuck!

Any help would be appreciated, thanks! =)

- JDRhoads
Last edited on
An example is he always puts "using std::cout;" and "using std::cin" etc.. etc.. everywhere. When it is completely unnecessary as long as you have "using namespace std;" at the top. Is there something I am missing?


The best practise is to put std:: before each std thing, as in:

std::cout << "\nPlayer one, you win!\nGame Over.";

Then you can remove all the using statements, especially using namespace std; It's more typing, but you won't have any name clashes. That is what the experts here do, so you may as well learn this now :+) The using std::cout; is ok, just that it gets tiresome when there are lots of them at the top of a file, it's easy to do when using different STL containers and algorithms.

And it receives an error on line 105 saying "Gameboard" is not declared. And im like... "what do you think that 'void GameBoard::' up top is...??" I am stuck!


C++ is case sensitive, the identifier must match the class name.

102
103
104
105
106
107
class Game
{
public:
    GameBoard* doInput(string player, GameBoard* gb);
    bool inRange(int test);
};


more typos here:

In member function 'GameBoard* Game::doInput(std::string, GameBoard*)':
140:13: error: 'class GameBoard' has no member named 'setO'
In function 'int main()':
162:9: error: 'cint' was not declared in this scope


I would rename the function in the class definition to setO, that is more sensible than set0.

When you get that working, an improvement would be to put the class defintions in their own hpp files (header file with cpp code) - 1 for each class , and the definition of the class functions in their own cpp files (1 for each class). Then you can #include those header files in each file that requires them - that is uses something which is in that header file.
Last edited on
You aren't citing the error very carefully. It tells you the line number: 105. On that line I can see a GameBoard and a gameBoard. Your post claims a third version: Gameboard. I am sure that the book told you upper and lower case matter and are distinct.
The following might be a little advanced right now, but there you go :+)

Also, pass std::string by const reference, in the function definition not in the class:

1
2
GameBoard* Game::doInput(const string& player, GameBoard* gb)
{


Use const where ever you can, if the variable is not supposed to be altered make it const.

Class functions which don't change the value of any of it's members, should also be const

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class GameBoard
{
private:
    const int WIDTH;
    const int HEIGHT;
    int* gameBoard;

public:
    GameBoard() : WIDTH(3),HEIGHT(3)
    {
        gameBoard = new int[9];
        for (int i = 0; i < 9; i++)
            *(gameBoard + i) = blank;
    }

    ~GameBoard() {delete[] gameBoard;}
    void setX(int h, int w) const ;
    void set0(int h, int w) const ;
    bool isTaken(int h, int w) const ;
    SquareState isLine() const ;
    void draw() const ;
};


Make sure you change the function definition to match, function marked with const is a different function to one that isn't.

Use of new and delete is not a good idea. For this, using a tiny amount of memory, it won't make any difference to anything. If one had a lot of data, prefer to use an STL container like std::vector say. The STL containers do their own memory management.

Use of pointers is also not preferred, use a container instead. The trouble is that teachers tend to mix C techniques into the C++, which is confusing and harder for the student.
Thank you very much! So I have tackled through the responses and made some changes. I appreciate the "const" advice. I am now actually able to run it! Now I just have to fix it... As it stands this is the code, when it runs it endlessly seems to print the gameBoard... I am trying to figure out why and how to fix it.

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
#include <iostream>
#include <string>
#include <cmath>
#include <cstdlib>
#include <errno.h>

using namespace std;

using std::string;

enum SquareState { blank = ' ', X = 'X', O='O'};

class GameBoard
{
private:
    const int WIDTH;
    const int HEIGHT;
    int* gameBoard;

public:
    GameBoard() : WIDTH(3),HEIGHT(3)
    {
        gameBoard = new int[9];
        for (int i = 0; i < 9; i++)
            *(gameBoard + i) = blank;
    }

    ~GameBoard() {delete[] gameBoard;}
    void setX(int h, int w) const ;
    void setO(int h, int w) const ;
    bool isTaken(int h, int w) const ;
    SquareState isLine() const ;
    void draw() const ;
};

void GameBoard::setX(int h, int w) const
{
    *(gameBoard + h*HEIGHT + w) = X;
}

void GameBoard::setO(int h, int w) const
{
    *(gameBoard + h*HEIGHT + w) = O;
}

bool GameBoard::isTaken (int h, int w) const
{
    return *(gameBoard + h*HEIGHT + w) != ' ';
}

SquareState GameBoard::isLine() const

{
    if(*gameBoard==X && *(gameBoard +1)==X && *(gameBoard +2)==X)
        return X;
    if(*gameBoard==O && *(gameBoard +1)==O && *(gameBoard +2)==O)
        return O;
    if(*(gameBoard +3)==X && *(gameBoard +4)==X && *(gameBoard +5)==X)
        return X;
    if(*(gameBoard +3)==O && *(gameBoard +4)==O && *(gameBoard +5)==O)
        return O;
    if(*(gameBoard +6)==X && *(gameBoard +7)==X && *(gameBoard +8)==X)
        return X;
    if(*(gameBoard +6)==O && *(gameBoard +7)==O && *(gameBoard +8)==O)
        return O;
    if(*gameBoard==X && *(gameBoard +3)==X && *(gameBoard +6)==X)
        return X;
    if(*gameBoard==O && *(gameBoard +3)==O && *(gameBoard +6)==O)
        return O;
    if(*(gameBoard +1)==X && *(gameBoard +4)==X && *(gameBoard +7)==X)
        return X;
    if(*(gameBoard +1)==O && *(gameBoard +4)==O && *(gameBoard +7)==O)
        return O;
    if(*(gameBoard +2)==X && *(gameBoard +5)==X && *(gameBoard +8)==X)
        return X;
    if(*(gameBoard +2)==O && *(gameBoard +5)==O && *(gameBoard +8)==O)
        return O;
    if(*gameBoard==X && *(gameBoard +4)==X && *(gameBoard +8)==X)
        return X;
    if(*gameBoard==O && *(gameBoard +4)==O && *(gameBoard +8)==O)
        return O;
    if(*(gameBoard +2)==X && *(gameBoard +4)==X && *(gameBoard +6)==X)
        return X;
    if(*(gameBoard +2)==O && *(gameBoard +4)==O && *(gameBoard +6)==O)
        return O;
    return blank;
}

void GameBoard::draw() const
{
    using std::cout;
    cout << "\n";
    for (int i=0; i < HEIGHT; i++)
    {
        cout << (char)*(gameBoard + i*HEIGHT);
        for(int c=1; c < WIDTH; c++)
            cout << " | " << (char)*(gameBoard + i*WIDTH + c);
        cout << "\n" << "-------" << "/n";
    }
}

class Game
{
public:
    GameBoard* doInput(const string& player, GameBoard* gb);
    bool inRange(int test);
};

GameBoard* Game::doInput(const string& player, GameBoard* gb)
{
    using std::cout;
    using std::cin;

    gb->draw();
    string letter;
    if (player.compare("one")==O)
        letter = "X";
    else if (player.compare("two")==O)
        letter = "O";
    else return gb;

    int input1, input2;
    do {
        do {
            cout << "\nPlayer " << player.c_str()
                << ", please enter a row number to put an "
                << letter.c_str() << ": ";
            cin >> input1;
        } while(!inRange(input1));
        do{
            cout << "\nPlease enter a column number to put an "
                << letter.c_str() << ": ";
            cin >> input2;
        } while(!inRange(input2));
    } while (gb->isTaken(input1, input2));

    if (player.compare("one") == O)
        gb->setX(input1, input2);
    else
        gb->setO(input1, input2);
    return gb;
}

bool Game::inRange(int test)
{
    return test > -1 && test < 3;
}

int main( void )
{
    using std::cout;
    using std::cin;

    GameBoard* gb = new GameBoard;
    Game g;
    string player1, player2;

    cout << "Welcome to Tic Tac Toe!"
        << "\nPlayer one, please enter your name: ";
        cin >> player1;
    cout << "\nPlayer two, please enter your name: ";
        cin >> player2;

    while (gb->isLine()==' ' )
    {
        gb = g.doInput("one",gb);
        gb = g.doInput("two",gb);
    }
    gb->draw();
    if(gb->isLine() == X)
        cout << "\nPlayer one, you win!\nGame Over.";
    else
        cout << "\nPlayer two, you win!\nGame Over.";
    return 0;
}
As it stands this is the code, when it runs it endlessly seems to print the gameBoard... I am trying to figure out why and how to fix it.


Nothing is jumping out at me, maybe you should try the debugger in your IDE. You should be able to set up a watch list of variables; set a break point; step through the code 1 line at time; see how the values of the variables change; deduce where it all goes wrong.

If not using an IDE, there are command line versions.

What I meant about std::

1
2
3
4
5
6
7
8
9
10
11
12
13
void GameBoard::draw() const
{
    using std::cout;
    std::cout << "\n";
    for (int i=0; i < HEIGHT; i++)
    {
        std::cout << (char)*(gameBoard + i*HEIGHT);
        for(int c=1; c < WIDTH; c++) {
            std::cout << " | " << (char)*(gameBoard + i*WIDTH + c);
        }
        std::cout << "\n" << "-------" << "/n";
    }
}


and

1
2
GameBoard* Game::doInput(const std::string& player, GameBoard* gb)
{


Always use braces for loops, even if there is only 1 statement. It will save you one day, when you add more code.

There are other places to use const: where the function argument shouldn't be changed.

1
2
3
4
bool Game::inRange(const int test)
{
    return test > -1 && test < 3;
}



When there are no arguments, void has never been a requirement in C++. That again shows the C influence in this code.
int main( void )

What would be really good: Try to figure out how to do this without pointers, new or C style casts. In other words more like C++. Try std::array

http://www.cplusplus.com/reference/array/array/
http://en.cppreference.com/w/cpp/container/array

The STL containers can be nested
1
2
3
4
5
6
7
#include <array>

 constexpr std::size_t Size = 3;
 std::array<std::array<char, Size>, Size> Board{{}}; // initialise all the cells to default values

 Board[1][1] = 'X'; // assign the centre cell


What I mean about teachers teaching C not C++:
http://www.cplusplus.com/forum/lounge/211316/

Some other really good stuff:

http://en.cppreference.com/w/cpp/links

There are a lot of bad books out there, here are some better ones:
https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list
Topic archived. No new replies allowed.