Thread: Tic Tac Toe

  1. #1
    Registered User
    Join Date
    Dec 2009
    Location
    Brighton
    Posts
    4

    Tic Tac Toe

    Hi all,

    I've been going through the tutorials on the site and decided to create a simple tic tac toe program to put them in to context. This is my first attempt at c++ so go easy on me.

    Code:
    #include <iostream>
    
    using namespace std;
    
    //Tile Class
    
    class Tile {
    	
    	public:
    	Tile();
    	~Tile();
    	void changeValue( int newValue );
    	void display();
    	int getValue();
    	int getX();
    	int getY();
    	
    	protected:
    	int value;
    	int x;
    	int y;
    	};
    
    Tile::Tile() {
    	
    	value = 0;
    	
    }
    
    Tile::~Tile() {
    	
    	//Destructors do not accept arguments
    }
    
    void Tile::changeValue (int newValue) {
    
    	value = newValue;
    	
    }
    
    int Tile::getValue() {
    	return value;
    }
    
    void Tile::display() {
    	if (value == 0) {
    		cout << "|   ";
    	}
    	if (value == 1) {
    		cout << "| X ";
    	}
    	if (value == -1) {
    		cout << "| 0 ";
    	}
    }
    
    int Tile::getX() {
    	
    	return x;
    }
    
    int Tile::getY() {
    	
    	return y;
    }
    
    //Board Class
    
    class Board {
    	
    public:
    	Board();
    	~Board();
    	void displayBoard();
    	void changeValue(char ox, int x, int y);
    	bool isFinished(int moves);
    	bool boardFull(int moves);
    	bool isLegal(int x, int y);
    	
    protected:
    	Tile board[3][3];
    };
    	
    Board::Board() {
    	
    	int i;
    	int j;
    	
    	for (i = 0; i < 3; i++) {
    		for (j = 0; j < 3; j++) 
    			Tile newTile;
    			board[i][j] = newTile;  //error: 'newTile' was not declared in this scope
    	}
    }
    
    Board::~Board() {
    	
    }
    
    void Board::displayBoard() {
    	
    	int i;
    	int j;
    	
    	cout << "Noughts and Crosses: \n";
    	
    	cout << "_____________\n";
    	
    	for (i = 0; i < 3; i++) {
    		for (j = 0; j < 3; j++)
    			board[i][j].display();
    		cout << "|";
    		cout << "\n";
    		cout << "-------------\n";
    	}
    }
    	
    void Board::changeValue(char ox, int x, int y) {
    	
    	if (ox == 'X' || ox == 'x') {
    		board[x][y].changeValue(1);
    	}
    	
    	if (ox == '0' || ox == 'o' || ox == 'O'){
    		board[x][y].changeValue(-1);
    	}
    		
    	displayBoard();
    }
    
    bool Board::boardFull(int moves) {
    
    	bool isFull;
    	isFull = 0;
    	
    	if (moves >= 9) {
    		isFull = 1;
    	}
    	else {
    		return isFull;
    	}
    	
    	return isFull;
    }
    		
    
    bool Board::isFinished(int moves) {
    	
    	bool finished = 0;
    	
    	if (boardFull(moves)){
    		finished = 1;
    	}
    	
    	return finished;
    }
    
    
    bool Board::isLegal(int x, int y) {
    	
    	bool isLegal = 0;
    	
    	if (x > 0 && x <= 3 && y > 0 && y <= 3 && board[x-1][y-1].getValue() == 0){
    		isLegal = 1;
    	}
    	return isLegal;
    }
    
    
    int main () {
    	
    	char player;
    	int x;
    	int y;
    	int moves;
    	moves = 0;
    	
    	Board board;
    	board.displayBoard();
    	
    	while (!board.isFinished(moves)){
    		
    		if (moves % 2 == 0) {
    			player = '0';
    		}
    		else {
    			player = 'X';
    		}
    		
    		cout << "Player " << player << " please enter your next move: \n";
    		cout << "X Coordinate: " << endl;
    		cin >> x;
    		cout << "Y Coordinate: " << endl;
    		cin >> y;
    		
    		cin.ignore();
    		
    		//create is legal method
    		
    		if (board.isLegal(x, y)) {
    			board.changeValue(player, x-1, y-1);
    			moves++;
    		}
    		else {
    			cout << "Invalid Move!\n";
    		}
    	}
    	
    	cin.get();
    	cout << "Game Over\n";
    	
    	return 0;
    }
    In the constructor method for the board class I'm getting the error message "//error: 'newTile' was not declared in this scope" and I can't work out why. Could anyone help with this?

    Zack

  2. #2
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    In a word: missing curly braces.
    Code:
    	for (i = 0; i < 3; i++) {
    		for (j = 0; j < 3; j++) {
    			Tile newTile;
    			board[i][j] = newTile;  //error: 'newTile' was not declared in this scope
                    }
    	}
    Once I add the code in blue, it works just fine. Nice program, by the way!
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  3. #3
    Registered User
    Join Date
    Dec 2009
    Location
    Brighton
    Posts
    4
    Haha, thanks man. Can't believe I didn't spot that!

  4. #4
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    FWIW, in case you're interested: tic-tac-toe computer
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  5. #5
    Registered User
    Join Date
    Dec 2009
    Location
    Brighton
    Posts
    4

    One more question:

    Thanks for the link, looks very interesting. I'll have to have a look when I've had a go at writing something myself and see what others have done differently (better).

    One more question, my first question came from trying to debug this error, I've spent a while on this and can't work out what's wrong. I've added two int arguments to the constructor of the Tile class, and the program throws the error and warning messages in the code below.

    Any ideas?

    Thanks again!

    Code:
    #include <iostream>
    
    using namespace std;
    
    //Tile Class
    
    class Tile {
    
    //note: Tile:Tile(const Tile&)
    	
    	public:
    	Tile(int x, int y);
    	~Tile();
    	void changeValue( int newValue );
    	void display();
    	int getValue();
    	int getX();
    	int getY();
    	
    	protected:
    	int value;
    	int x;
    	int y;
    	};
    
    Tile::Tile(int myX, int myY) {
    //note : candidates are Tile::Tile(int, int)
    	
    	value = 0;
    	x = myX;
    	y = myY;
    	
    }
    
    Tile::~Tile() {
    	
    	//Destructors do not accept arguments
    }
    
    void Tile::changeValue (int newValue) {
    
    	value = newValue;
    	
    }
    
    int Tile::getValue() {
    	return value;
    }
    
    void Tile::display() {
    	if (value == 0) {
    		cout << "|   ";
    	}
    	if (value == 1) {
    		cout << "| X ";
    	}
    	if (value == -1) {
    		cout << "| 0 ";
    	}
    }
    
    int Tile::getX() {
    	
    	return x;
    }
    
    int Tile::getY() {
    	
    	return y;
    }
    
    //Board Class
    
    class Board {
    	
    public:
    	Board();
    	~Board();
    	void displayBoard();
    	void changeValue(char ox, int x, int y);
    	bool isFinished(int moves);
    	bool boardFull(int moves);
    	bool isLegal(int x, int y);
    	
    protected:
    	Tile board[3][3];
    };
    	
    Board::Board() {
    
    //Error: no matching function for call to 'Tile::Tile()'
    	
    	int i;
    	int j;
    	
    	for (i = 0; i < 3; i++) {
    		for (j = 0; j < 3; j++) {
    			Tile newTile(i, j);
    			board[i][j] = newTile;
    		}
    	}
    }
    
    Board::~Board() {
    	
    }
    
    void Board::displayBoard() {
    	
    	int i;
    	int j;
    	
    	cout << "Noughts and Crosses: \n";
    	
    	cout << "_____________\n";
    	
    	for (i = 0; i < 3; i++) {
    		for (j = 0; j < 3; j++)
    			board[i][j].display();
    		cout << "|";
    		cout << "\n";
    		cout << "-------------\n";
    	}
    }
    	
    void Board::changeValue(char ox, int x, int y) {
    	
    	if (ox == 'X' || ox == 'x') {
    		board[x][y].changeValue(1);
    	}
    	
    	if (ox == '0' || ox == 'o' || ox == 'O'){
    		board[x][y].changeValue(-1);
    	}
    		
    	displayBoard();
    }
    
    bool Board::boardFull(int moves) {
    
    	bool isFull;
    	isFull = 0;
    	
    	if (moves >= 9) {
    		isFull = 1;
    	}
    	else {
    		return isFull;
    	}
    	
    	return isFull;
    }
    		
    
    bool Board::isFinished(int moves) {
    	
    	bool finished = 0;
    	
    	if (boardFull(moves)){
    		finished = 1;
    	}
    	
    	return finished;
    }
    
    
    bool Board::isLegal(int x, int y) {
    	
    	bool isLegal = 0;
    	
    	if (x > 0 && x <= 3 && y > 0 && y <= 3 && board[x-1][y-1].getValue() == 0){
    		isLegal = 1;
    	}
    	return isLegal;
    }
    
    
    int main () {
    	
    	char player;
    	int x;
    	int y;
    	int moves;
    	moves = 0;
    	
    	Board board;
    	board.displayBoard();
    	
    	while (!board.isFinished(moves)){
    		
    		if (moves % 2 == 0) {
    			player = '0';
    		}
    		else {
    			player = 'X';
    		}
    		
    		cout << "Player " << player << " please enter your next move: \n";
    		cout << "X Coordinate: " << endl;
    		cin >> x;
    		cout << "Y Coordinate: " << endl;
    		cin >> y;
    		
    		cin.ignore();
    		
    		//create is legal method
    		
    		if (board.isLegal(x, y)) {
    			board.changeValue(player, x-1, y-1);
    			moves++;
    		}
    		else {
    			cout << "Invalid Move!\n";
    		}
    	}
    	
    	cin.get();
    	cout << "Game Over\n";
    	
    	return 0;
    }
    Last edited by zackKidd; 12-29-2009 at 06:20 PM.

  6. #6
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    The first error, namely
    Code:
    ttt2.cpp:89: error: no matching function for call to ‘Tile::Tile()’
    is because you have an array of Tiles in each Board. (Actually, there's only one error, the other messages are just supporting messages for the same error.)
    Code:
    protected:
    	Tile board[3][3];
    Since you don't specify otherwise in the constructor, these Tiles are initialized with the default constructor (except that these isn't one). There's no way to initialize an array in a constructor initializer list*, so I think the easiest way to resolve this issue is to create a default Tile constructor. You could just use, for example,
    Code:
    // default constructor
    Tile::Tile() {
    	value = 0;
    	x = -1;
    	y = -1;
    }
    * That I know of -- I'd be interested to see what others have to say about this . . . .

    [edit] To be clear: a default constructor is a constructor that takes no parameters. A class can have any number of constructors; in your case you'd need the default one because of reasons outlined above, and the Tile(int, int) one is convenient as well.

    Also: this
    Code:
    			Tile newTile(i, j);
    			board[i][j] = newTile;
    can be written as
    Code:
    			board[i][j] = Tile(i, j);
    but it's exactly the same thing, so don't bother if the syntax is confusing to you.
    [/edit]
    Last edited by dwks; 12-29-2009 at 06:25 PM.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  7. #7
    Registered User
    Join Date
    Dec 2009
    Location
    Brighton
    Posts
    4
    Very interesting, thanks for the help. Had no idea that you could have multiple constructors.

    I just need to clear something up. This line:

    Code:
    protected:
    	Tile board[3][3];
    I thought this was just initialising an array which could store Tile objects, and therefore has no need to access the constructor. Is this actually creating Tile objects and filling the array?

  8. #8
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    Quote Originally Posted by zackKidd View Post
    Very interesting, thanks for the help. Had no idea that you could have multiple constructors.

    I just need to clear something up. This line:

    Code:
    protected:
    	Tile board[3][3];
    I thought this was just initialising an array which could store Tile objects, and therefore has no need to access the constructor. Is this actually creating Tile objects and filling the array?
    The constructor is always called in C++. If you don't write one, the compiler generates it by itself, and calls* that.
    (* Often the generated constructor may do nothing and it may also be inlined, resulting in no additional code in the resulting executable)

    This brings me to another point. You don't need to declare destructors for either of those two classes because neither of them has any additional work to do upon destruction, and they are both public and non-virtual. Removing them makes for cleaner code.

    Note also that variables of type 'bool' should be assigned 'true' or 'false' or something that evaluates to either of those, not 0 or 1, which are integers.

    Very good first attempt with C++! You've nailed OOP in another language already, I imagine.
    The next thing I would suggest learning about is const-correctness.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  9. #9
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Quote Originally Posted by zackKidd View Post
    Very interesting, thanks for the help. Had no idea that you could have multiple constructors.

    I just need to clear something up. This line:

    Code:
    protected:
    	Tile board[3][3];
    I thought this was just initialising an array which could store Tile objects, and therefore has no need to access the constructor. Is this actually creating Tile objects and filling the array?
    As iMalc mentioned, that declaration reserves a 3x3 array of objects, and each object is of type Tile. The thing is, each element of the array has to have an actual value; since each element is of type Tile, it has to call some Tile constructor or another.

    It's different with primitive types like int. If you said
    Code:
    int array[5];
    then you'd have an uninitialized array of integers (unless it was global or something, in which case everything would be initialized to zero). But you can't have an uninitialized object in C++. This is why the new operator automatically calls the constructor, and why C++ doesn't use malloc() like C does. It would be very difficult to write code if some object might not have been initialized.

    To expand on this a little: let's say I had the following class declaration.
    Code:
    class Data {};
    
    class Test {
    private:
        int x;
        Data d;
    public:
        Test();
    };
    Suppose I try to write the Test() default constructor. I might write something like this:
    Code:
    Test::Test() {
        x = 0;
        d = Data();
    }
    The fact is, the "d = Data()" line would be redundant. The Data object has already been initialized by the time the code in the constructor executes! (The same is not true of the int, of course: had we not set this to some value, it would be uninitialized.)

    Actually, what I did in that constructor was member assignment, just ordinary variable assignment. Suppose I used this strange syntax instead:
    Code:
    Test::Test() : x(0), d() {
        // doesn't have to do anything more
    }
    Now x is initialized to 0, and d is initialized to a Data with the default constructor. If I had a Data(int, int) constructor, I could use it like so:
    Code:
    Test::Test() : x(0), d(1, 2) {
        // doesn't have to do anything more
    }
    This is initializing member variables, instead of assigning to them later. This lets you catch the variables before they've been initialized and say how you want them to be initialized.

    Incidentally, this is the only way to initialized const variables. This doesn't work, for example:
    Code:
    class Something {
    private:
        const int x;
    public:
        Something() { x = 42; }
    };
    The compiler will tell you that you're trying to assign a value to a constant variable. If you use this it won't complain.
    Code:
    class Something {
    private:
        const int x;
    public:
        Something() : x(42) {}
    };
    It's like the difference between
    Code:
    const int x = 5;  // initialization
    and
    Code:
    const int x;
    x = 5;  // assignment
    The first works, the second doesn't. Incidentally, if we used
    Code:
    SomeClass x;
    x = SomeClass(3, 2);
    then x would first be assigned a SomeClass() created with the default constructor, and then later on assigned to the SomeClass(3, 2) created with a SomeClass(int, int) constructor.

    Anyway, I think that's enough verbosity for now . . . .
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. tic tac toe check winner
    By dhardin in forum C++ Programming
    Replies: 15
    Last Post: 12-20-2009, 07:57 PM
  2. Help me with my simple Tic tac toe prog
    By maybnxtseasn in forum C Programming
    Replies: 2
    Last Post: 04-04-2009, 06:25 PM
  3. Help with Tic Tac Toe game
    By snef73 in forum C++ Programming
    Replies: 1
    Last Post: 04-25-2003, 08:33 AM
  4. Tic Tac Toe Help
    By aresashura in forum C++ Programming
    Replies: 1
    Last Post: 11-21-2001, 12:52 PM
  5. Replies: 22
    Last Post: 11-08-2001, 11:01 PM