| | |
Tic-Tac-Toe Game - Need some information or help
Please support our C++ advertiser: Programming Forums - DaniWeb Sister Site
![]() |
Hello,
I've recently, inadvertently, found incentive to write my own Tic-Tac-Toe game. I've been working on it for more-or-less 15 minutes and would like some help or a point in the right direction. It is almost finished but there is a function, namely the "_scan4Winner" function, that I must write an algorithm or come up with a formula to check for a winning condition.
Thanks in advanced, LamaBot
I've recently, inadvertently, found incentive to write my own Tic-Tac-Toe game. I've been working on it for more-or-less 15 minutes and would like some help or a point in the right direction. It is almost finished but there is a function, namely the "_scan4Winner" function, that I must write an algorithm or come up with a formula to check for a winning condition.
C++ Syntax (Toggle Plain Text)
#include <iostream> #include <stdlib.h> #include <stdio.h> #include <time.h> using namespace std; #define NWIN_CON 0 #define PONE_WIN 1 #define PTWO_WIN 2 #define GRST 2 const char playerOne = 'X'; const char playerTwo = 'O'; int _writeGrid( int y, int x, int flag ); int _scan4Winner(char (*grid)[3]); int _playerWin(int winner); int main() { char setLocation; /* char hexc = 0x41; */ int randomee, turn, ret; int px = 0, py = 0; srand(time(NULL)); // Seed for random // This will put a random number between 1 and 10 which will // determine what player initially goes first randomee = rand() % 10 + 1; // Which player goes first turn = (randomee >= 5) ? 1 : 0; // Indicate which user goes first cout << "Player " << turn << "is first" << endl; // This will print a fresh new grid _writeGrid(NULL, NULL, GRST); // Start the actual game while (1) { cout << "Player " << turn << " set: "; cin >> setLocation; switch (setLocation) { case 0x41 : px = 0; py = 0; break; case 0x42 : px = 1; py = 0; break; case 0x43 : px = 2; py = 0; break; case 0x44 : px = 0; py = 1; break; case 0x45 : px = 1; py = 1; break; case 0x46 : px = 2; py = 1; break; case 0x47 : px = 0; py = 2; break; case 0x48 : px = 1; py = 2; break; case 0x49 : px = 2; py = 2; break; } /************************************* while (hexc != 0x49) { if (setLocation == hexc) { ret = _writeGrid(py, px, turn); hexc = 0x41; px = 0; py = 0; break; } hexc++; if (px < 2) px++; else { px = 0; py++; } } ****************************************/ // Once the coords are determined pass them and which player is // going, return and check if that player won. ret = _writeGrid(px, py, turn); if (ret == PONE_WIN) { turn = 0; _writeGrid(NULL, NULL, GRST); } else if (ret == PTWO_WIN) { turn = 1; _writeGrid(NULL, NULL, GRST); } else turn = (turn) ? 0 : 1; // If no one won yet switch players } return 0; } // This function writes a 3 x 3 tic-tac-toe grid and adds an X or a O // depending on the current user, and also takes a grid corrdinates // that'll determine the position or the X or O before it prints the grid int _writeGrid(int y, int x, int flag) { static char gridMap[3][3]; // Make static so grid is remembered int i, j, winner; char hexc = 0x41; // If the flag is a reset flag, reset the whole grid if (flag == GRST) { for (i=0;i<3;i++) { for (j=0;j<3;j++) { gridMap[i][j] = hexc; hexc++; cout << "| " << gridMap[i][j]; } cout << endl << endl; } return GRST; } else { // Condition flag and place either an X(playerOne) or O // (playerTwo) into the coords passed as parameters gridMap[x][y] = (flag) ? playerOne : playerTwo; system("cls"); // This section will actually write the grid using the values // stored in gridMap for (i=0;i<3;i++) { for (j=0;j<3;j++) { cout << "| " << gridMap[i][j]; } cout << endl << endl; } // The next step is to check for a winner so we pass gridMap // containing the actual grid status winner = _scan4Winner // (gridMap) If a winning condition is encountered notify the // player who wins, add one point to his current score and reset // the grid. if (winner) return _playerWin((flag) ? PONE_WIN : PTWO_WIN); return NWIN_CON; } } // This function will have a formula or algorition that'll check for // winning conditions. int _scan4Winner(char (*grid)[3]) { return 0; } // This function simply prints whose the winner of a tic-tac-toe game // and increments a counter variable for the corresponding user int _playerWin(int winner) { static int pcount1; static int pcount2; if (winner == PONE_WIN) { pcount1++; cout << "Player one wins - score is" << pcount1 << endl; return PONE_WIN; } else { pcount2++; cout << "Player two wins - score is" << pcount2 << endl; return PTWO_WIN; } }
Thanks in advanced, LamaBot
Last edited by Lazaro Claiborn; Feb 15th, 2007 at 5:29 pm. Reason: Comment not perfect
•
•
•
•
Easiest is to pass in the position of the last move then check each direction from that location for 3 in a row.
I didn't do exactly what you'd said but you gave me an idea. I figured that'd I check on every move and just pass the whole array so that even if the player were to move in the middle of a given check it'll still work without writing extra code to detect where to scan relative to the most current position. Wicked cool! Thanks again Waltp. Also, since you're a Moderator, perhaps you can point me in the right direction where I can upload some tutorials or something? If not, its cool, I'll find it sooner or later. Last, in the previously posted code, I accidently rendered a statement as a comment, namely the "winner = _scan4Winner(gridMap)"; I was trying to make it look pretty and I messed it up I guess. :o Here is the code for the _scan4Winner function and all affiliated functions:
C++ Syntax (Toggle Plain Text)
// This function writes a 3 x 3 tic-tac-toe grid and adds an X or a O // depending on the current user, and also takes a grid corrdinates // that'll determine the position or the X or O before it prints the grid int _writeGrid(int y, int x, int flag) { static char gridMap[3][3]; // Make static so grid is remembered int i, j, winner; char hexc = 0x41; // If the flag is a reset flag, reset the whole grid if (flag == GRST) { for (i=0;i<3;i++) { for (j=0;j<3;j++) { gridMap[i][j] = hexc; hexc++; cout << " " << gridMap[i][j]; } cout << endl << endl; } return SUCCESS; } else { system("cls"); // Condition flag and place either an X(playerOne) or O //(playerTwo) into the coords passed as parameters if (gridMap[x][y] != 'X' && gridMap[x][y] != 'O') gridMap[x][y] = (flag) ? playerOne : playerTwo; else cout << "That position is already occupied" << endl << endl; if (_checkFull(gridMap)) return GRST; // This section will actually write the grid using the values // stored in gridMap for (i=0;i<3;i++) { for (j=0;j<3;j++) cout << " " << gridMap[i][j]; cout << endl << endl; } // The next step is to check for a winner so we pass gridMap // which contains the actually grid status. Note, this is the // statement that got accidently included with the comments // of the first posted code winner = _scan4Winner(gridMap); // If a winning condition is encountered notify the player who //wins, add one point to his current score and reset the grid if (winner) return _playerWin(winner); return NWIN_CON; } } // This function will have a formula or algorition that'll check for // winning conditions. int _scan4Winner(char (*grid)[3]) { if (_checkDiagnol(grid, 'X') || _checkAcross(grid, 'X') || _checkDown(grid, 'X')) return PONE_WIN; else if (_checkDiagnol(grid, 'O') || _checkAcross(grid, 'O') || _checkDown(grid, 'O')) return PTWO_WIN; return NWIN_CON; } // This function simply prints whose the winner of a tic-tac-toe game // and increments a counter variable for the corresponding user int _playerWin(int winner) { static int pcount1; static int pcount2; if (winner == PONE_WIN) { pcount1++; cout << "Player one wins - win score is " << pcount1 << endl; return PONE_WIN; } else { pcount2++; cout << "Player two wins - win score is " << pcount2 << endl; return PTWO_WIN; } } // Check both diagnol directions bool _checkDiagnol(char (*grid)[3], char player) { int i, j, counter1 , counter2; j = counter1 = counter2 = 0; for (i=0;i<3;i++) { if (grid[j][i] == player) counter1++; j++; } j=0; for (i=2;i>=0;i--) { if (grid[j][i] == player) counter2++; j++; } return (counter1 == 3 || counter2 == 3) ? true : false; } // Across down the Y axis bool _checkAcross(char (*grid)[3], char player) { int i, j, counter; counter = 0; for (i=0;i<3;i++) { for (j=0;j<3;j++) { if (grid[i][j] == player) counter++; } if (counter >= 3) return true; else counter = 0; } return false; } // Check down across the X axis bool _checkDown(char (*grid)[3], char player) { int i, j, counter; counter = j = 0; for (i=0;i<3;i++) { for (j=0;j<3;j++) { if (grid[j][i] == player) counter++; } if (counter == 3) return true; else counter = 0; } return false; } // Check for a full grid static bool _checkFull(char (*grid)[3]) { int i, j; for (i=0;i<3;i++) { for (j=0;j<3;j++) { if (grid[i][j] != 'X' && grid[i][j] != 'O') return 0; } } return 1; }
I'll probably need to modify the code, but it works fine for right now. Any suggestions will be much appreciated.
Thanks a lot, LamaBot
With this solution you are checking 3 colums, 3 rows, and 2 diagonals. IOW 8 tests.
If you pass in the last move, you can check 1 row, 1 col, and 0, 1, or 2 diagonals. For this, a maximum of 4 tests. To check to see if a diagonal has to be tested,
If you pass in the last move, you can check 1 row, 1 col, and 0, 1, or 2 diagonals. For this, a maximum of 4 tests. To check to see if a diagonal has to be tested,
C++ Syntax (Toggle Plain Text)
if both indexes are 1, both diagonals must be tested (center square) else if either index is 1 there are no diagonals (side square) else test one diagonal (corner square)
The 3 Laws of the Procrastination Society:
1) Never do today that which can be put off until tomorrow
2) Tomorrow never comes
1) Never do today that which can be put off until tomorrow
2) Tomorrow never comes
•
•
•
•
With this solution you are checking 3 colums, 3 rows, and 2 diagonals. IOW 8 tests.
If you pass in the last move, you can check 1 row, 1 col, and 0, 1, or 2 diagonals. For this, a maximum of 4 tests. To check to see if a diagonal has to be tested,
C++ Syntax (Toggle Plain Text)
if both indexes are 1, both diagonals must be tested (center square) else if either index is 1 there are no diagonals (side square) else test one diagonal (corner square)
Sorry I havn't replied sooner, but I've had work today
I understood what you suggestion, and it works. I kind of re-wrote the program, created classes for my nueral network (3 layer-forward model) and started to write some activations functions; as to see which one seems fit during training, and yes, I am going to incorporate an AI don't ask why:lol: Some of the programs original functionality doesn't work, in particular the "_endGame(void)" function will not end the game but simply allows you to view a winners score before resetting the grid. I'll change this laters as I develope my AI, which I might need some help, hopefully you, now-and-then???? Anyway, thanks for the suggestion; To think, I've got experienced with AI yet I can't deviate, figure and reckon that 8 tests would be better than 4!!!! Need to stop plumbing and start programming more again. Enough babbling, here is the code:
C++ Syntax (Toggle Plain Text)
#include <iostream> #include <stdlib.h> #include <stdio.h> #include <time.h> using namespace std; #define PONE_WIN 0 #define PTWO_WIN 1 #define GREG 1 #define GRST 2 const char player[] = "XO"; char grid[3][3]; void _writeGrid(int flag); void _playerWin(int winner); inline bool _checkDiagnolDecline(char player) { return (grid[1][1]==player && grid[2][2]==player && grid[0][0]==player) ? true : false; } inline bool _checkDiagnolIncline(char player) { return (grid[2][0]==player && grid[0][2]==player && grid[1][1]==player) ? true : false; } inline bool _checkDown(int x, char player) { return (grid[0][x]==player && grid[1][x]==player && grid[2][x]==player) ? true : false; } inline bool _checkAcross(int y, char player) { return (grid[y][0]==player && grid[y][1]==player && grid[y][2]==player) ? true : false; } static inline int _endGame(void) { char endGame; cout << "Would you like to play another game? y / n "; cin >> endGame; if (endGame == 'y' || endGame == 'Y') return 0; return 1; } static bool _checkFull(void); int main() { char setLocation, endGame; char hexc = 0x41; int randomee, turn, ret; int px = 0, py = 0; srand(time(NULL)); // Seed for random randomee = rand() % 10 + 1; turn = (randomee >= 5) ? 1 : 0; cout << "Player " << turn << " is first" << endl << endl; _writeGrid(GRST); while (1) { cout << "Player " << turn << " set: "; cin >> setLocation; switch (setLocation) { case 0x41 : px = 0; py = 0; break; case 0x42 : px = 1; py = 0; break; case 0x43 : px = 2; py = 0; break; case 0x44 : px = 0; py = 1; break; case 0x45 : px = 1; py = 1; break; case 0x46 : px = 2; py = 1; break; case 0x47 : px = 0; py = 2; break; case 0x48 : px = 1; py = 2; break; case 0x49 : px = 2; py = 2; break; } if (grid[py][px] == player[0] || grid[py][px] == player[1]) cout << "Position is occupied" << endl; else { grid[py][px] = player[turn]; if (_checkFull()) { } else { if (py==1 && px==1) { if (_checkDiagnolIncline(player[turn]) || _checkDiagnolDecline(player[turn])) _playerWin(turn); } else if (!py && !px || py==2 && px==2) { if (_checkDiagnolDecline(player[turn])) _playerWin(turn); } else if (py==2 && px==0 || py==0 && px==2) { if (_checkDiagnolIncline(player[turn])) _playerWin(turn); } if (_checkAcross(py, player[turn])) _playerWin(turn); if (_checkDown(px, player[turn])) _playerWin(turn); _writeGrid(GREG); turn = (turn) ? 0 : 1; } } } return 0; } void _writeGrid(int flag) { int i, j; char hexc = 0x41; if (flag == GRST) { for (i=0;i<3;i++) { for (j=0;j<3;j++) { grid[i][j] = hexc; hexc++; cout << " " << grid[i][j]; } cout << endl << endl; } } else { system("cls"); for (i=0;i<3;i++) { for (j=0;j<3;j++) cout << " " << grid[i][j]; cout << endl << endl; } } }
Does that look right? I'm still open for suggestions and I've got some ideas of my own I'll post later on, but I'm freaking tired.
Thanks in advance, LamaBot
Last edited by Lazaro Claiborn; Feb 18th, 2007 at 1:48 am. Reason: formatting
No problem. It's not like I was waiting by the computer just for you :mrgreen:
It all comes with more time and more experience. I remember one program I wrote with multiple nested for loops (15 I think) -- took over 3 pages and a couple bad practices. Less than a year later I rewrote the entire program to less than 1 page. Knowledge can come at you fast...
This whole section can be reduced to 2 simple equations. Hint: Subract 41 from setLocation and look at division and modulus operators...
If it works, it's (probably) right. I didn't look at the whole thing, but the above jumped out at me big time...
•
•
•
•
Anyway, thanks for the suggestion; To think, I've got experienced with AI yet I can't deviate, figure and reckon that 8 tests would be better than 4!!!!
•
•
•
•
c Syntax (Toggle Plain Text)
cin >> setLocation; switch (setLocation) { case 0x41 : px = 0; py = 0; break; case 0x42 : px = 1; py = 0; break; case 0x43 : px = 2; py = 0; break; case 0x44 : px = 0; py = 1; break; case 0x45 : ... py = 2; break; }
If it works, it's (probably) right. I didn't look at the whole thing, but the above jumped out at me big time...
The 3 Laws of the Procrastination Society:
1) Never do today that which can be put off until tomorrow
2) Tomorrow never comes
1) Never do today that which can be put off until tomorrow
2) Tomorrow never comes
•
•
•
•
No problem. It's not like I was waiting by the computer just for you :mrgreen:
You'll have to forgive my spunky personality. I used the method(s) you suggested; the obviously one insinuated was:
C++ Syntax (Toggle Plain Text)
px = (setLocation - 0x41) % 3; // Duh...;)
In a non-defensive manner of speaking, because I wrote the original program relatively fast I didn't put to much time in code efficiency - meaning I usually write the steps of a program and modify the code later for efficiency. Although you helped me from having to really think about it and I appreciate your expertise.
Thanks, LamaBot
Last edited by Lazaro Claiborn; Feb 18th, 2007 at 3:36 pm.
![]() |
Similar Threads
- Tic-Tac-Toe (C++)
- Tic-Tac-Toe Game (Visual Basic 4 / 5 / 6)
- HELP!!! Tic-tac-toe game! (C++)
- C++ Tic Tac Toe using classes & operator overloading (C++)
- Tic Tac Toe Homework (C++)
Other Threads in the C++ Forum
- Previous Thread: problem inserting elements in a 2D vector
- Next Thread: from C to C++
Views: 3200 | Replies: 6
| Thread Tools | Search this Thread |
Tag cloud for C++
6 api application array arrays assignment based beginner binary c++ c/c++ calculator char char* class classes code coding compile compiler console conversion convert count data database delete developer display dll dynamiccharacterarray email encryption error file format forms fstream function functions game generator givemetehcodez graph iamthwee ifstream image input int java lib list loop looping loops map math matrix memory multidimensional multiple newbie news number numbertoword output pointer problem program programming project python random read recursion recursive reference return rpg search sort sorting string strings struct template templates text tree url variable vector video visual visualstudio win32 windows winsock wordfrequency wxwidgets






