Advertisement

Tic-tac-toe

Started by April 30, 2002 03:35 PM
8 comments, last by jar 22 years, 6 months ago
hi, this is a newbish question, but here it goes... i''m starting to make a tic-tac-toe game in c++. all i did so far was make the board out of a 2-dimensional array, but here''s the question. if i want the person to make their move at row 1, column 1, or whatever, how do i show on the screen where the person made his move? any help would greatly be appreciated. thanks!
Well, I''m assuming that you are doing this in console C++ mode, and not using a graphics API...

It''s quite easy, just blit the updated array to the screen


  int map[3][3] = { 0, 0, 0,                  0, 0, 0,                  0, 0, 0 };for (y = 0; y < 3; y++){    for (x = 0; x < 3; x++)    {         printf("%i \t", map[y][x]);    }    printf("\n");}  


To change the array, as you probably already know, is quite easy, just have a input poll routine and depending on what location they pick, just update the array location.

if (key_up) map[0][2] = 1;

Does that help?

"I am governed by none other than the Laws of the Universe."
"I am governed by none other than the Laws of the Universe."
Advertisement
Instead of using a 2 dimensional array just use a single array,
array[9], since there is only 9 possible moves. When I first made tic-tac-toe I used a switch statement to decide where to mark.

 1 | 2 | 3========= 4 | 5 | 6========= 7 | 8 | 9there are many ways that you can do this.    -----------------------------"There are ones that say they can and there are those who actually do.""...u can not learn programming in a class, you have to learn it on your own."     
-----------------------------"There are ones that say they can and there are those who actually do.""...u can not learn programming in a class, you have to learn it on your own."
is there an algorithm you could make or use to check if there are three in a row or do you just use IF statements cos that could get messy
//My Tic-Tac-Toe Program
//This was my first C++ program and I didn't exactly finish it, but, it should be a good start for getting into c++
//Phil Castellanos - z3hp@yahoo.com
#include <iostream.h>
#include <cstring>
#include <windows.h>
#include <fstream.h>
#include <time.h>

//Const values for X & O
const X = 1;
const O = 2;
const BLANK = 0;

int lplayer; //Last player to make a move
int BOARD[8]; //Array used to keep track of the board


//Program Functions
void ShowMenu(); //Prints the menu and prompts for input
void PickPlayer(); //Randomly selects player X or O to go first
void DrawBoard(); //Draws the tic-tac-toe board in ASCII
void IntBoard(); //Initilaizes the board
int ChkWinner(); //Checks for a winner
int ChkCat(); //Checks to see if cat is the winner
int GetInput(); //Get input from the users
int IsAllowed(int Square); //Checks to see if move is allowed
int GameLoop(); //This is the game loop

void init_mm( ); //Used to seed
int number_range( int from, int to ); //Generate number from x to y
int number_mm( void ); //Used for generating rand numbers
static int rgiState[2+55]; // leave this alone

/* Incomplete */
void LogScore(); //Logs winner
void ViewScore(); //Displays winners

