• Welcome to League Of Reason Forums! Please read the rules before posting.
    If you are willing and able please consider making a donation to help with site overheads.
    Donations can be made via here

My tic-tac-toe display/core

CosmicJoghurt

New Member
arg-fallbackName="CosmicJoghurt"/>
Hey there.

I made a C++ Tic Tac Toe core/display. It's basically the function that prints the board, with a 3x3 array to store X's and O's. It's fully functional... for now.
Code:
#include <iostream>
#include <string>
using namespace std;
/* Displaying the board works the following way:
 There's a 3x3 array to hold the X/O's for the board.
 First, the pBoard function prints the initial line of the tic-tac-toe board.
 This initial line is printed every time a horizontal set of 3 X/O's is done printing.
 Then, the actual X/O printing starts at the 1x1 spot of the board/array[0][0]. 
 It prints each X/O's first line, in
 the first set of 3 horizontal X/O's of the board. Then it does the same for each of the two remaining sets of 3 X/O's
 in the board. When it's done printing any of the lines for each set of 3 X/O's,
 it prints the final character of each line, a '|'. It's part of the outline of the board.
 */


/* Creating the strings for circles, crosses, empty rooms, the final board column and
 the lines in between of each line of three X/O spots.*/
string bCircle1 = "|/  \\"; // For the printing of each X/O there are two lines:
string bCircle2 = "|\\  /"; 
string bCross1 = "| \\/ ";
string bCross2 = "| /\\ ";
string bEmpty = "|    ";
string bColumn = "|"; // When the X/O are done printing we need the last column of the board to be printed;
string bLine = " ---- ---- ----"; //
int line = 0; // Current line (to use with 3x3 X/O array which stores data from [0][0])
int column = 0; // Current column (/*/)
int bLoop = 1; // Determines which one of the cross/circle *cout*'s is executed.


void pBoard(void){ 
	int n1 = 1;
	string spot[3][3];
	spot[0][0] = "X"; // 3x3 array to store players' X/O's.
	spot[1][0] = " "; // Example.
	spot[2][0] = " ";
	spot[0][1] = "O";
	spot[1][1] = " ";
	spot[2][1] = " ";
	spot[0][2] = "X";
	spot[1][2] = " ";
	spot[2][2] = " ";
	
	/* Function to be called for showing the current board */
	for (int c = 0; c<3; c++) // One iteration of the *for* loop for each line of X/O's.
	{
		if (n1 == 1){ // Only displays bLine once, since it displays at the end of each X/O line.
			cout << bLine << endl;// Line in between of each set of X/O's and at the beginning of each board.
		}
		for (int b = 0; b<2; b++){ // Each X/O has two lines for /'s and \'s.
			for (int a = 0; a<3; a++) { // One iteration of the *for* loop for each X/O.
				if (spot[line][column] == "X") { // Checks if current spot has an X/O/nothing on it.
					if (bLoop == 1){
						cout << bCross1; // First line for the X.
					}
					else if (bLoop == 2){
						cout << bCross2; // Second line for the X.
					}
					
					
				}
				if (spot[line][column] == "O") { // Same here.
					if (bLoop == 1){
						cout << bCircle1;
					}
					else if (bLoop == 2){
						cout << bCircle2;
					}
					
					
				}
				
				if (spot[line][column] == " ") { // Same.
					if (bLoop == 1){
						cout << bEmpty;
					}
					else if (bLoop == 2){
						cout << bEmpty;
					}
					
					
				}
				column++; // When it's done with printing an X/O/nothing - line, increase the column variable;
			}
			cout << bColumn << endl; // Print the last column of the board.
			column = 0; // Reset the column to 0 (remember, the 3x3 array stores from [0][0], not [1][1];
			bLoop++; // Increase bLoop when the first line of the first set of X/O's is done printing, so it prints the second part of each X/O.
			if (b == 1) { // If the twice-looping loop is finishing the second and last iteration, reset bLoop so the next set of X/O's is well printed.
				bLoop = 1;
			}
		}
		cout << bLine << endl; // Line in between of each of the 3 sets of X/O's.
		line++; // Move on, print the second set of X/O's.
		n1++; // Makes sure the initial bLine is never printed again.
	}
	
}



int main (int argc, char * const argv[]) {
	pBoard();
	return 0;
	
}

Yes, i am aware that it isn't optimized, it's dirty, it's confusing... I'll work on cleanness later. But it's filled with comments for explanation purposes.

Anyways, I'd like some advice. Is there anything in particular that should be cleaned?

Beware, I've spent about half a dozen hours on this, it's messy. That's what you get for fixing a bugged display at 5:30 AM with the sun rising.

And yes, I'm aware everyone makes a tictactoe game. So quit it.
 
arg-fallbackName="Master_Ghost_Knight"/>
A) Since it is c++ you can take benefit of the class and make a board class (I guess that is the only class you can make).

B) Do not use global variables or variables to store constant items that are defined a priori. Use the method define instead.
Example:
string bCircle1 = "|/ \\";
should be:
#define CIRCLE1 "|/ \\"

C) Do not initiate the variables with a "b" if they are not bolean, it may get quite confusing.
I find no reason why there should be a global variable for line and column for 2 reasons:
1. They are only used in 1 function and they are not used to store information between functions
2. You are already using a local variable that alredy does the job of counting lines and columns.

D) If you are performing short counts use "char" instead of "int" because int takes 4 bytes while char takes only 1.
You might find this strange because "char" is commonly used to store characters, but that is more of a use we give it than an actual restriction. It is stil a byte and you can use it exactly like a int but only shorter.

