Click here to Skip to main content
15,444,490 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I want the program to print "You win" when any of the instances in the champion() function are given. It only shows a winner when "123" is inputted. Whenever three X's are displayed anywhere else the program continues. For instance if three X's are given diagonally the program will still continue. Novice programmer so any criticism is greatly appreciated.

C++
#include <iostream>
#include <string>
#include<cstdio>
#include <stdlib.h>

#define GRID_SIZE 3

class TicTacToe {
private:
    char map[GRID_SIZE][GRID_SIZE];
    
public:
    
     void computers_turn() {
        while (true) {
            int choice = (rand() % 9) + 1 ;
            
            int row = choice / 3;
            int col = choice % 3;
            char grid_position = map[row][col];
            
            if (grid_position == 'X' || grid_position == 'O') {
                std::cout << "Space taken. Try again" << std::endl;
            } else {
                map[row][col] = (char) 'O';
                break;
            }            
        }            
    }
    
    void champion() {
        const char *possiblities[8] = {
            "123",
            "456",
            "789",
            "147",
            "258",
            "369",
            "159",
            "753"
        };
        
        for (int i = 0; i < 8; i++) {            
            char previous_pos = '0';
            const char *possible_moves = possiblities[i];
            bool winner = true;
            
            for (int index = 0; index < GRID_SIZE; index++) {
                char character = possible_moves[index];
                int entered_num = character - '0';
                int grid_space = entered_num - 1;
                
                int row = index / GRID_SIZE;
                int col = index % GRID_SIZE;
                
                char grid_coordinate = map[row][col];                
                
                if (previous_pos == '0') {
                    previous_pos = grid_coordinate;
                } else if
                    (previous_pos == grid_coordinate) {
                        continue;
                    } else {
                        winner = false;
                        break;
                    }
            }
            if (winner ) {
                puts("You win");
                exit(0);                
            }            
        }              
    }
    
    void playgame() {
        std::string input;
        
        while (true) {
            puts( "Go player one");
            getline(std::cin, input);
            if (input != "") {
                char entered = input.c_str()[0];
                
                if (entered >= '1' && entered <= '9') {
                    int entered_num = entered - '0';
                    int index = entered_num - 1;
                    int row = index / 3;
                    int col = index % 3;
                    char grid_position = map[row][col];
                    
                    if (grid_position == 'X' || grid_position == 'O') {
                        std::cout << "Space taken. Try again" << std::endl;
                    } else {
                        map[row][col] = (char) 'X';
                        break;
                    }                    
                } else {
                    std::cout << "Only numbers 1 - 9" << std::endl;
                }
            } else {
                std::cout << "Have to enter something, try again" << std::endl;
            }                  
        }
    }
    
    void generateGrid() {
        int number = 1;
        
        for (int x = 0; x < GRID_SIZE; x++) {
            for (int y = 0; y < GRID_SIZE; y++) {
                map[x][y] = std::to_string(number).c_str()[0];
                number += 1;
            }
        }
    }
    
    void tictacToeMap() {                
        std::cout << std::endl;
        
        for (int x = 0; x < GRID_SIZE; x++) {
            for (int y = 0; y < GRID_SIZE; y++) {
                std::printf(" %c ", map[x][y]);
            }
            std::cout << std::endl;
        }        
    }    
    
    TicTacToe() {
        generateGrid();        
        
        while (true) {        
            tictacToeMap();
            champion();
            playgame();                               
        }
    }
};

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


What I have tried:

I have tried everything I know to fix this but I can't figure it out.
Posted
Updated 2-Jul-19 10:17am
v3

Try
C++
bool champion()
{
  int possibilities[8][3] =
  {
    {0,1,2},
    {3,4,5},
    {6,7,8},
    {0,3,6},
    {1,4,7},
    {2,5,8},
    {0,4,8},
    {6,4,2}
  };

  for (size_t i = 0; i<8; ++i)
  {
    size_t j = 0;
    for ( ; j <3; ++j)
    {
      size_t r = possibilities[i][j] / 3;
      size_t c = possibilities[i][j] - r * 3;
      if ( map[r][c] != 'X')
        break;
    }
    if (j == 3)
    {
      puts("you win");
      return true;
    }
  }
  return false;
}
and
C++
 TicTacToe() 
{
  generateGrid();
  while (true) 
  {
    tictacToeMap();
    if ( champion() ) break;
    playgame();
  }
}
 
