Bienvenidos sean a este post, hoy veremos un concepto mas en conjunto con otro para completar al mazo.
Hoy repasaremos un tema que vimos en este post como es la aleatoriedad e introduciremos uno nuevo como son las estructureas con array de estructuras, de lo cual hablamos en este post, pero para esto debemos modificar el codigo que estuvimos trabajando hasta ahora, sino lo poseen lo pueden descargar desde el siguiente link:
Simplemente extraigan los dos archivos en el mismo directorio, una vez realizado simplemente abran el archivo cartas.h y comenzaremos a hacer las primeras modificaciones, la primera sera agregar un nuevo struct al cual llamaremos Mazo con el siguiente codigo:
typedef struct {
Carta ordenadas[ cCartasEnMazo ];
Carta* mezclado[ cCartasEnMazo ];
int totalCartas;
bool bEstaMezclado;
} Mazo;
Como ahora trabajaremos con aleatoriedad necesitaremos tener dos datos para trabajar, por un lado nuestro mazo completamente ordenado y por otro lado debermos tener un mazo con nuestras cartas mezcladas, aqui entran en accion los dos primeros elementos, ya que el primero nos permitira almacenar los elementos del mazo, el segundo es un apuntador a los elementos del anterior pero lo usaremos para mezclar el mazo, tendremos una variable para el total de cartas para cada jugador y por ultimo una variable que sera la encargada de saber si el mazo esta mezcclado o no, ya veremos porque, nuestro siguiente paso sera modificar la funcion encargada de iniciar el mazo, para ello tomaremos a IniciarMazo y lo modificaremos de la siguiente manera:
void IniciarMazo( Mazo* aMazo )
{
Numero n[]={ uno, dos, tres, cuatro, cinco, seis,
siete, ocho, nueve, sota, caballo, rey };
Carta* aC;
for(int i=0; i < cCartasEnPalo; i++)
{
aC=&(aMazo->ordenadas[i + (0*cCartasEnPalo)]);
IniciarCarta(aC, oro, n[i]);
aC=&(aMazo->ordenadas[i + (1*cCartasEnPalo)]);
IniciarCarta(aC, copa, n[i]);
aC=&(aMazo->ordenadas[i + (2*cCartasEnPalo)]);
IniciarCarta(aC, basto, n[i]);
aC=&(aMazo->ordenadas[i + (3*cCartasEnPalo)]);
IniciarCarta(aC, espada, n[i]);
}
for(int i=0; i < cCartasEnMazo; i++)
aMazo->mezclado[i] = &(aMazo->ordenadas[i]);
aMazo->bEstaMezclado = false;
aMazo->totalCartas = 0;
}
Es muy parecido al codigo que teniamos anteriormente seguimos teniendo un array conteniendo todos los valores de nuestra carta, seguimos teniendo un apuntador de tipo Carta, despues tenemos el bucle for que pasara por las doce cartas de cada palo y por medio de una operacion que explicamos en este post iremos iniciando cada carta, la unica diferencia con el codigo anterior es que ahora usaremos a ordenadas para almacenar el valor en lugar de un objeto especifico, luego por medio de otro bucle for iniciaremos al mazo mezclado y para ello simplemente pasaremos la direccion de memoria de los elementos ordenados anteriormente, por ultimo estableceremos como false a la variable que verifica si se mezclo el mazo y establecemos el valor de 0 a totalCartas, nuestro siguiente paso sera agregar una nueva funcion la cual se encargara de mezclar el mazo y para ello agregaremos el siguiente segmento:
void MezclarMazo(Mazo* aMazo)
{
long indiceRand;
srand(time(NULL));
Carta* aCartaTemp;
for(int esteIndice=0; esteIndice < cCartasEnMazo; esteIndice++)
{
indiceRand = rand() % cCartasEnMazo;
aCartaTemp = aMazo->mezclado[esteIndice];
aMazo->mezclado[esteIndice] = aMazo->mezclado[indiceRand];
aMazo->mezclado[indiceRand] = aCartaTemp;
}
aMazo->bEstaMezclado = true;
}
Aca recibiremos el tipo que definimos al comienzo, primero definiremos una variable que sera la encargada de nuestros indices aleatorios, despues estableceremos la semila para la accion de generar numeros aleatorios mediante el PRNG, lo siguiente sera una variable de tipo Carta que nos servira para el intercambio de los apuntadores de las cartas cuando las mezclemos, despues tenemos un bucle for con el cual pasaremos por todas las cartas del mazo, dentro del bloque a la variable indiceRand le asiganremos un valor a la azar entre 0 y 51, valor generado por rand y la constante mediante ese operador, despues a la variable aCartaTemp le asignaremos el valor establecido en mezclador mediante el indice actual, luego este mismo valor le estableceremos uno al azar para finalmente al valor al azar establecer el valor asignado en primera instancia, estas tres lineas seran las encargadas de hacer el efecto de mezclador en nuestro mazo, por ultimo estableceremos como true a la variable encargada de informar que el mazo fue mezclado, con todo esto comentado podemos pasar a modificar la funcion encargada de tomar una carta del mazo de la siguiente forma:
Carta* TomarCartaDelMazo(Mazo *aMazo)
{
Carta* aCarta = aMazo->mezclado[aMazo->totalCartas];
aMazo->mezclado[aMazo->totalCartas] = NULL;
aMazo->totalCartas++;
return aCarta;
}
Aqui como argumento utilizaremos al mazo nuevvamente, nuestro nuevo struct, despues si definiremos una variable de tipo Carta y en ella almacenaremos la carta en mezclado mediante el valor de totalCartas, despues a esa misma posicion le estableceremos el valor NULL para asegurarnos que esa carta no se use nuevamente, despues incrementamos a totalCartas y por ultimo devolvemos el valor que establecimos al comienzo, por ultimo solo nos resta modificar la funcion encargada de mostrar el mazo de la siguiente forma:
void MostrarMazo( Mazo* aMazo )
{
printf("%d cartas en el mazo\n\n", cCartasEnMazo);
printf("El mazo %s mezclado\n",
aMazo->bEstaMezclado ? "esta" : "no esta");
printf("%d cartas para %d jugadores\n",
aMazo->totalCartas, cNumJugadores);
if (aMazo->bEstaMezclado == true)
{
if (aMazo->totalCartas > 0)
{
printf("El mazo restante: \n");
} else {
printf("Todo el mazo mezclado:\n");
}
for(int i=aMazo->totalCartas, j=0;
i < cCartasEnMazo; i++, j++)
{
printf("(%2d)", i+1);
MostrarCarta(aMazo->mezclado[i]);
if (j == 3)
{
printf("\n");
j = -1;
} else {
printf("\t");
}
}
} else {
int indice;
printf("El mazo ordenado:\n");
for(int i=0; i < cCartasEnPalo; i++)
{
indice=i + (0*cCartasEnPalo);
printf(" (%2d)", indice + 1);
MostrarCarta(&(aMazo->ordenadas[indice]));
indice=i + (1*cCartasEnPalo);
printf(" (%2d)", indice + 1);
MostrarCarta(&(aMazo->ordenadas[indice]));
indice=i + (2*cCartasEnPalo);
printf(" (%2d)", indice + 1);
MostrarCarta(&(aMazo->ordenadas[indice]));
indice=i + (3*cCartasEnPalo);
printf(" (%2d)", indice + 1);
MostrarCarta(&(aMazo->ordenadas[indice]));
printf("\n");
}
}
printf("\n\n");
}
Devuelta pasamos como argumento a uno de tipo Mazo, la primera linea indica la cantidad de cartas del mazo, la siguiente nos indica si esta mezclado o no, mediante la variable que esta creada para ello y un operador condicional para establecer el texto de si «esta» o «no esta», la siguiente linea sera para indicar cuantas cartas entregamos a los jugadores, despues tendremos un condicional donde verificamos si fue mezclado o no, en este caso la primera condicion es para el caso de cuando es verdad, el primer condicional sera para indicar el mazo restante porque fueron entregadas las cartas a los jugadores, de lo contrarrio indicaremos que es todo el mazo mezclado, despues tenemos un bucle for donde comenzaremos desde totalCartas, ya sea para mostrar todas o comenzar desde donde repartimos la ultima carta, para ello usaremos dos contadores, uno sera para pasar por todas las cartas, i, y el otro, j, sera para darle formato, en la condicion lo haremos mientras sea menor al total de cartas en el mazo, despues incrementaremos a ambas variables, primero mostraremos el valor de i y luego por medio de MostrarCarta le pasaremos la carta del mazo mezclado, por ultimo tenemos un condicional donde verificamos si j es igual a 3 en caso de ser verdadero pasamos el operador de nueva linea y estableceremos a j con el valor de -1, en caso contrario simplemente pasamos un tabulador para separar a cada carta, con esto terminamos el condicional en caso de que el mazo este mezclado.
Ahora pasemos a ver la parte encargada de cuando no esta mezclada, para el otro caso seguimos manteniendo la misma mecanica que antes pero con la salvedad de que en lugar de apuntar a un objeto llamada carta lo hacemos al elemento ordenadas en el mazo, pero si lo comparan con lo visto en este post veran que es exactamente lo mismo pero ahora con el mazo en lugar de un mazo basado en el tipo Carta, con todo esto veamos como quedo nuestro codigo final del archivo cartas.h:
cartas.h
enum {
cCartasEnMazo = 48,
cCartasEnMano = 3,
cCartasEnPalo = 12,
cNumJugadores = 4
};
typedef enum {
oro = 1,
copa,
basto,
espada
} Palo;
typedef enum {
uno = 1, dos, tres, cuatro, cinco, seis,
siete, ocho, nueve, sota, caballo, rey
} Numero;
typedef struct
{
Palo palo;
int valorPalo;
Numero numero;
int valorNumero;
} Carta;
typedef struct {
int totalCartas;
Carta* jugador[cCartasEnMano];
} Jugador;
typedef struct {
Carta ordenadas[ cCartasEnMazo ];
Carta* mezclado[ cCartasEnMazo ];
int totalCartas;
bool bEstaMezclado;
} Mazo;
void CartaAString(Carta* aCarta,char aCadenaCarta[20])
{
switch(aCarta->numero)
{
case uno: strcpy(aCadenaCarta, "as "); break;
case dos: strcpy(aCadenaCarta, "dos "); break;
case tres: strcpy(aCadenaCarta, "tres "); break;
case cuatro: strcpy(aCadenaCarta, "cuatro "); break;
case cinco: strcpy(aCadenaCarta, "cinco "); break;
case seis: strcpy(aCadenaCarta, "seis "); break;
case siete: strcpy(aCadenaCarta, "siete "); break;
case ocho: strcpy(aCadenaCarta, "ocho "); break;
case nueve: strcpy(aCadenaCarta, "nueve "); break;
case sota: strcpy(aCadenaCarta, "sota "); break;
case caballo: strcpy(aCadenaCarta, "caballo "); break;
case rey: strcpy(aCadenaCarta, "rey "); break;
default: strcpy(aCadenaCarta, "??? "); break;
}
switch(aCarta->palo)
{
case oro: strcat(aCadenaCarta,"de Oro"); break;
case copa: strcat(aCadenaCarta,"de Copas"); break;
case basto: strcat(aCadenaCarta,"de Bastos"); break;
case espada: strcat(aCadenaCarta,"de Espadas"); break;
default: strcat(aCadenaCarta,"de ????"); break;
}
}
void IniciarCarta(Carta* aCarta, Palo p, Numero n)
{
aCarta->palo = p;
aCarta->valorPalo = (int)p;
aCarta->numero = n;
aCarta->valorNumero = (int)n;
}
void MostrarCarta(Carta* aCarta)
{
char cadenaCarta[20] = {0};
CartaAString(aCarta, cadenaCarta);
printf("%18s", cadenaCarta);
}
void IniciarMazo( Mazo* aMazo )
{
Numero n[]={ uno, dos, tres, cuatro, cinco, seis,
siete, ocho, nueve, sota, caballo, rey };
Carta* aC;
for(int i=0; i < cCartasEnPalo; i++)
{
aC=&(aMazo->ordenadas[i + (0*cCartasEnPalo)]);
IniciarCarta(aC, oro, n[i]);
aC=&(aMazo->ordenadas[i + (1*cCartasEnPalo)]);
IniciarCarta(aC, copa, n[i]);
aC=&(aMazo->ordenadas[i + (2*cCartasEnPalo)]);
IniciarCarta(aC, basto, n[i]);
aC=&(aMazo->ordenadas[i + (3*cCartasEnPalo)]);
IniciarCarta(aC, espada, n[i]);
}
for(int i=0; i < cCartasEnMazo; i++)
aMazo->mezclado[i] = &(aMazo->ordenadas[i]);
aMazo->bEstaMezclado = false;
aMazo->totalCartas = 0;
}
void MostrarMazo( Mazo* aMazo )
{
printf("%d cartas en el mazo\n\n", cCartasEnMazo);
printf("El mazo %s mezclado\n",
aMazo->bEstaMezclado ? "esta" : "no esta");
printf("%d cartas para %d jugadores\n",
aMazo->totalCartas, cNumJugadores);
if (aMazo->bEstaMezclado == true)
{
if (aMazo->totalCartas > 0)
{
printf("El mazo restante: \n");
} else {
printf("Todo el mazo mezclado:\n");
}
for(int i=aMazo->totalCartas, j=0;
i < cCartasEnMazo; i++, j++)
{
printf("(%2d)", i+1);
MostrarCarta(aMazo->mezclado[i]);
if (j == 3)
{
printf("\n");
j = -1;
} else {
printf("\t");
}
}
} else {
int indice;
printf("El mazo ordenado:\n");
for(int i=0; i < cCartasEnPalo; i++)
{
indice=i + (0*cCartasEnPalo);
printf(" (%2d)", indice + 1);
MostrarCarta(&(aMazo->ordenadas[indice]));
indice=i + (1*cCartasEnPalo);
printf(" (%2d)", indice + 1);
MostrarCarta(&(aMazo->ordenadas[indice]));
indice=i + (2*cCartasEnPalo);
printf(" (%2d)", indice + 1);
MostrarCarta(&(aMazo->ordenadas[indice]));
indice=i + (3*cCartasEnPalo);
printf(" (%2d)", indice + 1);
MostrarCarta(&(aMazo->ordenadas[indice]));
printf("\n");
}
}
printf("\n\n");
}
void IniciarJugador(Jugador* aJugador)
{
aJugador->totalCartas = 0;
for(int i=0; i < cCartasEnMano; i++)
aJugador->jugador[i] = NULL;
}
void AgregarCartaAJugador(Jugador* aJugador, Carta* aCarta)
{
if(aJugador->totalCartas==cCartasEnMano) return;
aJugador->jugador[ aJugador->totalCartas ] = aCarta;
aJugador->totalCartas++;
}
void MostrarJugador(Jugador* aJugador, char* aCadenaJug, char* aCadenaLider)
{
printf("%s%s\n", aCadenaLider, aCadenaJug);
for(int i=0; i < cCartasEnMano; i++)
{
printf("%s", aCadenaLider);
MostrarCarta(aJugador->jugador[i]);
printf("\n");
}
}
Carta* TomarCartaDelMazo(Mazo *aMazo)
{
Carta* aCarta = aMazo->mezclado[aMazo->totalCartas];
aMazo->mezclado[aMazo->totalCartas] = NULL;
aMazo->totalCartas++;
return aCarta;
}
void MostrarTodosJugadores(Jugador* jugadores[ cNumJugadores ])
{
MostrarJugador(jugadores[0], "Jug 1: ", "");
MostrarJugador(jugadores[1], "Jug 2: ", "");
MostrarJugador(jugadores[2], "Jug 3: ", "");
MostrarJugador(jugadores[3], "Jug 4: ", "");
}
void MezclarMazo(Mazo* aMazo)
{
long indiceRand;
srand(time(NULL));
Carta* aCartaTemp;
for(int esteIndice=0; esteIndice < cCartasEnMazo; esteIndice++)
{
indiceRand = rand() % cCartasEnMazo;
aCartaTemp = aMazo->mezclado[esteIndice];
aMazo->mezclado[esteIndice] = aMazo->mezclado[indiceRand];
aMazo->mezclado[indiceRand] = aCartaTemp;
}
aMazo->bEstaMezclado = true;
}
Solo nos resta tomar el codigo de cartas.c y modificarlo para hacer algunas pruebas, para ello abran el archivo y cambien el codigo actual por el siguiente:
cartas.c
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
#include <time.h>
#include "cartas.h"
int main()
{
Mazo mazo;
Mazo* aMazo = &mazo;
IniciarMazo(aMazo);
MostrarMazo(aMazo);
MezclarMazo(aMazo);
MostrarMazo(aMazo);
}
Va a ser un codigo simple pero efectivo para ver nuestras primeras modificaciones, en este caso agregamos un par de librerias nuevas:
- stdbool.h, para poder utilizar tipos de datos booleanos (bool)
- stdlib.h, esta es la que nos permite utilizar las funciones para los numeros aleatorios
- time.h, esta es para utilizar la funcion time en la semilla de PRNG
Despues declaramos un objeto de tipo Mazo, seguido de un apuntador a este objeto, para despues iniciar nuestro mazo y mostrarlo mediante sus funciones, las otras dos lineas seran para mezclarlo y mostrarlo nuevamente, compilemos y veamos como es su salida mediante el siguiente video
Si ven en el video ejecutamos varias el programa y pudimos ver como el mazo ordenado permanece inalterable pero en cambio las que son «mezcladas» siempre cambian su orden, con esto ya tenemos la capacidad de poder mezclar mediante el uso de rand, en el proximo post lo completaremos.
En resumen, hoy hemos visto como son las estructuras con un array de estructuras, como se crean, como se pueden manipular y como se puede recuperar su informacion, todo esto mediante nuestro ejemplo y ahora tenemos la capacidad de tener nuestro mazo ordenado y mezclado, espero les haya sido de utilidad sigueme en tumblr, Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.


Donación
Es para mantenimento del sitio, gracias!
$1.50