E) Avoid pointless checks like this:
if (bLoop == 1){
cout << bCircle1;
}
else if (bLoop == 2){
cout << bCircle2;
}

bLoop can only take either the value 1 or 2, if it is not one then it is 2, so if you make it like this:
if (bLoop == 1) cout << bCircle1;
else cout << bCircle2;
It works as fine.

And pay attention because:
if (spot[line][column] == " ") { // Same.
if (bLoop == 1){
cout << bEmpty;
}
else if (bLoop == 2){
cout << bEmpty;
}
}
It is totaly pointless since whatever bLoop is it is allways going to perform the same function so you just have to straight up do this:
if (spot[line][column] == " ") cout << bEmpty;

This last if was even pointless because you could have chained it with else's and you would have saved one check:
if (spot[line][column] == "X") { // Checks if current spot has an X/O/nothing on it.
//code
}
else if (spot[line][column] == "O") {
//code
}

else{ //for when spot[line][column] == " ".
//code
}

And if you want to be really awsome, if you have multiple "if" statments use switch instead:
switch (spot[line][column] ){
case 'O': //code;
break;
case 'X': //code;
break;
default: //code;
}

F) There is no reason why you should start counting bLoop in 1 and not in 0.

I have a question. Are you doing this for windows or linux?
If you are using windows then we can hookup some directx on that thing and cranck up the graphics.
And we can crankup some IP protocols on that and have 2 people playing against each other online in no time.

That is all i got so far.
 
arg-fallbackName="Snufkin"/>
Good stuff, and nice commentary Master_Ghost_Knight.
I disagree with a few of your points, but the only one I think is worth mentioning is this:
B) Do not use global variables or variables to store constant items that are defined a priori. Use the method define instead.

I agree with avoiding globals - but #define is worse than globals at document level because you can't even limit its scope with namespaces.
In general the preprocessor is avoided in modern C++ unless there's no alternative, text substitution can lead to some surprising problems.

I'd recommend using const variables in the smallest scope possible instead.
const std::string circle = "O";
 
arg-fallbackName="CosmicJoghurt"/>
Very helpful. However...
A) Since it is c++ you can take benefit of the class and make a board class (I guess that is the only class you can make).

Yes, but what's the advantage of that for this particular case?
2. You are already using a local variable that alredy does the job of counting lines and columns.

I'm not :? line and column store the current line/column for printing, I don't think I have any other variables for that.
D) If you are performing short counts use "char" instead of "int" because int takes 4 bytes while char takes only 1.
You might find this strange because "char" is commonly used to store characters, but that is more of a use we give it than an actual restriction. It is stil a byte and you can use it exactly like a int but only shorter.

So you mean that as advice for a matter of efficiency? Advice accepted.
And if you want to be really awsome, if you have multiple "if" statments use switch instead:
switch (spot[line][column] ){
case 'O': //code;
break;
case 'X': //code;
break;
default: //code;
}

The last time I did that it got angry and told me I couldn't put anything besides integers in each -case-. I think...? I'll give it a try.
Are you doing this for windows or linux?

OS X. I am, however more inclined to gain some experience building command line apps before I get into graphics. I'm thinking java afterwards... ever since I realized Minecraft was in Java :roll:

Any ideas for graphics libraries and stuff for OS X, later? I think OpenGL is multi-platform... is it not?
And we can crankup some IP protocols on that and have 2 people playing against each other online in no time.

Good idea. I found an amazing (!) tutorial on network programming a while ago, but I lost the link... it was so exciting... it went from the start, explained what TCP, UDP were, IPv4, IPv6, everything... damn it, freaking safari auto deleting history.

Anyways, my goal for now is to gain some experience in C++, for a good understanding of not only programming concepts in general, but gaming concepts, and OOP experience... All this for a hobby, though.
In general the preprocessor is avoided in modern C++ unless there's no alternative, text substitution can lead to some surprising problems.

For example.....?
 
arg-fallbackName="Master_Ghost_Knight"/>
CosmicJoghurt said:
Very helpful. However...
A) Since it is c++ you can take benefit of the class and make a board class (I guess that is the only class you can make).
Yes, but what's the advantage of that for this particular case?
In this particular case nothing because your program just does one single function, and there is no problem doing it without any class at all.
But when you have extra functions, players trying to update the state of the game, the code becomes cleaner and easier.
CosmicJoghurt said:
2. You are already using a local variable that alredy does the job of counting lines and columns.
I'm not :? line and column store the current line/column for printing, I don't think I have any other variables for that.
You do but you just haven't noticed. If you take a closer look the variable "a" counts columns, the variable "b" counts sub-lines (line 1 and line 2 of just one line of the matrix), and the variable "c" counts lines. You even gave yourself the trouble of commenting it.
CosmicJoghurt said:
The last time I did that it got angry and told me I couldn't put anything besides integers in each -case-. I think...? I'll give it a try.
switch can work with int as well as with char. It does not work however with strings.
So you cannot make a list of commands and use a switch to find the proper match.
CosmicJoghurt said:
Any ideas for graphics libraries and stuff for OS X, later? I think OpenGL is multi-platform... is it not?
Yes OpenGL is multi-platform. I never worked with OS X so I can't help you much on the specifics, and they will be important when you will have to multi-thread and establish internet connections (because the libraries to do that change from OS to OS).
 
arg-fallbackName="Master_Ghost_Knight"/>
Snufkin said:
Here's an example (grabbed from SO):
#define square(x) x*x
a = square(2+3)
After this a is 11.

