C++ tic tac toe help (true noob)

Started by
7 comments, last by nobodynews 16 years, 10 months ago
Hello. I need help creating a tic tac toe program using vectors. I am confused with the whole thing in general and not sure how to complete it. My problem is when player one says to put X in row 0, column 0, the X doesnt show up (obviously, because i havent put the code there). and that is just the start of my problems. I would appreciate it if someone could help me complete this program, with hints, or the whole code, whatever works :) thank you

#include <iostream>
#include <vector>
using namespace std;

void displayBoard(const vector< vector<char> > &table);
void getMove(vector< vector<char> > &table, char turn);

int main()
{
    char turn;
    
    vector<char>column(3,' ');
    vector< vector<char> > table(3,column);
    
    displayBoard(table);
    getMove(table, turn);
    
    cin.get();
    cin.get();
    return 0;
}


void displayBoard(const vector< vector<char> > &table)
{
	cout << endl;

		for(int row=0;row<table.size();row++)
		{
			for(int col=0;col<table[row].size();col++)
			{
				cout << "[" << table[row][col] << "] ";
			}
			cout << endl;
		}

}



void getMove(vector< vector<char> > &table, char turn)
{
     int row=0;
     int col=0;
     int x=0;
     int y=0;

     cout << turn << ", please enter row of move <0, 1, or 2>: ";
     cin >>row;

     cout << turn << ", please enter column of move <0, 1, or 2>: ";
     cin >> col;


     table[row][col] = x;
}
Advertisement
try to think of your game somewhat like this: you want a player to enter a number, wich should be equal to a space on the board. before you can place the X/O, you need to check to see if there is allready placed a X/O. After each turn you should also check if there is 3 in a row. Instead of using vectors on this particulair project, you should use arrays.
try organizing your tic-tac-toe board like this:

(position)

0 | 1 | 2
----------
3 | 4 | 5
----------
6 | 7 | 8


hope this helps :) try writing down on paper what you want to do codewhise (= psedocode).
•°*”˜˜”*°•.˜”*°•..•°*”˜.•°*”˜˜”*°•..•°*”˜˜”*°•.˜”*°•.˜”*°•. Mads .•°*”˜.•°*”˜.•°*”˜˜”*°•.˜”*°•..•°*”˜.•°*”˜.•°*”˜ ˜”*°•.˜”*°•.˜”*°•..•°*”˜I am going to live forever... or die trying!
No one is going to complete your program for you.

However, we will be more than willing to help if you show a little more enthusiasm towards working out some of your problems on your own.

I can see one problem with your code already, where you have "table[row][col] = x;" you probably meant "table[row][col] = 'x';". With the quotes you are assigning the character x to the row and column. Without the quotes, it is the contents of variable x, which you set to 0 at the start of the function.

Added to that, you will need a loop to make your game playable. We could add a control variable to tell us when the game is over, and loop until its false.

int main(){    char turn;    vector<char>column(3,' ');    vector< vector<char> > table(3,column);    bool gameRunning = true;    while(gameRunning)    {       displayBoard(table);       getMove(table, turn);    }    cin.get();    cin.get();    return 0;}


Note, until we actually add code to detect when a player has won that loop will never end. But its a start.

We also want to alternate between player one and player two. I assume that is the "turn" variable. Lets store instead an enumeration, which is more meaningful:

enum Player {   ONE,   TWO};// other stuff omittedint main(){    Player player = ONE;    vector<char>column(3,' ');    vector< vector<char> > table(3,column);    bool gameRunning = true;    while(gameRunning)    {       displayBoard(table);       getMove(table, player);       if(player == ONE)       {           player = TWO;       }       else // player must be equal to TWO       {           player = ONE;       }    }    cin.get();    cin.get();    return 0;}


We will need to modify getMove to take account of this change:

void getMove(vector< vector<char> > &table, Player player ){     int row=0;     int col=0;     // these are no longer used.     // int x=0;     // int y=0;     cout << player << ", please enter row of move <0, 1, or 2>: ";     cin >>row;     cout << player << ", please enter column of move <0, 1, or 2>: ";     cin >> col;     if( player == ONE )     {        table[row][col] = 'x';     }     else     {        table[row][col] = 'o';     }}


This gives us enough to make an interactive game with.
#include <iostream>#include <vector>using namespace std;enum Player {   ONE,   TWO};void displayBoard(const vector< vector<char> > &table){	    cout << endl;		for(int row=0;row<table.size();row++)		{			for(int col=0;col<table[row].size();col++)			{				cout << "[" << table[row][col] << "] ";			}            cout << endl;		}}void getMove(vector< vector<char> > &table, Player player ){     int row=0;     int col=0;     // these are no longer used.     // int x=0;     // int y=0;     cout << player << ", please enter row of move <0, 1, or 2>: ";     cin >>row;     cout << player << ", please enter column of move <0, 1, or 2>: ";     cin >> col;     if( player == ONE )     {        table[row][col] = 'x';     }     else     {        table[row][col] = 'o';     }}int main(){    Player player = ONE;    vector<char>column(3,' ');    vector< vector<char> > table(3,column);    bool gameRunning = true;    while(gameRunning)    {       displayBoard(table);       getMove(table, player);       if(player == ONE)       {           player = TWO;       }       else // player must be equal to TWO       {           player = ONE;       }    }    cin.get();    cin.get();    return 0;}


You can "play" this game, but you will need to add logic to:

0) prevent players putting a token on a box thats in use
1) detect when the game is over
2) make sure that the player enters a valid row and column
WOW thanks ripoff! That explains a lot. At first glance, i only have one question. What is enum and how does it work into the functions?


enum Player {
ONE,
TWO
};
Quote:Original post by mastern200
WOW thanks ripoff! That explains a lot. At first glance, i only have one question. What is enum and how does it work into the functions?


enum Player {
ONE,
TWO
};


Use [source][/source] to get pretty source boxes [smile].

enum is short for an enumeration. An enumeration is a list of constant values (from the compilers point of view), that are given names meaningful to use.

For example, in a card game we may wish to represent the various suits. We can use an enumeration rather than try remember some obscure convention like heart = 1, spade = 3 etc:
enum Suit {    SPADE, HEART, CLUB, DIAMOND};Suit suit = SPADE;



In our case we have 2 players. You wanted to store the current player in a char variable "turn" for some reason. I assume you were going to set that variable to 1 during player one's turn and 2 during player two's turn. This would have worked, but the more general solution is to use an enumeration (its not so obvious as to which Suit should comes first, in the above list for example).

I think you'll find it easier to work with the symbolic names ONE and TWO. You can test for equality just like you would test an integer (as you have seen already in my code).

As for how they work with functions, they work exactly the same as any other type. We can pass them to functions, return them from functions.

Here is a function you may find useful soon:

#include <string>std::string playerName( Player player ){    if( player == ONE ) {        return "Player One";    } else {        return "Player Two";    }}


We could use that in the getMove function, to print out a more meaningful promt rather than "0, please enter..." we could use
cout << playerName(player) << ", please enter...\n"




This next bit is a bit advanced and slightly irrelevant right now, but is included for completeness.

When compiling, the compiler will give the value 0 to the first element of an enumeration by default. Every subsequent element will have the value of the last one + 1. So in the Suit example SPADE will be 0, and HEART 1, CLUB 2 and DIAMOND 3. We can change the values by manually giving them a number. For example, if for some reason we wished the values to start at 1 we could do this:
enum Suit {   SPADE = 1,   HEART = 2,   CLUB = 3,   DIAMOND = 4};


