[C con Clase] Ayuda[minijuego]

Steven Davidson srd4121 en njit.edu
Mar Feb 16 00:23:06 CET 2010


Hola Daniel,

Rido wrote:
> ¡¡¡Buaf ya lo hice!!!   --->   http://cl1p.net/codigo/   <---
> 
> El problema era que había que resetear también las variables punt1 y
> punt2, por lo que hice un procedimiento que lo hiciese y lo puse al
> inicio del case contra la máquina y del case de jugador contra
> jugador.
> 
> Si alguno ve algún otro problema por favor comuníquemelo. Muchas
> gracias a todos por vuestra ayuda.
> 
> En breve haré que se alternen los turnos para que la máquina no tenga
> tanta ventaja y lo subiré a la dirección de siempre:
> http://cl1p.net/codigo/
> 

Como estás terminando el juego, quiero aprovechar para hacerte unos 
comentarios acerca del código fuente:

- El nombre correcto del fichero de cabecera en C++ es <ctime>.

- Define las constantes en C++ en lugar de usar el precompilador. Esto es,

const int CARTAS = 12;
const int PALOS = 4;
const int BARAJA = CARTAS*PALOS;

- Elimina 'typedef', ya que no es necesario.

- Existen 13 elementos para los arrays 'jug1' y 'jug2'. Aconsejo que 
definas y uses una constante para representar esta cantidad, en lugar de 
usar el literal directamente.

- En 'inicializar()', usas 11 y 12 en lugar de la constante 'CARTAS'. 
También usas 1 y 0 para el miembro 'cog', cuando deberías acostumbrarte 
a usar los valores booleanos 'true' y 'false'.

- Has decidido diseñar el programa usando una baraja de 48 cartas, aun 
sabiendo que el juego requiere una de 40. Sugiero que definas una baraja 
de 40 cartas y así no tienes que estar eliminando cartas que no te 
interesa. Desde el punto de vista del juego, sólo existen 40 cartas, y 
por tanto, el programa debería implementar tal diseño.

- En 'intercambiar()', eliges aceptar punteros a las cartas. Creo que 
convendría usar referencias. El diseño de 'intercambiar()' es lo 
suficientemente claro para entender que se requieren las variables y no 
los valores.

- No invoques 'srand()' más de una vez, en un programa. Solamente hazlo 
al principio, en 'main()'. Elimina la invocación en 'jugador()'.

- En 'jugador()', usas 'cont' como índice de 'jug', pero de una manera 
descontrolada. Ten presente que tienes 13 elementos para cada jugador.

Deberías limitar el valor que 'cont' puede guardar para que no acceda a 
elementos fuera del array.

- Usas un bucle para calcular la puntuación total del jugador. Sin 
embargo, haces esto en cada iteración del bucle 'do/while'. Esto es 
superfluo. Haces algo como esto:

do
{
   ...
   for( j=0; j<=cont; j++ )
     punt += jug[j];
   ...
} while( ... );

Sólo nos interesa acumular los puntos en cada iteración. Al final de 
este bucle obtendremos la puntuación total. Simplemente hacemos esto:

do
{
   ...
   punt += jug[cont];
   ...
} while( ... );

- Usas un 'switch/case' para elegir un mensaje acerca del palo de la 
carta. Sugiero crear un array de cadenas constantes estratégicamente 
para que coincida con los palos que has diseñado. Por ejemplo,

const char *szPalos[PALOS] = { "copas", "oros", "espadas", "bastos" };

Ahora no tienes más que usar el miembro 'palo' como índice a esta lista 
de cadenas constantes. Esto es,

cout << baraja[i].num << " de " << szPalos[ baraja[i].palo ];

Así nos evitamos realizar comprobaciones innecesarias.

- Deberías comprobar mejor la opción introducida por el usuario. 
Compruebas si el usuario ha elegido 'D', pero no haces ninguna 
distinción para 'P'. El usuario siempre puede escribir otro carácter que 
no está permitido por tu programa.

- No se sabe la razón de la terminación del bucle y de la función 
'jugador()', porque usas 'vcon' para terminar el bucle y además no 
retornas el estado del juego a través de la función.

Aconsejo crear y mantener un sistema por estados. Por ejemplo,

enum estado_t { VICTORIA_JUG1=1, VICTORIA_JUG2=2 };

Ahora podemos usar estas constantes con una variable que represente el 
estado del juego para determinar si hay victoria y de quién. Por ejemplo,

// inicialmente
estado_t nEstado = 0;

// Agregamos la NO Victoria del jugador 1
nEstado &= ~VICTORIA_JUG1;

// Agregamos la NO Victoria del jugador 2
nEstado &= ~VICTORIA_JUG2;

// Agregamos la Victoria del jugador 1
nEstado |= VICTORIA_JUG1;

// Agregamos la Victoria del jugador 2
nEstado |= VICTORIA_JUG2;


Después del juego, comprobamos el estado del juego para su resolución:

if( nEstado & (VICTORIA_JUG1 | VICTORIA_JUG2) )
{
   // Ambos jugadores son victoriosos <= 7.5
   // Resolución: Determinar cuál de los dos jugadores es el ganador
}
else if( nEstado & VICTORIA_JUG1 )
   cout << "El jugador 1 se planta" << endl << endl;
else if( nEstado & VICTORIA_JUG2 )
   cout << "El jugador 2 se planta" << endl << endl;
else
   cout << "No hay ganadores" << endl << endl;

- Lo mismo sucede con 'maq()'.

- Aconsejo rediseñar las funciones 'jugador()' y 'maq()'. A veces estas 
funciones implementan las tareas del jugador (o máquina), pero otras 
veces tratan las tareas del juego en sí. Esto es incorrecto a mi 
parecer. Cada función debe realizar la tarea imputada; ni más ni menos. 
Si necesitas más tareas, entonces cada función debe comunicarse con el 
exterior pasando la información interesada, para procesarla y 
posiblemente para tomar otras decisiones.

Si te fijas, tanto 'jugador()' como 'maq()' son muy parecidas. Desde el 
punto de vista de diseño, realmente no existe mucha diferencia entre un 
jugador humano y otro automático. La diferencia está en la decisión de 
aceptar o no otra carta.


Espero que todo esto te oriente.

Steven





Más información sobre la lista de distribución Cconclase