Tic tac toe program

Hi everyone, i am currently doing a progrma that runs tictac toe and saves the previous results, i am having issues with a multiple call to a function wich allows me to run the game, i need to call it but make it start form 0, instead you can play but the next round it will be filled with the previous round. Any help is wellcomed

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267

// PAQUETES IMPORTADOS
#include <iostream>
#include <cstdlib>
#include <fstream>
// PERMITE USAR LAS FUNCIONES DE ENTRADA Y SALIDA
using namespace std;
// DECLARACION DE ARREGLO DE VARIABLES CHAR
char cuadro[10] = {'o','1','2','3','4','5','6','7','8','9'};
string jugador1;
string jugador2;
int ronda;
// INVOCA METODOS REVISAR GANADOR Y TABLERO
int RevisarGanador();
void tablero();
int iniciarPartida();
void crearArchivo();
// INICIO DEL MAIN
int main()
{
    // DECLARACION DE VARIABLE TIPO INT PARA SELECCIONAR LA OPCION EN EL MENU
    int opcionMenu;
    // IMPRIME LAS INSTRUCCIONES PARA SELECCIONAR LA OPCION
    cout<<"\n Introduzca la opcion deseada";
    cout<<"\n 1.Iniciar Partida \n 2.Ver Marcadores \n 3.Salir\n";
    // ASIGNA LA OPCION DIGITADA
    cin>>opcionMenu;
    // ASIGNA LA OPCION DIGITADA CON UN CASO
    switch (opcionMenu)

    {
        // DESPLIEGA LA INTERFAZ DE JUEGO PARA EL USUARIO
        // CASO 1
        case 1:
        {

            // INSTRUCCIONES PARA SOLICITAR Y ALAMACENAR LOS NOMBRES DE LOS JUGADORES
            cout<<"Ingrese el nombre del Jugador 1"<<endl;
            cin>>jugador1;
            cout<< "Ingrese el nombre del Jugador 2"<<endl;
            cin>>jugador2;
            // LLAMADA AL METODO INICIARPARTIDA PARA DAR INICIO A LA PARTIDA

            iniciarPartida();
            iniciarPartida();
            iniciarPartida();
            iniciarPartida();

            // LLAMADA A EL METODO CREAR ARCHIVO PARA ALMACENAR LOS DATOS EN UN ARCHIVO .TXT
            crearArchivo();

            }
            // CIERRA CON EXITO EL PROGRAMA
            return 0;
        // CASO 2
        case 2:
            {
                //
                std::string line_;
                ifstream file_("Marcadores.txt");
                // COMPRUEBA SI EL ARCHIVO ESTA ABIERTO
                if (file_.is_open())
                {

                    while(getline(file_,line_))
                    {
                      std::cout<<line_<<'\n';
                    }
                    // CIERRA EL ARCHIVO
                    file_.close();
                }
                // EN CASO DE QUE EL ARCHIVO NO ESTE ABIRTO IMPRIME MENSAJE DE NOTIFICACION
                else

                    std::cout<<"El archivo no esta abierto"<<'\n';
                    std::cin.get();
                // CIERRA LA FASE 2 CON EXITO
                cout << "Se ha cerrado con exito";
                return 0;
                }
        // CASO 3
        case 3:
            {
                //INFORMA LA SALIDA CON EXITO DEL PROGRAMA
                cout<<"\n Se ha salido con exito del programa";
                return 0;
            }



    }

}