However, the compiler still follows the rule that if you don't specify a value for an element, it uses the value of the previous one + 1. Knowing this we could re-write the above to get the same effect:
enum Suit {   SPADE = 1,   HEART,    // will be 2   CLUB,     // will be 3   DIAMOND   // will be 4};


However, right now I'm guessing you don't really care what the value of ONE and TWO are, only how to tell which player is currently moving [smile].
thanks! I have i think one more question. I am confused when to use ==, =, |, and ||. Whenever i use one in one place and one in another place, i get a "non lvalue in assignment" error.

#include <iostream>#include <vector>using namespace std;void displayBoard(const vector< vector<char> > &table);void getMove(vector< vector<char> > &table);void winner(vector< vector<char> > &table);int main(){    int x=0;        vector<char>column(3,' ');    vector< vector<char> > table(3,column);        for(x=0;x<=9;x++){    displayBoard(table);    getMove(table);    winner(table);    }        cin.get();    cin.get();    return 0;}void displayBoard(const vector< vector<char> > &table){	cout << endl;		for(int row=0;row<table.size();row++)		{			for(int col=0;col<table[row].size();col++)			{				cout << "[" << table[row][col] << "] ";			}			cout << endl;		}}void getMove(vector< vector<char> > &table){     int row=0;     int col=0;     cout << "X , please enter row of move <0, 1, or 2>: ";     cin >> row;     cout << "X , please enter column of move <0, 1, or 2>: ";     cin >> col;          if(row<0 | row>2 | col<0 | row>2)     {     if(table[row][col]=='x' | table[row][col]=='o'){     cout<<"Sorry, this cannot be accepted. Try again.";     cout<<endl;            cout << "X , please enter row of move <0, 1, or 2>: ";     cin >> row;     cout << "X , please enter column of move <0, 1, or 2>: ";     cin >> col;}}                 table[row][col] = 'x';          displayBoard(table);          cout << "O , please enter row of move <0, 1, or 2>: ";     cin >> row;     cout << "O , please enter column of move <0, 1, or 2>: ";     cin >> col;          if(row<0 | row>2 | col<0 | row>2)     {     if(table[row][col]='x' || table[row][col]='o'){     cout<<"Sorry, this cannot be accepted. Try again.";     cout<<endl;            cout << "O , please enter row of move <0, 1, or 2>: ";     cin >> row;     cout << "O , please enter column of move <0, 1, or 2>: ";     cin >> col;}}          table[row][col] = 'o';}void winner(vector< vector<char> > &table){     if('x' == table[0][0] & 'x' == table[0][1]& 'x' == table[0][2])     {     cout<<"X is the winner!;";     }          if(table[1][0] == 'x' & table[1][1] == 'x' & table[1][2] == 'x')     {     cout<<"X is the winner!;";     }          if(table[2][0] == 'x' & table[2][1] == 'x' & table[2][2] == 'x')     {     cout<<"X is the winner!;";     }          if(table[0][0] == 'x' & table[1][0] == 'x' & table[2][0] == 'x')     {     cout<<"X is the winner!;";     }          if(table[0][1] == 'x' & table[1][1] == 'x' & table[2][1] == 'x')     {     cout<<"X is the winner!;";     }          if(table[0][2] == 'x' & table[1][2] == 'x' & table[2][2] == 'x')     {     cout<<"X is the winner!;";     }          if(table[0][0] == 'x' & table[1][1] == 'x' & table[2][2] == 'x')     {     cout<<"X is the winner!;";     }          if(table[2][0] == 'x' & table[1][1] == 'x' & table[0][2] == 'x')     {     cout<<"X is the winner!;";     }          if(table[0][0] == 'o' & table[0][1] == 'o' & table[0][2] == 'o')     {     cout<<"O is the winner!;";     }          if(table[1][0] == 'o' & table[1][1] == 'o' & table[1][2] == 'o')     {     cout<<"O is the winner!;";     }          if(table[2][0] == 'o' & table[2][1] == 'o' & table[2][2] == 'o')     {     cout<<"O is the winner!;";     }          if(table[0][0] == 'o' & table[1][0] == 'o' & table[2][0] == 'o')     {     cout<<"O is the winner!;";     }          if(table[0][1] == 'o' & table[1][1] == 'o' & table[2][1] == 'o')     {     cout<<"O is the winner!;";     }          if(table[0][2] == 'o' & table[1][2] == 'o' & table[2][2] == 'o')     {     cout<<"O is the winner!;";     }          if(table[0][0] == 'o' & table[1][1] == 'o' & table[2][2] == 'o')     {     cout<<"O is the winner!;";     }          if(table[2][0] == 'o' & table[1][1] == 'o' & table[0][2] == 'o')     {     cout<<"O is the winner!;";     }}


[Edited by - mastern200 on June 12, 2007 3:33:49 PM]
Quote:Original post by mastern200
thanks! I have i think one more question. I am confused when to use ==, =, |, and ||. Whenever i use one in one place and one in another place, i get a "non lword in assignment" error.

*** Source Snippet Removed ***


== is the comparison operator. It compares two values and returns a true or false value that can be used in an expression. For instance, you can use the result in an if/while/for statements. Or you can store the result.

= is either the assignment operator or the initialization operator depending on context. That is:

int a = 10; // initialization
a = 20; // assignment

An l-value is something that you can assign something to. You can't assign a to 20 ( 20 = a; ) because 20 is a constant, for instance.

| and || are very different from each other. | is to be used with two integer types to compare individual bits while || compares two boolean expressions. Basically, don't use | unless you know about how to fiddle with bits. In your case, you won't to compare two expressions like so:

if(row<0 || row>2 || col<0 || row>2)

Same with with & and &&. You can &&. I don't want to go into explaining what & and | does, but I recommend looking up tutorials on 'bitwise operators' which should help you understand what's going on.

Another thing, you can pretty much make the code in your about half the size. Consider this: you check all 8 possible winning combinations for both 'x' and 'o'. Why not make one function that compares each winning combination with a variable? Then you only need to change that variable's contents. That's a little confusing so just see this:
// the const in 'const char plyr' isn't needed, but if you do something like:// plyr = table[0][0] ...// then the compiler will generate an error instead of working, which would// assign the value in table[0][0] to plyr.  Eg., if plyr had 'x' and// table[0][0] had 'o', the code wouldn't work.// Same thing with making the vector table const.  We won't accidently// change the contents of table.void winner(const vector< vector<char> > &table, const char plyr){  if(plyr == table[0][0] && plyr == table[0][1] && plyr == table[0][2])  {    cout << plyr << " is the winner!;";  }  ...


We can make the code even smaller though:
bool winner(const vector< vector<char> > &table, const char plyr){  if(plyr == table[0][0] && plyr == table[0][1] && plyr == table[0][2])  {    return true; // winner!  }  ...  ...  return false; // no winner!}// later:if(winner(table, 'x') ){  cout << "X is the winner!" << endl;}

Hopefully that will give enough information to both fix and improve your code. If not, I'm rewriting it and will post it to a paste site in a little bit.

C++: A Dialog | C++0x Features: Part1 (lambdas, auto, static_assert) , Part 2 (rvalue references) , Part 3 (decltype) | Write Games | Fix Your Timestep!

Ahh ok i understand now. Thanks. The people in this forum are awesome! Two more questions though. Assuming that i use the same code i posted before (not the shorter, but better version posted above me. i am trying to get a feel for both ways), how would i get my winner function to work (the old one). i feel like its written correctly, but im missing something. and why wont the "Sorry, this space has been taken already" statement wont work when i run the program? ive been stuck on those two issues for a while...
There are really 3 different things you're trying to do when making sure you have valid input.
1)Is the row in a valid range?
2)Is the column in a valid range?
3)Has anyone moved in this spot before?