Well yeah, because
a = square(2+3)
is going to be replaced by the rule:
#define square(x) x*x
and becomes:
a = 2+3*2+3
if you have done this instead:
#define square(x) (x)*(x)
there wouldn't be a problem.
But that is not what he is using. I haven't sugested to construct functions out of defines (altough sometimes it is ok).
As long as you remember what #define means there shouldn't be a problem, however I do see when it sometimes can get confusing.
 
arg-fallbackName="Snufkin"/>
Yes OpenGL is multi-platform. I never worked with OS X so I can't help you much on the specifics, and they will be important when you will have to multi-thread and establish internet connections (because the libraries to do that change from OS to OS).
I strongly recommend Qt if you want to do cross platform C++ programming.
It comes with platform abstracted windowing, networking, an IDE (which you don't have to use), lots of other high level stuff and it is well documented.
 
arg-fallbackName="CosmicJoghurt"/>
You do but you just haven't noticed. If you take a closer look the variable "a" counts columns, the variable "b" counts sub-lines (line 1 and line 2 of just one line of the matrix), and the variable "c" counts lines. You even gave yourself the trouble of commenting it.

Ah, you're right... I'll rename the three variables to proper names and do the work that needs to be done.

Updated source code will be posted sometime today.
 
arg-fallbackName="Master_Ghost_Knight"/>
There is another issue that I have only noticed now:
void pBoard(void){
int n1 = 1;
//code
if(n1==1) //code
//code
n1++;
//exits function
}

The variable n1 isn't doing anything. It is a local variable and it is destroyed when the function ends (so the value isn't preserved).
Next time you will call that function is going to be re-initiated with n1=1. To preserver the value you can use the method static instead:
static int n1=1;
that way the variable n1 is not going to be destroyed once the function is over, it will not be reinitiated with 1, and the value is stored just like with a global variable.
Plus there is no reason why you should only allow yourself to do that function only once ever, so it is better that you get rid of it altogheter.
 
arg-fallbackName="CosmicJoghurt"/>
The variable n1 isn't doing anything. It is a local variable and it is destroyed when the function ends (so the value isn't preserved).
Next time you will call that function is going to be re-initiated with n1=1. To preserver the value you can use the method static instead:
static int n1=1;
that way the variable n1 is not going to be destroyed once the function is over, it will not be reinitiated with 1, and the value is stored just like with a global variable.
Plus there is no reason why you should only allow yourself to do that function only once ever, so it is better that you get rid of it altogheter.

It does do something. It makes sure that the initial bLine is only printed once. If n1 didn't exist, in the between of each set of 3 horizontal X/O's there would be two bLines, which kind of fucks up the board design. At the end of the first for loop, it does n1++ so the if statement that prints the initial bLine is never run again.

EDIT: Nevermind, I already have another variable to do that... Fixed!
 
arg-fallbackName="CosmicJoghurt"/>
Fixed code:
[ShowMore=]
Code:
#include <iostream>
#include <string>
using namespace std;
/* Displaying the board works the following way:
 There's a 3x3 array to hold the X/O's for the board.
 First, the pBoard function prints the initial line of the tic-tac-toe board.
 This initial line is printed every time a horizontal set of 3 X/O's is done printing.
 Then, the actual X/O printing starts at the 1x1 spot of the board/array[0][0]. 
 It prints each X/O's first line, in
 the first set of 3 horizontal X/O's of the board. Then it does the same for each of the two remaining sets of 3 X/O's
 in the board. When it's done printing any of the lines for each set of 3 X/O's,
 it prints the final character of each line, a '|'. It's part of the outline of the board.
 */


/* Creating the strings for circles, crosses, empty rooms, the final board column and
 the lines in between of each line of three X/O spots.*/
string bCircle1 = "|/  \\"; // For the printing of each X/O there are two lines:
string bCircle2 = "|\\  /"; 
string bCross1 = "| \\/ ";
string bCross2 = "| /\\ ";
string bEmpty = "|    ";
string bColumn = "|"; // When the X/O are done printing we need the last column of the board to be printed;
string bLine = " ---- ---- ----";


void pBoard(void){ 
	string spot[3][3];
	spot[0][0] = "X"; // 3x3 array to store players' X/O's.
	spot[1][0] = " "; // Example.
	spot[2][0] = " ";
	spot[0][1] = "O";
	spot[1][1] = " ";
	spot[2][1] = " ";
	spot[0][2] = "X";
	spot[1][2] = " ";
	spot[2][2] = " ";
	
	/* Function to be called for showing the current board */
	for (int line = 0; line<3; line++) // One iteration of the *for* loop for each line of X/O's.
	{
		if (line == 0){ // Only displays bLine once, since it displays at the end of each X/O line.
			cout << bLine << endl;// Line in between of each set of X/O's and at the beginning of each board.
		}
		for (int b = 0; b<2; b++){ // Each X/O has two lines for /'s and \'s.
			for (int column = 0; column<3; column++) { // One iteration of the *for* loop for each X/O.
				if (spot[line][column] == "X") { // Checks if current spot has an X/O/nothing on it.
					if (b == 0)
						cout << bCross1; // First line for the X.
					else
						cout << bCross2; // Second line for the X.
				}
				else if (spot[line][column] == "O") {
					if (b == 0)
						cout << bCircle1;
					else
						cout << bCircle2;
				}
				
				else 
					cout << bEmpty;
				
			}
			cout << bColumn << endl; // Print the last column of the board.
		}
		cout << bLine << endl; // Line in between of each of the 3 lines of X/O's.
	}
	
}



int main (int argc, char * const argv[]) {
	pBoard();
	return 0;
	
}
[/ShowMore]


I decided not to use a switch statement, too much work, I want to use strings. :twisted:

Anyways, a question: Is there a difference between using 'something' and "something"?

Also, I have a question regarding cin.ignore() for other projects, if anyone has experience with it, let me know, I'll post the question.
 
arg-fallbackName="Master_Ghost_Knight"/>
CosmicJoghurt said:
It does do something. It makes sure that the initial bLine is only printed once. If n1 didn't exist, in the between of each set of 3 horizontal X/O's there would be two bLines, which kind of fucks up the board design. At the end of the first for loop, it does n1++ so the if statement that prints the initial bLine is never run again.
In that case take it out of the loop and execute:
cout << bLine << endl;
before the the for.

This is how I would correct the code:
Code:
#include <iostream>
#include <string>
using namespace std;
/* Displaying the board works the following way:
 There's a 3x3 array to hold the X/O's for the board.
 First, the pBoard function prints the initial line of the tic-tac-toe board.
 This initial line is printed every time a horizontal set of 3 X/O's is done printing.
 Then, the actual X/O printing starts at the 1x1 spot of the board/array[0][0]. 
 It prints each X/O's first line, in
 the first set of 3 horizontal X/O's of the board. Then it does the same for each of the two remaining sets of 3 X/O's
 in the board. When it's done printing any of the lines for each set of 3 X/O's,
 it prints the final character of each line, a '|'. It's part of the outline of the board.
 */


/* Creating the strings for circles, crosses, empty rooms, the final board column and
 the lines in between of each line of three X/O spots.*/
string CSCircle1 = "|/  \\"; // For the printing of each X/O there are two lines:
string CSCircle2 = "|\\  /"; 
string CSCross1 = "| \\/ ";
string CSCross2 = "| /\\ ";
string CSEmpty = "|    ";
string CSColumn = "|"; // When the X/O are done printing we need the last column of the board to be printed;
string CSLine = " ---- ---- ----";
char spot[3][3];

void pBoard(void){ 
	spot[0][0] = 'X'; // 3x3 array to store players' X/O's.
	spot[1][0] = ' '; // Example.
	spot[2][0] = ' ';
	spot[0][1] = 'O';
	spot[1][1] = ' ';
	spot[2][1] = ' ';
	spot[0][2] = 'X';
	spot[1][2] = ' ';
	spot[2][2] = ' ';
	
	/* Function to be called for showing the current board */
	cout << CSLine << endl;// Line in between of each set of X/O's and at the beginning of each board.
	for (char line = 0; line<3; line++) // One iteration of the *for* loop for each line of X/O's.
	{
		for (char column = 0; column<3; column++) { // One iteration of the *for* loop for each X/O.
			if (spot[line][column] == 'X') cout << CSCross1; // First line for the X.
			else if (spot[line][column] == 'O') cout << CSCircle1;
			else cout << CSEmpty;	
			}
		cout << CSColumn << endl; // Print the last column of the board.
		for (column = 0; column<3; column++) { // One iteration of the *for* loop for each X/O.
			if (spot[line][column] == 'X') cout << CSCross2; // Second line for the X.
			else if (spot[line][column] == 'O') cout << CSCircle2;
			else cout << CSEmpty;	
		}
		cout << CSColumn << endl; // Print the last column of the board.
		cout << CSLine << endl; // Line in between of each of the 3 lines of X/O's.
	}
}



int main (int argc, char * const argv[]) {
	pBoard();
	return 0;	
}
 
arg-fallbackName="Master_Ghost_Knight"/>
CosmicJoghurt said:
Anyways, a question: Is there a difference between using 'something' and "something"?
Yes. "Stuff\0" is used for strings (be carefull with the nasty habit of not terminaing a string with \0, explicit use of \0 will save you allot of trouble)
'C' is notmaly used for a single char.
CosmicJoghurt said:
Also, I have a question regarding cin.ignore() for other projects, if anyone has experience with it, let me know, I'll post the question.
http://www.cplusplus.com/reference/iostream/istream/ignore/

Edit: Code using switches
Code:
#include <iostream>
#include <string>
using namespace std;
/* Displaying the board works the following way:
There's a 3x3 array to hold the X/O's for the board.
First, the pBoard function prints the initial line of the tic-tac-toe board.
This initial line is printed every time a horizontal set of 3 X/O's is done printing.
Then, the actual X/O printing starts at the 1x1 spot of the board/array[0][0]. 
It prints each X/O's first line, in
the first set of 3 horizontal X/O's of the board. Then it does the same for each of the two remaining sets of 3 X/O's
in the board. When it's done printing any of the lines for each set of 3 X/O's,
it prints the final character of each line, a '|'. It's part of the outline of the board.
*/


/* Creating the strings for circles, crosses, empty rooms, the final board column and
the lines in between of each line of three X/O spots.*/
string CSCircle1 = "| /\\ "; // For the printing of each X/O there are two lines:
string CSCircle2 = "| \\/ ";
string CSCross1 = "| \\/ ";
string CSCross2 = "| /\\ ";
string CSEmpty = "|    ";
string CSColumn = "|"; // When the X/O are done printing we need the last column of the board to be printed;
string CSLine = " ---- ---- ----";
char spot[3][3];