/*
    FUNCION PARA DEVOLVER EL ESTADO DEL JUEGO
    1 EL JUEGO FINALIZO CON RESULTADO
    -1 EL JUEGO SIGUE EN PROGRESO
    O EL JUEGO TERMINO SIN RESULTADO
*/
// METODO PARA REVISAR EL GANADOR, DEVUELVE GANADOR
// SE ENCARGA DE COMPARAR CUADROS, EN ESTE CASO 3 EN LINEA, EN CASO DE QUE SEAN IGUALES DEVUELVE 1 PARA GANADOR
int RevisarGanador()
{
    // COMPARA CUADRO 1 CON 2 Y CUADRO DOS CON 3
    if (cuadro[1] == cuadro[2] && cuadro[2] == cuadro[3])

        return 1;
    // COMPARA CUADRO 4 CON 5 Y CUADRO 5 CON 6
    else if (cuadro[4] == cuadro[5] && cuadro[5] == cuadro[6])

        return 1;
    // COMPARA CUADRO 7 CON 8 Y CAUDRO 8 CON 9
    else if (cuadro[7] == cuadro[8] && cuadro[8] == cuadro[9])

        return 1;
    // COMPARA CUADRO 1 CON 4 Y CUADRO 4 CON 7
    else if (cuadro[1] == cuadro[4] && cuadro[4] == cuadro[7])

        return 1;
    // COMPARA CUADRO 2 CON CUADRO 5 Y CUADRO 5 CON 8
    else if (cuadro[2] == cuadro[5] && cuadro[5] == cuadro[8])

        return 1;
    // COMPARA CUADRO 3 CON  6 Y CUADRO 6 CON 9
    else if (cuadro[3] == cuadro[6] && cuadro[6] == cuadro[9])

        return 1;
    // COMPARA CUADRO 1 CON 5 Y CUADRO 5 CON 9
    else if (cuadro[1] == cuadro[5] && cuadro[5] == cuadro[9])

        return 1;
    // COMPARA CUADRO 3 CON 5 Y CUADRO 5 CON 7
    else if (cuadro[3] == cuadro[5] && cuadro[5] == cuadro[7])

        return 1;
    // ESTABLECE UN "DEFAULT" PARA EL CASO EN QUE LAS COMPARACIONES ANTERIORES NO SE CUMPLAN
    else if (cuadro[1] != '1' && cuadro[2] != '2' && cuadro[3] != '3'
                    && cuadro[4] != '4' && cuadro[5] != '5' && cuadro[6] != '6'
                  && cuadro[7] != '7' && cuadro[8] != '8' && cuadro[9] != '9')

        return 0;
    // ESTABLECE CASO DE MANEJO EN CASO DE QUE OCURRA UN ERROR NO PREVISTO
    else
        return -1;
}