Share this answer
 
Comments
KarstenK 2-Jul-19 6:02am    
to run the whole code in the constructor isnt the best idea. :-O
CPallini 2-Jul-19 11:10am    
At least such idea is not mine. :-)
merano99 2-Jul-19 15:48pm     CRLF
The playgame method can be improved too:
void playgame() {  std::string input;  while (true) {	puts("Go player one");	getline(std::cin, input);	if (input != "") {		int index = std::stoi(input) - 1;		if ((index >= 0) && (index <= 8)) {			int row = index / 3;			int col = index % 3;			char grid_position = map[row][col];			...
I have tried everything I know

You haven't tried to make use of your compiler, having it generate warnings and reacting to them (variable character is unused). If it didn't generate this warning, use -Wall to make it so.

Also you should have tried a debugger to see what is happening. Then you quickly would have realized that in your champion function, you never check the cells in the lower rows: row is always 0. And it is 0, because you calculate it as index/3, where index is a value between 0 and 2 ...

The mistake is, you should use character here, not index.

The lesson to be learned here is: learn to use the tools that you have available. If used well, they will help you a lot more than you you might imagine.

P.S.: another tip that could help you recognize bugs even before the compiler touches your code: use meaningful variable names.

This does include loop variables, especially when you have nested loops: using 'i' and 'index' isn't very useful. Naming them 'i_possibility' and 'string_pos' instead would be much clearer, and maybe you would have noticed that it isn't very sensible to determine your row and column index on the base of 'string_pos'.
C++
row = string_pos / GRID_SIZE; // this doesn't look right to me. How about you?
Also the name 'character' is very bad indead: character is it's type, not its meaning! What the value stored in this variable represents, is the index into your tic tac toe matrix, so why not name it matrix_index? Then the code to determine your row would be
C++
row = matrix_index / GRID_SIZE;
 
Share this answer
 
v2
Quote:
Novice programmer so any criticism is greatly appreciated.
...
I have tried everything I know to fix this but I can't figure it out.

Your code do not behave the way you expect, or you don't understand why !

There is an almost universal solution: Run your code on debugger step by step, inspect variables.
The debugger is here to show you what your code is doing and your task is to compare with what it should do.
There is no magic in the debugger, it don't know what your code is supposed to do, it don't find bugs, it just help you to by showing you what is going on. When the code don't do what is expected, you are close to a bug.
To see what your code is doing: Just set a breakpoint and see your code performing, the debugger allow you to execute lines 1 by 1 and to inspect variables as it execute.

Debugger - Wikipedia, the free encyclopedia[^]

Mastering Debugging in Visual Studio 2010 - A Beginner's Guide[^]
Basic Debugging with Visual Studio 2010 - YouTube[^]

1.11 — Debugging your program (stepping and breakpoints) | Learn C++[^]

The debugger is here to only show you what your code is doing and your task is to compare with what it should do.
 
Share this answer
 
With Palinis bugfix it would be a good idea to split class-definition from
implementation.

C++
class TicTacToe {
public:
	TicTacToe();
	void computers_turn();
	bool champion();
	void playgame();
	void generateGrid();
	void tictacToeMap();

private:
	char map[GRID_SIZE][GRID_SIZE];
	int possibilities[8][3] = {
		{ 0,1,2 },
		{ 3,4,5 },
		{ 6,7,8 },
		{ 0,3,6 },
		{ 1,4,7 },
		{ 2,5,8 },
		{ 0,4,8 },
		{ 6,4,2 } };
};

// Constructor
TicTacToe::TicTacToe()
{
	generateGrid();
}

...

int main(int argc, char *argv[]) 
{
	TicTacToe letsplay;

	while (!letsplay.champion())
	{
		letsplay.tictacToeMap();
		letsplay.playgame();
	}

	return 0;
}


Instead of using the field "Possibilities" the profit situation should be calculated. Maybe you want to change the field size later ...
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900