void pBoard(void){ 
	spot[0][0] = 'X'; // 3x3 array to store players' X/O's.
	spot[1][0] = ' '; // Example.
	spot[2][0] = ' ';
	spot[0][1] = 'O';
	spot[1][1] = ' ';
	spot[2][1] = ' ';
	spot[0][2] = 'X';
	spot[1][2] = ' ';
	spot[2][2] = ' ';

   /* Function to be called for showing the current board */
	cout << CSLine << endl;// Line in between of each set of X/O's and at the beginning of each board.
	for (char line = 0; line<3; line++){ // One iteration of the *for* loop for each line of X/O's.
		for (char column = 0; column<3; column++) { // One iteration of the *for* loop for each X/O.
			switch (spot[line][column]){
				case 'X': cout << CSCross1; break;
				case 'O': cout << CSCircle1; break;
				default: cout << CSEmpty;
			}
		}
		cout << CSColumn << endl; // Print the last column of the board.
		for (column = 0; column<3; column++) { // One iteration of the *for* loop for each X/O.
			switch (spot[line][column]){
				case 'X': cout << CSCross2; break;
				case 'O': cout << CSCircle2; break;
				default: cout << CSEmpty;
			}
		}
		cout << CSColumn << endl << CSLine << endl; // Line in between of each of the 3 lines of X/O's.
	}
}

int main (int argc, char * const argv[]){
	pBoard();
	return 0;   
}
 
arg-fallbackName="CosmicJoghurt"/>
So I'm making it a one-player version, one player can change the X's and O's as he wants. It's a prototype for a two player version, which then will be made into an online 2 player version! (hopefully).

But... PROBLEM!

I have two files now, a Board.h file with the Board class and functions and stuff, and the main.cpp.
Code:
/*
 *  Board.h
 *  C++ Practice Program #1
 *
 *  Created by CosmicJoghurt on 8/25/11.
 *  Copyright 2011 __MyCompanyName__. All rights reserved.
 *
 */

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


/* Creating the strings for circles, crosses, empty rooms, the final board column and
 the lines in between of each line of three X/O spots.*/
string Circle1 = "|/  \\"; // For the printing of each X/O there are two lines:
string Circle2 = "|\\  /"; 
string Cross1 = "| \\/ ";
string Cross2 = "| /\\ ";
string Empty = "|    ";
string Column = "|"; // When the X/O are done printing we need the last column of the board to be printed;
string Line = " ---- ---- ----";

class Board {
public:
	char spot[3][3];
	Board(char spot2[3][3]);
	void pBoard(void);
	void pInstructions(void);
};


	
	


void Board::pBoard(void){		/* Function to be called for showing the current board */
	for (int line = 0; line<3; line++) // One iteration of the *for* loop for each line of X/O's.
	{
		if (line == 0){ // Only displays bLine once, since it displays at the end of each X/O line.
			cout << Line << endl;// Line in between of each set of X/O's and at the beginning of each board.
		}
		for (int b = 0; b<2; b++){ // Each X/O has two lines for /'s and \'s.
			for (int column = 0; column<3; column++) { // One iteration of the *for* loop for each X/O.
				switch (spot[line][column]) {
					case 'X':
						if (b == 0)
							cout << Cross1; // First line for the X.
						else
							cout << Cross2; // Second line for the X.
						break;
					case 'O':
						if (b == 0)
							cout << Circle1;
						else
							cout << Circle2;
						break;
					default:
						cout << Empty;
						break;
				}
				
			}
			cout << Column << endl; // Print the last column of the board.
		}
		cout << Line << endl; // Line in between of each of the 3 lines of X/O's.
	}
	
}



void Board::pInstructions(void){
	cout << "Welcome to Tic-Tac-Toe!\nThis is the initial, empty board:\n";
	pBoard();
	cout << "Each player will be asked to indicate which line and column they'll play.\n";
	cout << "This is a line ---------------------->\n";
	cout << "This is a column\n";
	cout << "       |\n";
	cout << "       |\n";
	cout << "       |\n";
	cout << "       |\n";
	cout << "       |\n";
	cout << "       |\n";
	cout << "       |\n";
	cout << "       |\n";
	cout << "       |\n";
	cout << "       |\n";
	cout << "       V\n";
}
Code:
#include <iostream>
#include <string>
#include "Board.h"
using namespace std;
/* Displaying the board works the following way:
 There's a 3x3 array to hold the X/O's for the board.
 First, the pBoard function prints the initial line of the tic-tac-toe board.
 This initial line is printed every time a horizontal set of 3 X/O's is done printing.
 Then, the actual X/O printing starts at the 1x1 spot of the board/array[0][0]. 
 It prints each X/O's first line, in
 the first set of 3 horizontal X/O's of the board. Then it does the same for each of the two remaining sets of 3 X/O's
 in the board. When it's done printing any of the lines for each set of 3 X/O's,
 it prints the final character of each line, a '|'. It's part of the outline of the board.
 */
char mainSpot[3][3];

Board::Board(char spot2[3][3]){
	spot[0][0] = spot2[0][0]; // 3x3 array to store players' X/O's.
	spot[1][0] = spot2[1][0]; // Example.
	spot[2][0] = spot2[2][0];
	spot[0][1] = spot2[0][1];
	spot[1][1] = spot2[1][1];
	spot[2][1] = spot2[2][1];
	spot[0][2] = spot2[0][2];
	spot[1][2] = spot2[1][2];
	spot[2][2] = spot2[2][2];
}

int main (int argc, char * const argv[]) {
	Board board(mainSpot[][3]);
	board.pInstructions();
	bool lValid, cValid;
	char pLine, pColumn;
	bool gameOver;
	while (gameOver == 0) {
		board.pBoard();
		pLine = 0;
		pColumn = 0;
		cout << "Player 1 - it's your turn to play!\n";
		while (lValid == 0) {
			cout << "Choose a line from 1-3!\n";
			cin >> pLine;
			if (pLine <= 3 | pLine >= 1) {
				lValid = 1;
			}
		}
		while (cValid == 0) {
			cout << "Choose a column from 1-3!\n";
			cin >> pColumn;
			if (pLine <= 3 | pLine >= 1) {
				cValid = 1;
			}
		}
		mainSpot[pLine][pColumn] = 'X';
		cValid = 0;
		lValid = 0;
		
	}
	
	return 0;
	
}