// FUNCION PARA DIBUJAR EL TABLERO DEL JUEGO
void tablero()
{

    system("cls");
    // IMPRIME NOMBRE DEL JUEGO
    cout << "\n\n   Tres en linea\n\n";
    cout << "   Ronda: \n  " <<endl;

    // IMPRIME LOS JUGADORS Y LA OPCION QUE UTILIZARAN ENTRE "X" Y "O"
    cout <<"   "<<jugador1<<" (X)  -  "<<jugador2<<" (O)" << endl << endl;
    cout << endl;
    // IMPRIME LA PARTE GRÁFICA PARA VISUALIZAR EL CUADRO
    cout << "       |     |     " << endl;
    cout << "  " << cuadro[1] << "    |  " << cuadro[2] << "  |  " << cuadro[3] << endl;

    cout << "  _____|_____|_____" << endl;
    cout << "       |     |     " << endl;

    cout << "  " << cuadro[4] << "    |  " << cuadro[5] << "  |  " << cuadro[6] << endl;

    cout << "  _____|_____|_____" << endl;
    cout << "       |     |     " << endl;

    cout << "  " << cuadro[7] << "    |  " << cuadro[8] << "  |  " << cuadro[9] << endl;

    cout << "       |     |     " << endl << endl;
}
int iniciarPartida()
{
    int jugador = 1;
    int i;
    int eleccion;
    char simbolo;
    int n = 0;
    int cuenta = 0;
    while (cuenta<=3)
    {
        do
        {
            // INVOCA METODO TABLERO
            tablero();
            // IGUALA LA VARIABLE JUGADOR A JUGADOR 1 Y JUGADOR 2
            jugador=(jugador%2)?1:2;
            // IMPRIME INSTRUCCION DE INGRESAR UN NUMERO
            cout << "Jugador " << jugador << ", Ingese un numero:  ";
            // CAPTA LA ELECCION
            cin >> eleccion;
            // ASIGNA LOS SIMBOLOS TIPO CHAR A LA ELECCION DEL JUGAR, X PARA JUGADOR 1 O PARA JUGADOR 2
            simbolo=(jugador == 1) ? 'X' : 'O';
            // CICLOS IF Y ELSE PARA ASIGNAR  EL SIMBOLO AL NUMERO ELEGIDO
            if (eleccion == 1 && cuadro[1] == '1')
                cuadro[1] = simbolo;
            else if (eleccion == 2 && cuadro[2] == '2')
                cuadro[2] = simbolo;
            else if (eleccion == 3 && cuadro[3] == '3')
                cuadro[3] = simbolo;
            else if (eleccion == 4 && cuadro[4] == '4')
                cuadro[4] = simbolo;
            else if (eleccion == 5 && cuadro[5] == '5')
                cuadro[5] = simbolo;
            else if (eleccion == 6 && cuadro[6] == '6')
                cuadro[6] = simbolo;
            else if (eleccion == 7 && cuadro[7] == '7')
                cuadro[7] = simbolo;
            else if (eleccion == 8 && cuadro[8] == '8')
                cuadro[8] = simbolo;
            else if (eleccion == 9 && cuadro[9] == '9')
                cuadro[9] = simbolo;
            else
            {
                // MANEJA EXCEPCION ANTE UN NUMERO NO POSIBLE O UN CUADRO OCUPADO
                cout<<" Movimiento invalido ";
                jugador--;
                cin.ignore();
                cin.get();
            }
            // REVISA LOS MOVIMIENTOS PARA ASIGNAR UN GANADOR
            i=RevisarGanador();
            // SUMA A JUGADOR QUE GANO
            jugador++;
        }
        while(i==-1);
        //INVOCA A TABLERO CUANDO DEVUELVE -1
            tablero();
            // IMPRIME GANADOR SI DEVUELVE 1
            if(i==1)
                cout<<"==>\aJugador "<<--jugador<<" Gano ";
            else
            // IMPRIME EMPATE EN CASO DE QUE NO SE CUMPLAN LOS REQUISITOS PARAA GANAR
                cout<<"==>\aEmpate";

                cin.ignore();
                cin.get();

            n++;
            cout << cuenta;
            ++cuenta;
    }
}
void crearArchivo()
{
    // DECLARACION DE VARIABLES
    int jugador = 1;
    // CREA ARCHIVO DE TEXTO
    ofstream file_("Marcadores.txt");
    //marcadores_.open("Marcadores.txt");
    // SI EL TEXTO ESTA ABIERTO, INTRODUCE EL JUGADOR QUE GANO
    if (file_.is_open())
    {
        file_<<jugador;
    }
    //CIERRA EL TEXTO
    file_.close();

    std::cin.get();

}
Last edited on
Please edit your post to include code tags.
http://www.cplusplus.com/articles/jEywvCM9/
Hello Donquijota,

PLEASE ALWAYS USE CODE TAGS (the <> formatting button), to the right of this box, when posting code.

Along with the proper indenting it makes it easier to read your code and also easier to respond to your post.

http://www.cplusplus.com/articles/jEywvCM9/
http://www.cplusplus.com/articles/z13hAqkS/

Hint: You can edit your post, highlight your code and press the <> formatting button.
You can use the preview button at the bottom to see how it looks.

I found the second link to be the most help.



This is going to take awhile because of the translations needed just to get an idea of how the program works.

Some things I have found:

Try to avoid using global variables. Anything below their definition can change these variables and it becomes hard to track down where it went wrong. These variables should be in "main" and passed to the functions that need them.

In "main" lines 24 and maybe line 23 to line 90 can be put in a do/while loop. The will avoid the multiple call to "iniciarPartida()" in case 1.

You have the line std::string line_;. It is best to leave names with the underscore (_) to the standard header files that come with the compiler. This avoids any conflict with something that is defined in the standard header files.