int main() {
//Infinite Loop
for(; {
//Call ShowMenu() Function
ShowMenu();
}
return 0; //Exit/Return 0
}

//This functions is used to ask the player which square they would like to select
int GetInput() {
int psqr;
do {
if (lplayer == X) { //If the last player was X lets ask O
cout << "Player O please select a square: ";
cin >> psqr;
} else { //The last player was O lets ask X
cout << "Player X please select a square: ";
cin >> psqr;
}
} while (IsAllowed(psqr) == 1); //Do while the user enters an allowed square
//Lets set the last player value
if (lplayer == X) {
lplayer = O;
return psqr;
} else {
lplayer = X;
return psqr;
}
}

//This function is used to initalize the board array to 0 which is = to BLANK
void IntBoard() {
int f;
for (f=0; f<9; f++) {
BOARD[f] = BLANK;
}
return;
}


//This function is used to check for a winner
int ChkWinner() {

//Check for horizontal win
if ((BOARD[0] == BOARD[1] && BOARD[1] == BOARD[2]) && (BOARD[0] != BLANK && BOARD[1] != BLANK && BOARD[2] != BLANK)) {
if (BOARD[0] == X) {
return X;
} else {
return O;
}
}
if ((BOARD[3] == BOARD[4] && BOARD[4] == BOARD[5]) && (BOARD[3] != BLANK && BOARD[4] != BLANK && BOARD[5] != BLANK)) {
if (BOARD[3] == X) {
return X;
} else {
return O;
}
}
if ((BOARD[6] == BOARD[7] && BOARD[7] == BOARD[8]) && (BOARD[6] != BLANK && BOARD[7] != BLANK && BOARD[8] != BLANK)) {
if (BOARD[6] == X) {
return X;
} else {
return O;
}
}

//Check for vertical win
if ((BOARD[0] == BOARD[3] && BOARD[3] == BOARD[6]) && (BOARD[0] != BLANK && BOARD[3] != BLANK && BOARD[6] != BLANK)) {
if (BOARD[0] == X) {
return X;
} else {
return O;
}
}
if ((BOARD[1] == BOARD[4] && BOARD[4] == BOARD[7]) && (BOARD[1] != BLANK && BOARD[4] != BLANK && BOARD[7] != BLANK)) {
if (BOARD[1] == X) {
return X;
} else {
return O;
}
}
if ((BOARD[2] == BOARD[5] && BOARD[5] == BOARD[8]) && (BOARD[2] != BLANK && BOARD[5] != BLANK && BOARD[8] != BLANK)) {
if (BOARD[2] == X) {
return X;
} else {
return O;
}
}

//Check for diagonal win
if ((BOARD[0] == BOARD[4] && BOARD[4] == BOARD[8]) && (BOARD[0] != BLANK && BOARD[4] != BLANK && BOARD[8] != BLANK)) {
if (BOARD[0] == X) {
return X;
} else {
return O;
}
}
if ((BOARD[2] == BOARD[4] && BOARD[4] == BOARD[6]) && (BOARD[2] != BLANK && BOARD[4] != BLANK && BOARD[6] != BLANK)) {
if (BOARD[2] == X) {
return X;
} else {
return O;
}
}
//Check for cat game
ChkCat();
return 0;
}

//This function is used to draw the board to the screen in ASCII
void DrawBoard() {
char line1[14], line2[14], line3[14];
char tmp[50];


cout << "-------------\n";

//Prepare the start of line 1
strcpy(tmp,"| ");
if (BOARD[0] == BLANK) { strcat(tmp,"1 | "); }
if (BOARD[0] == X) { strcat(tmp,"X | "); }
if (BOARD[0] == O) { strcat(tmp,"O | "); }

if (BOARD[1] == BLANK) { strcat(tmp,"2 | "); }
if (BOARD[1] == X) { strcat(tmp,"X | "); }
if (BOARD[1] == O) { strcat(tmp,"O | "); }

if (BOARD[2] == BLANK) { strcat(tmp,"3 |"); }
if (BOARD[2] == X) { strcat(tmp,"X |"); }
if (BOARD[2] == O) { strcat(tmp,"O |"); }
strcat(tmp, "\n");
strcpy(line1, tmp);
cout << line1;

//Prepare line 2
strcpy(tmp, "-------------\n");
strcat(tmp,"| ");
if (BOARD[3] == BLANK) { strcat(tmp,"4 | "); }
if (BOARD[3] == X) { strcat(tmp,"X | "); }
if (BOARD[3] == O) { strcat(tmp,"O | "); }

if (BOARD[4] == BLANK) { strcat(tmp,"5 | "); }
if (BOARD[4] == X) { strcat(tmp,"X | "); }
if (BOARD[4] == O) { strcat(tmp,"O | "); }

if (BOARD[5] == BLANK) { strcat(tmp,"6 |"); }
if (BOARD[5] == X) { strcat(tmp,"X |"); }
if (BOARD[5] == O) { strcat(tmp,"O |"); }
strcat(tmp, "\n");
strcpy(line2, tmp);
cout << line2;

//Prepare line 3
strcpy(tmp, "-------------\n");
strcat(tmp,"| ");
if (BOARD[6] == BLANK) { strcat(tmp,"7 | "); }
if (BOARD[6] == X) { strcat(tmp,"X | "); }
if (BOARD[6] == O) { strcat(tmp,"O | "); }

if (BOARD[7] == BLANK) { strcat(tmp,"8 | "); }
if (BOARD[7] == X) { strcat(tmp,"X | "); }
if (BOARD[7] == O) { strcat(tmp,"O | "); }

if (BOARD[8] == BLANK) { strcat(tmp,"9 |"); }
if (BOARD[8] == X) { strcat(tmp,"X |"); }
if (BOARD[8] == O) { strcat(tmp,"O |"); }
strcat(tmp, "\n");
strcpy(line3, tmp);
cout << line3 << "-------------\n";

return;
}


//This function is used to check if the square entered is a valid value
int IsAllowed(int Square) {

if ((BOARD[Square-1] == BLANK) && (Square >= 1 && Square <= 9)) {
return 0;
} else {
return 1;
}
}


//This function checks for cat as Winner
int ChkCat() {
int f;

//If none of the squares are blank then all moves have been made and no one is the winner
for (f=0; f<8; f++) {
if (BOARD[f] == BLANK) { return 0; }
}
return 1;
}


//This function is used to randomly pick the first player
void PickPlayer() {
int p;
init_mm();
p = number_range(1,2);
if (p == X) {
lplayer = O;
cout << "Player X has been randomly selected to go first\n";
} else {
lplayer = X;
cout << "Player O has been randomly selected to go first\n";
}
return;
}

//This function displays the menu to the user and waits for input
void ShowMenu() {
int Selec;
cout << "==============================\n";
cout << "= Phil's Tic-Tac-Toe =\n";
cout << "= =\n";
cout << "= 1) New Game =\n";
cout << "= 2) View Player Wins =\n";
cout << "= 3) Exit =\n";
cout << "= =\n";
cout << "==============================\n";
cout << "Selection> ";
cin >> Selec;
if (Selec == 1) { GameLoop(); }
if (Selec == 2) { ViewScore(); ShowMenu(); }
if (Selec == 3) { exit(0); } //Exit the program
return;
}

//This is the main Game Loop
int GameLoop() {
int data;

PickPlayer(); //Lets randomly pick a player to go first
IntBoard(); //Initilaze Board
DrawBoard(); //Draw the Board
do { //We do this while there is no winner
data = GetInput(); //Get the users input
if (lplayer == X) { //If last player is X
BOARD[data -1] = X; //Update the Board with the players move
} else { //Else last player was O
BOARD[data -1] = O; //Update the Board with the players move
}
DrawBoard(); //Draw the board to show the recent player move
} while (ChkWinner() == 0 && ChkCat() == 0); //while there is no winner
if (ChkCat() == 1) { //Check to see if cat has won the game
cout << "Cat Wins The Game\n";
return 0;
}
if (ChkWinner() == X) { //Check to see if X was the winner
cout << endl << "X IS THE WINNER!!!!!!\n";
LogScore(); //Log the win ***This is incomplete***
} else { //Else, O is the winner
cout << endl << "O IS THE WINNER!!!!!!\n";
LogScore(); //Log the win ***This is incomplete***
}
return 0;
}

//This function is used to keep track of who won
/***This is incomplete***/
void LogScore() {
ofstream Score;
char Name[20];

Score.open("score.dat", ios::app);
if (Score.fail()) {
cout << "Error opening scores.dat\n";
exit(1);
}
cout << "Winners Name: ";
cin >> Name;
if (lplayer == X) {
Score << Name << " - X" << endl;
} else {
Score << Name << " - O" << endl;
}
Score.close();

return;
}

//This function is used to view the winner list
/***This is incomplete***/
void ViewScore() {
ifstream Score;
char Buff[22];

Score.open("score.dat");
if (Score.fail()) {
cout << "Error opening scores.dat\n";
exit(1);
}
while (! Score.eof()) {
Score.getline(Buff,22);
cout << Buff << endl;
}
Score.close();

return;
}
int number_mm( void )


{
int *piState;
int iState1;
int iState2;
int iRand;
piState = &rgiState[2];
iState1 = piState[-2];
iState2 = piState[-1];
iRand = ( piState[iState1] + piState[iState2] )
& ( ( 1 << 30 ) - 1 );
piState[iState1] = iRand;
if ( ++iState1 == 55 )
iState1 = 0;
if ( ++iState2 == 55 )
iState2 = 0;
piState[-2] = iState1;
piState[-1] = iState2;
return iRand >> 6;
}
/*
* Generate a random number.
*/
int number_range( int from, int to )


{
int power;
int number;
init_mm();
if ( ( to = to - from + 1 ) <= 1 )
return from;
for ( power = 2; power < to; power <<= 1 )
;
while ( ( number = number_mm( ) & ( power - 1 ) ) >= to )
;
return from + number;
}
/*
* this is the Mitchell-Moore algorithm from Knuth Volume II.
*/
void init_mm( )


{
int *piState;
int iState;
piState = &rgiState[2];
piState[-2] = 55 - 55;
piState[-1] = 55 - 24;
piState[0] = ( (int) time( NULL ) ) & ( ( 1 << 30 ) - 1 );
piState[1] = 1;
for ( iState = 2; iState < 55; iState++ )


{
piState[iState] = ( piState[iState-1] + piState[iState-2] )
& ( ( 1 << 30 ) - 1 );
}
return;
}

[edited by - cYon on April 30, 2002 7:51:26 PM]
Thanks for all the responses everyone! it really helped!
Advertisement
As a sidenote, you don''t have to check every possible combination to win. After a move is made, it is implied that if he/she has won that it involves that piece. So all yuo need to do is check every possible win from that position, rather than at every position. At the center it makes no real difference, but at every other place it saves a bit of time. Also, you don''t need to check for any wins until at least the 5th move, though I guess it doesn''t really matter.

____________________________________________________________
Direct3D vs. OpenGL
SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.
I once made a tic-tac-toe in perl (as a CGI). I remember i represented X with 1, and O with -1 in the table representing the board.
Then for each row, column and diagonal I would calculate the sum of the three numbers. If any sum=3 X had won, if any sum=-3 O had won. I also used these sums to figure out good moves for the computer player.

---------
"It''s always useful when you face an enemy prepared to die for his country. That means both of you have exactly the same aim in mind." -Terry Pratchett

[edited by - deformed rabbit on May 3, 2002 4:42:07 AM]
---------"It''s always useful when you face an enemy prepared to die for his country. That means both of you have exactly the same aim in mind." -Terry Pratchett
Me and a friend are making a Tic Tac Toe game right now. It''s gonna use the allegro library and have machine learning AI that through after a series of training runs will be able to beat anyone (itl learn unbeatable combination if going first). Should be pretty spiff :D
quote: Original post by noober
Me and a friend are making a Tic Tac Toe game right now. It''s gonna use the allegro library and have machine learning AI that through after a series of training runs will be able to beat anyone (itl learn unbeatable combination if going first). Should be pretty spiff :D


Trainable AI? Cool! I would call it overkill for a game as simple as Tic-tac-toe, but it''s probably a good way to learn about AI. I wouldn''t know how to even start making a learning AI, but still IIRC my program was abut 50 lines of code, unbeatable, and would pounce on any weak opening moves. BTW, there are no sure winning opening moves even when moving first. If you want to keep training the AI until its able to beat itself when moving first, you can train it from now on an until doomsday :-).
---------"It''s always useful when you face an enemy prepared to die for his country. That means both of you have exactly the same aim in mind." -Terry Pratchett

This topic is closed to new replies.

Advertisement