And I get a "expected primary expression before ']' token" at the first line of int(). What gives?

Oh, the fillArray() function is a function that takes a database of X/O's from the int function and pass it as an argument for the Board class. Because I can't create a global X/O database, I have to work with two and do that.

I know it isn't good, it's horribly coded, but, please deal with the problem first, then the other small corrections if possible :lol:

Any questions?
 
arg-fallbackName="Master_Ghost_Knight"/>
CosmicJoghurt said:
And I get a "expected primary expression before ']' token" at the first line of int(). What gives?
This is a more complicated error than what one might expect.
This error specificaly happens because you have this:
Board board(mainSpot[][3]);
but if you had this:
Board board(mainSpot[0][3]);
you wouldn't get that error, because if you define an acess to a slot on the memory hep you must define which slot.
Notice that I have refrained myself from saying "you should have this" because you shouldn't, that would efectively just send the content stored on mainspot[0][3] and not the acess to the entire matrix (which is what you want), and therefore you would get another error. Instead, this would work:
Board board(mainSpot);
Altough you can, this isn't what you are supoused to do either because you have defined "mainSpot" as a global variable and you don't need to do any of that. Why do you even need that global variable?
If you are going to define that global variable why not just skip the entire board class? I know I have sugested before, but on second taught I recognise that it ws a bad idea, the program is way to short to take any advantage from classes.
But if you want to keep doing it anyways, here is a couple of advices. Use the method inline so you have to save unecessary function calls.
1. Change the name of the function "pBoard" to "show", so you can do "board.show" like a boss.
2. Put the matrix state (i.e. the variale spot) to private and create the followig function "set(line,column, bool x_o)" to update the state and returns bool (or char) if either suceeded or failed (fail must depend if slot has already be taken or not, preventing the player from playing on a previously used slot). Implement a function "reset" to reset the board and ready for a new game.
3. Implement a check_win to check if a player has won the game, returning either X, O or none.
4. Remove the function "pInstructions" because that doesn't belong there

And finaly, you have defined the class but you are updating your boad on the global variable and not on the class.
ie. you are doing this: "mainSpot[pLine][pColumn] = 'X'" which doesn't change the class board at all.

Sorry for misleading you.
But my advice now is, forget the classes, it is to short to help you and until now just made you understand less of what you were doing.
 
arg-fallbackName="CosmicJoghurt"/>
So, I kept using classes - just because I want to get used to their workings.

Anyways, I implemented a spot-occupation checking system, and everything... but the program won't let me move on from "Choose a line from 1-3!". It thinks my input is invalid, for some strange reason...

Have a look :)
Code:
/*
 *  Board.h
 *  C++ Practice Program #1
 *
 *  Created by CosmicJoghurt on 8/25/11.
 *  Copyright 2011 __MyCompanyName__. All rights reserved.
 *
 */

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


/* Creating the strings for circles, crosses, empty rooms, the final board column and
 the lines in between of each line of three X/O spots.*/
string Circle1 = "|/  \\"; // For the printing of each X/O there are two lines:
string Circle2 = "|\\  /"; 
string Cross1 = "| \\/ ";
string Cross2 = "| /\\ ";
string Empty = "|    ";
string Column = "|"; // When the X/O are done printing we need the last column of the board to be printed;
string Line = " ---- ---- ----";

class Board {
	char spot[3][3];
public:
	bool set(int,int,bool);
	void show(void);
	void pInstructions(void);
}board;

bool Board::set(int line, int column, bool x_o){
	bool spotOccupied;
	int fLine, fColumn;
	fLine = --line;
	fColumn = --column;
	if (spot[fLine][fColumn] != 'X' && spot[fLine][fColumn] != 'O'){
		if (x_o) {
			spot[fLine][fColumn] = 'X';
		}
		else {
			spot[fLine][fColumn] = 'O';
		}
	}
	else {
		spotOccupied = 1;
		cout << "Spot is already occupied! Choose another spot!\n";
	}
	return spotOccupied;
}
	
	
	void Board::show(void){		/* Function to be called for showing the current board */
		for (int line = 0; line<3; line++) // One iteration of the *for* loop for each line of X/O's.
		{
			if (line == 0){ // Only displays bLine once, since it displays at the end of each X/O line.
				cout << Line << endl;// Line in between of each set of X/O's and at the beginning of each board.
			}
			for (int b = 0; b<2; b++){ // Each X/O has two lines for /'s and \'s.
				for (int column = 0; column<3; column++) { // One iteration of the *for* loop for each X/O.
					switch (spot[line][column]) {
						case 'X':
							if (b == 0)
								cout << Cross1; // First line for the X.
							else
								cout << Cross2; // Second line for the X.
							break;
						case 'O':
							if (b == 0)
								cout << Circle1;
							else
								cout << Circle2;
							break;
						default:
							cout << Empty;
							break;
					}
					
				}
				cout << Column << endl; // Print the last column of the board.
			}
			cout << Line << endl; // Line in between of each of the 3 lines of X/O's.
		}
		
	}
	
	
	
	void Board::pInstructions(void){
		cout << "Welcome to Tic-Tac-Toe!\nThis is the initial, empty board:\n";
		show();
		cout << "Each player will be asked to indicate which line and column they'll play.\n";
		cout << "This is a line ---------------------->\n";
		cout << "This is a column\n";
		cout << "       |\n";
		cout << "       |\n";
		cout << "       |\n";
		cout << "       |\n";
		cout << "       |\n";
		cout << "       |\n";
		cout << "       |\n";
		cout << "       |\n";
		cout << "       |\n";
		cout << "       |\n";
		cout << "       V\n";
	}