The following is the function "tablero". I have adjusted the cout statements to properly print the board.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// FUNCION PARA DIBUJAR EL TABLERO DEL JUEGO
//IFUNCION TO DRAW THE GAME BOARD
void tablero()
{
	system("cls");

	// IMPRIME NOMBRE DEL JUEGO
	cout << "\n\n Tres en linea / Three online\n\n";
	cout << " Ronda / Round: \n " << endl;

	// IMPRIME LOS JUGADORS Y LA OPCION QUE UTILIZARAN ENTRE "X" Y "O"
	// PRINT THE PLAYERS AND THE OPTION THAT THEY USE BETWEEN "X" AND "O"
	cout << " " << jugador1 << " (X) - " << jugador2 << " (O)" << endl << endl;
	cout << endl;

	// IMPRIME LA PARTE GRÁFICA PARA VISUALIZAR EL CUADRO
	// PRINT THE GRAPHIC PART TO VISUALIZE THE TABLE
	cout << "      |     | " << endl;
	cout << "   " << cuadro[1] << "  |  " << cuadro[2] << "  |  " << cuadro[3] << endl;

	cout << " _____|_____|_____" << endl;
	cout << "      |     | " << endl;

	cout << "   " << cuadro[4] << "  |  " << cuadro[5] << "  |  " << cuadro[6] << endl;

	cout << " _____|_____|_____" << endl;
	cout << "      |     | " << endl;

	cout << "   " << cuadro[7] << "  |  " << cuadro[8] << "  |  " << cuadro[9] << endl;

	cout << "      |     | \n"<< endl;
}

This also shows how the blank lines can break up the code to something that is more readable.

I feel that some of the translations may not be accurate, but they help.

The line jugador = (jugador % 2) ? 1 : 2; can be changed to:
1
2
3
4
5
6
7
8
// IGUALA LA VARIABLE JUGADOR A JUGADOR 1 Y JUGADOR 2
// EQUAL THE VARIABLE PLAYER TO PLAYER 1 AND PLAYER 2
//jugador = (jugador % 2) ? 1 : 2;
jugador = jugador % 2;

// ASIGNA LOS SIMBOLOS TIPO CHAR A LA ELECCION DEL JUGAR, X PARA JUGADOR 1 O PARA JUGADOR 2
// ASSIGN CHAR CHARTER SYMBOLS TO THE CHOICE OF PLAY, 'X' FOR PLAYER 1 OR 'O'FOR PLAYER 2
simbolo = jugador ? 'X' : 'O'; // <--- jugador / player, simbolo / symbol. 

These two bits of code should be done together. Also notice that the () are not needed, but acceptable if you use them.

I also changes this cout << "Jugador " << simbolo << ", Ingese un numero / Enter a number: ";.

Looking at the if/else if statements I am thinking you could use:
1
2
3
4
if (eleccion == 1 && cuadro[eleccion] == '1') // <--- eleccion / choice.
cuadro[eleccion] = simbolo;
else if (eleccion == 2 && cuadro[eleccion] == '2')
cuadro[eleccion] = simbolo;

I believe it should work, but I have not tried this yet.

This started me thinking about char cuadro[10] = { 'o','1','2','3','4','5','6','7','8','9' };. I would make the first element either a space or better a "\0".
char cuadro[10] = { '\0','1','2','3','4','5','6','7','8','9' };. Since you are not using that element it really does not make any difference what you use, but the "\0" would be the better choice.

For now that is as far as I have achieved. I will figure out more when I learn more.

Hope that helps,

Andy
thank you andy i ll try every single advice you gave me and sorry my main lenguage is spanish and i thought it did not matter is anotations were in spanish but now i see what u guys meaned.
Hello Donquijota,

I have managed to get a little farther.

I moved most of the global variables to "main" with the exception of "cuadro" I put in the "iniciarPartida" function.

the prototypes now look like:
1
2
3
4
int RevisarGanador(std::string& cuadro);
void tablero(std::string& cuadro, std::string& jugador1, std::string& jugador2, int ronda);
int iniciarPartida(std::string& jugador1, std::string& jugador2, int ronda);
void crearArchivo();  // <--- Not worked with this yet. 


For now in "main" in "case 1" I have used one function call to "iniciarPartida" then I notices that this function returns a value thet is never captured in "main" or used.