What I think you should do is something like this:

do  while row is invalid    get row  while column is invalid    get columnwhile spot chosen isn't empty


Your logic right now is a little complicated and you don't really do any loops to make sure the input is correct.

Your winning function is pretty good, it could probably be simplified with loops. But not That much simpler. Anyway, I changed my mind with the code paste site because it's not that long and you can just ignore it.
#include <iostream>#include <vector>using namespace std;void displayBoard(const vector< vector<char> > &table);void getMove(vector< vector<char> > &table, const char player);bool winner(const vector< vector<char> > &table, const char player);int main(){	vector<char> column(3,' ');	vector< vector<char> > table(3,column);	// By using an array we can switch between players	// programmatically instead of hard coding it	char player[2] = {'x', 'o'};	int cur_player = 0; // start with player 'x'	// there are 9 places on the board, so you get as much as 9 moves. Don't forget,	// zero is included so we stop before we get to 9	for(int x = 0; x < 9; x++){		displayBoard(table);		getMove(table, player[cur_player]);		// check for a winner.  If there was, say so and break out of the loop		if( winner(table, player[cur_player]) )		{			cout << player[cur_player] << " is the winner!" << endl;			break; // there was a winner, quit playing		}		// switch between players 0 and 1. Do the math and you should figure it out!		cur_player = (cur_player + 1) % 2;	}	return 0;}void displayBoard(const vector< vector<char> > &table){	for(unsigned int  row = 0; row < table.size(); row++)	{		for(unsigned int col = 0; col < table[row].size(); col++)		{ cout << "[" << table[row][col] << "] "; }		cout << endl;	}}void getMove(vector< vector<char> > &table, const char player){	int row=-1, col=-1;	bool running = true;	while(running)	{		while(row < 0 || row > 2)		{			cout << player << ", please enter row of move <0, 1, or 2>: ";			cin >> row;		}		while(col < 0 || col > 2)		{			cout << player << ", please enter column of move <0, 1, or 2>: ";			cin >> col;		}		// if spot was open, put the symbol at that place and exit loop		// otherwise, give an error and repeat		if(table[row][col] == ' ')		{			table[row][col] = player;			running = false;		}		else		{			cout<<"Sorry, this spot cannot be accepted. Try again." << endl;		}	}}bool winner(const vector< vector<char> > &table, const char player){	if(table[0][0] == player && table[0][1] == player && table[0][2] == player)		return true;	if(table[1][0] == player && table[1][1] == player && table[1][2] == player)		return true;	if(table[2][0] == player && table[2][1] == player && table[2][2] == player)		return true;	if(table[0][0] == player && table[1][0] == player && table[2][0] == player)		return true;	if(table[0][1] == player && table[1][1] == player && table[2][1] == player)		return true;	if(table[0][2] == player && table[1][2] == player && table[2][2] == player)		return true;	if(table[0][0] == player && table[1][1] == player && table[2][2] == player)		return true;	if(table[2][0] == player && table[1][1] == player && table[0][2] == player)		return true;	return false; // player didn't win.}

C++: A Dialog | C++0x Features: Part1 (lambdas, auto, static_assert) , Part 2 (rvalue references) , Part 3 (decltype) | Write Games | Fix Your Timestep!

This topic is closed to new replies.

Advertisement