Code:
#include <iostream>
#include <string>
#include "Board.h"
using namespace std;
/* Displaying the board works the following way:
 There's a 3x3 array to hold the X/O's for the board.
 First, the show function prints the initial line of the tic-tac-toe board.
 This initial line is printed every time a horizontal set of 3 X/O's is done printing.
 Then, the actual X/O printing starts at the 1x1 spot of the board/array[0][0]. 
 It prints each X/O's first line, in
 the first set of 3 horizontal X/O's of the board. Then it does the same for each of the two remaining sets of 3 X/O's
 in the board. When it's done printing any of the lines for each set of 3 X/O's,
 it prints the final character of each line, a '|'. It's part of the outline of the board.
 */
int main (int argc, char * const argv[]) {
	board.pInstructions();
	int lValid = 0, cValid = 0;
	char pLine, pColumn;
	bool gameOver;
	while (gameOver == 0) {
		board.show();
		pLine = 0;
		pColumn = 0;
		cout << "Player 1 - it's your turn to play!\n";
		while (lValid == 0) {
			cout << "Choose a line from 1-3!\n";
			cin >> pLine;
			if (pLine <= 3 && pLine >= 1) {
				lValid = 1;
			}
			
		}
		while (cValid == 0) {
			cout << "Choose a column from 1-3!\n";
			cin >> pColumn;
			cValid = 1;
			if (pColumn <= 3 && pColumn >= 1) {
				cValid = 1;
			}
			
		}
		board.set(pLine,pColumn,1);
			
		cValid = 0;
		lValid = 0;
		
	}
	
	return 0;
	
}


PS: LoR should REALLY get a decent
Code:
 color system.
 
arg-fallbackName="Master_Ghost_Knight"/>
The problem is you are getting a character but you think you are getting a number.
And when it comes to characters the caracter 3 has the value 51.
Allways a good thing to come in handy is an ascii table, get it here: http://www.asciitable.com
So when comparing:
if(pLine <= 3 && pLine >= 1)
It will fail because the character with value 3 is actualy an ETX flag
if you do this instead:
if(pLine <= '3' && pLine >= '1')
You will see that the code will now works, writing a character between ' will tell your compiler that you actually want to find the character 3 and not a character with the value 3.
Hope this helped... It is very late now, I will check the rest tomorow.
 
arg-fallbackName="CosmicJoghurt"/>
Now the checking system works... but each time the line and column are selected, the board doesn't change from an empty state... I've checked and rechecked every function...
 
arg-fallbackName="Master_Ghost_Knight"/>
CosmicJoghurt said:
Now the checking system works... but each time the line and column are selected, the board doesn't change from an empty state... I've checked and rechecked every function...

The problem you are having is the same as before, you are confusing the character with the value they hold.

This is a very important distinction to understand programing, so pay very close attention:
THE CHARACTERS DO NOT HAVE THE SAME VALUE AS YOU INTERPRET THEM TO REPRESENT

The charcter '2' and the value 2 are not the same thing.

To understand this I have to explain a bit of history and hardwear. What is a computer and how does it work? Well you may the vague idea that internaly it works with 1's and 0's. Well no exactly. A computer is basically a complex piece of electronics that in the end of a long chain of components it puts in the end of a wire either 5 Volts or 0 Volts and we have decided that if in the end of the wire there is 5 volts we call it a 1 but if it has 0 Volts we call it a 0. There are no 0's or 1's inside, 0's and 1's are what we decide to interpret them to be (when we later say 1's and 0's this is what we mean). And if you have several wires with a difrent combination of 5 volts or 0 volts at the end (1's and 0's) you can interpret it as being a number. For instance if you have in a sequence of wires with the code [00000110] you can say that it represents a 6, there is no actual 6 inside the machine it is just 5 volts or 0 volts in the ends of wires, it is only a 6 in your head and because you say it is a 6.

Early computers were basicaly simple calculators, and when you wanted for instance to specify 2 numbers you wanted to add there was no such thing as a keyboard with numbers to press, we basically had to convert the numbers manualy into binary so we could have the combination of switches that we needed to turn on or off, the electronics is arranged in such a way that depending of the switches flicked it produces at the end the equivalent of the desiered operation and depending of the voltage in the wires it would turn on some lights that we would interpret as 1's and 0's that we would later convert back to decimal representation to get the result.

In the advent of the world war 2, for obvious reasons it became important to use computers to process text, but the computer deals in binary code that we can interpret as numbers, how do we tell the computer that what we want is for instance the letter 'a'. Well the solution is the same as before, inside the computer is just a combination of 0's ans 1's and we decide them to be whatever we decide them to be, so for instace when we get the code [01100001] we decide that it represents an 'a' and a [01100010] represents a 'b' and so forth.
But notice the problem now if in the end we get the code [01100001] from a computer it may mean a letter 'a' or it may mean the value 97 as the result of the operation 72+25. Well in context we can say when we are expecting text it means 'a' but when we are expecting values it is a 97.
Now what if we have the following text "We are sending 12 batallions to north of Berlin", we have leters and numbers mixed togheter, how do we solve this? Well simple, we just say that they are all characters and for instance to represent the character '2' we give it the code [00110010].