Starting with the function "iniciarPartida" I did this:
1
2
3
4
int iniciarPartida(std::string& jugador1, std::string& jugador2, int ronda)
{
	const std::string constCuadro{ " 123456789" };
	std::string cuadro = cCuadro;

The rest of the variables work well.

I made "cuadro" a std::string which will work just the same as the character array that you started with. The string makes it easier to work with as you will see.

in the while loop while (cuenta <= 3. be careful with using "<=". This will give you 4 rounds. I am guessing that you want 3 rounds which means you would have to use while (cuenta < 3).

For the in/else if statements I did find that this works:
1
2
3
4
if (eleccion == 1 && cuadro[eleccion] == '1') // <--- eleccion / choice.
	cuadro[eleccion] = simbolo;
else if (eleccion == 2 && cuadro[eleccion] == '2')
	cuadro[eleccion] = simbolo;

I changed the else part this way:
1
2
3
4
5
6
7
8
9
10
11
12
else
{
	// MANEJA EXCEPCION ANTE UN NUMERO NO POSIBLE O UN CUADRO OCUPADO
	// EXCEPTION HANDLING BEFORE A NON-POSSIBLE NUMBER OR A BUSY TABLE
	cout << "\n    Movimiento invalido / Invalid movement ";
	jugador--;
	//cin.ignore(); // <--- Ignores one character or the new line whichever comes first.
			// <--- Ignora un carácter o la nueva línea, lo que ocurra primero.
	std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');  // <--- Requires header file <limits>.
	std::cout << "\n\n    Press Enter to continue: ";
	cin.get();
}

on Line 5 I have been indenting an error message with at least 4 spaces to set it off from the rest of the output.

Line 9 is a better way of using the "cin.ignore". It is more portable and can be used by more systems. Meaning operating systems and compilers.

Line 10 is so you are not looking at a flashing cursor and wondering what to do. The whole of lines 9 - 11 tend to do the best job. and sometimes line 9 is not needed. It depends on the preceding code.

The line i = RevisarGanador(cuadro); passes the the string to the function to use.

Following the do/while loop I am not sure what you wanted to de with this:
1
2
//INVOCA A TABLERO CUANDO DEVUELVE -1 / NEVER BOARD WHEN RETURNING -1
tablero(cuadro, jugador1, jugador2, ronda);

Because it always calls the function. It does appear to work properly.

This is just an adjustment to the "cout" statements:
1
2
3
4
5
6
7
// IMPRIME GANADOR SI DEVUELVE 1
if (i == 1)
	cout << "   ==>\aJugador " << (--jugador?'X':'O') << " Gano / Won ";
else
	// IMPRIME EMPATE EN CASO DE QUE NO SE CUMPLAN LOS REQUISITOS PARAA GANAR
	// PRINT TIE IN THE EVENT THAT THE REQUIREMENTS ARE NOT FULFILLED TO WIN
	cout << "   ==>\aEmpate / Tie";


Then I changed your "cin.ignore()" to :
1
2
3
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');  // <--- Requires header file <limits>.
std::cout << "\n\n Press Enter to continue: ";
cin.get();


Just before the close of the while loop I have this:
1
2
3
4
5
6
cuadro = cCuadro; // <--- Resets the string. / Restablece la cadena.

n++;
ronda++;  // <--- Added. / Adicional
//cout << cuenta; // <--- Not really needed. / Realmente no es necesario
++cuenta;

Defining "cuadro" as a "std::string" makes this much easier. The simple assignment on line 1 resets the board. Which is what you need in the first place.

Something you might consider is adding to this function a way of keeping track of how many rounds each player wins. Just thinking yo would define that variables in "main" and pass them to the function by reference then at the end of the program use that information to print out the stats of who won haw many rounds.

The only part I have not worked on is the "crearArchivo" function. I am not sure what you want to do with this or when. I will start working on this.

Hope that helps,

Andy
Hello Donquijota,

After I posted I noticed that you figured out the code tags. Muchas gracias.

Now a few blank lines in some places and less in others and it will be good.

Andy
Thank you for all, you have been of much help! thank you for taking your time teaching me.
Handy Andy wrote:
You have the line std::string line_;. It is best to leave names with the underscore (_) to the standard header files that come with the compiler. This avoids any conflict with something that is defined in the standard header files.

Nonsense. Using trailing underscores is just fine, and is a very common naming convention.

There are some rules restricting use of leading underscores, but that doesn't impact anything the OP wrote.
Last edited on
Topic archived. No new replies allowed.