Now notice the character '2' [00110010] is not the same as the value 2 [00000010].
On a side note you may ask why didn't they tryed at least to mach the value of the character with the value they represent, well since they no longer represent values it doesn't make much diffrence but in terms of hardwear efficience it was decided to be beter to give it the code it has now then anyother (which basically as become the source for much confusion).

Historicaly the data type "char" has been used to store information regarding characters while the data type "int" has been used to store information regarding numbers. I said previously to use a "char" instead of "int" because a "char" only uses 1 byte while a "int" uses 4 bytes, but a "char" and a "int" are handled basically the same when it comes to basic opertions like adition multiplication and so on except for the fact that operations takes longer for a int because it has 3 aditional bytes to process. Because I have a lot of experience I can do operations with them without confusing the 2, but this is not the same for everyone, and it is natural that you feel kind of confused at the beggining.

But there are functions that are sensitive to the data types you use, for instance try this:
Code:
<i>
</i>char c=97;
int i=c;
cout << c<< endl;
cout << i<< endl;

Altough the variable "i" and "c" has the exact same value they produced difrent results. That is because that output performs difrent function depending of the data type, on the first case the output sees that the variable used is a "char" and beause "char" has been used to store characters it assumes that what you want is to print a chararcter so it grabs the value 97 and prints on the screen the character with the code 97 (i.e. an 'a'), on the second case because you are using an int it assumes that you want to print a number and therefore it puts on screen a 97.
The same thing in reverse for input. When you tpe in a 3, because you are storing in a char it thinks you want the character '3' and therefore it stores in your variable the code that corrsponds to the character '3' (i.e. the number 51).
Here is another example of a code that prints things in your screen that is not sensitive to data type:
Code:
<i>
</i>#include <stdio.h>

int main(){
	char c;
	int i;
		for(c=32;c<127;c++){
			printf("The character \'%c\' has the value %d\n",c,c);
		}
		for(i=32;i<127;i++){
			printf("The number %d is what it is used to represent the character \'%c'\n",i,i);
		}
	return 0;
}
I advise you to look for examples on how to use the function printf, you can find one here:
http://www.cplusplus.com/reference/clibrary/cstdio/printf

Now if you run that code it becomes self explenatory what it means.

So how do you correct your code easily?
Well simple, you goto the ascii table and look for value of '0', that will be 48.
Now what you have to do is to subtract 48 to the collected value and you are done, by doing that you have effectively converted a single numeric character to the value it represents. So your code will look like this:
while (lValid == 0) {
cout << "Choose a line from 1-3!\n";
cin >> pLine;
pLine=pLine-48;
if (pLine <= 3 && pLine >= 1) {
lValid = 1;
}

}
while (cValid == 0) {
cout << "Choose a column from 1-3!\n";
cin >> pColumn;
pColumn=pColumn-48;
if (pColumn <= 3 && pColumn >= 1) {
cValid = 1;
}

}
board.set(pLine,pColumn,1);

On doing comparisons with integers avoid using <= or >=, because this are in fact 2 operations i.e. pColumn<=3 is in fact (pColumn==3 || pColumn<3), if you do this instead pColumn<4 it is only 1 operation and does the same thing because 4 is still not included but you have included 3 anyways because 3<4.
So your code should look like this:
while (lValid == 0) {
cout << "Choose a line from 1-3!\n";
cin >> pLine;
pLine=pLine-48;
if (pLine < 4 && pLine > 0) {
lValid = 1;
}

}
while (cValid == 0) {
cout << "Choose a column from 1-3!\n";
cin >> pColumn;
pColumn=pColumn-48;
if (pColumn < 4 && pColumn > 0) {
cValid = 1;
}

}
board.set(pLine,pColumn,1);
You are also using unecessry vairables, because you can use the instruction "break" to get out of a while loop, for instacne you can do this:
while (true) {
cout << "Choose a line from 1-3!\n";
cin >> pLine;
pLine=pLine-48;
if (pLine < 4 && pLine > 0) break;
}
while (true) {
cout << "Choose a column from 1-3!\n";
cin >> pColumn;
pColumn=pColumn-48;
if (pColumn < 4 && pColumn > 0) break;
}
board.set(pLine,pColumn,1);


Finaly in the code:
Code:
<i>
</i>bool Board::set(int line, int column, bool x_o){
   bool spotOccupied;
   int fLine, fColumn;
   fLine = --line;
   fColumn = --column;
   if (spot[fLine][fColumn] != 'X' && spot[fLine][fColumn] != 'O'){
      if (x_o) {
         spot[fLine][fColumn] = 'X';
      }
      else {
         spot[fLine][fColumn] = 'O';
      }
   }
   else {
      spotOccupied = 1;
      cout << "Spot is already occupied! Choose another spot!\n";
   }
   return spotOccupied;
}

You are doing unecessary checks on the if statment.
because spot[fLine][fColumn] can only have 3 states (NULL, 'X' or 'O') that are all controled by the program and not subjected to user imput, you don't need to check if there is not an X or not a O to know that it is not ocupied, all you have to check is if it is NULL as long as you don't forget to initialize the variable with NULL.
Also you can do a return in the midle of the function and trminate it, so your code only needs to look like this
bool Board::set(int line, int column, bool x_o){
if (spot[fLine][fColumn] == NULL){
if (x_o) {
spot[fLine][fColumn] = 'X';
}
else {
spot[fLine][fColumn] = 'O';
}
return true;
}
cout << "Spot is already occupied! Choose another spot!\n";
return false;
}
tip, use true for sucess and false for failure.
I advise not use the return text "Spot is already occupied! Choose another spot!\n" inside the class, use it outside when you are checking for a sucess or failure.
 
Back
Top