9 PEC6

9.1 Ejemplo: listaCartas

El planteamiento es el siguiente: imaginemos que tenemos una lista de cartas de tipo DIAMANTES, CORAZONES, TREVOLES y PICAS; lo que queremos conseguir es filtrar esta lista para un tipo determinado de carta, DIAMANTES, y añadir todas estas cartas de DIAMANTES a otra lista.

Una posible implementación sería:

/* Ejemplo ES0901 */
#include <stdio.h>
#include <stdbool.h>

/* Definición del modelo de cartas según el enlace:
 *  https://es.wikipedia.org/wiki/Baraja_francesa
 */

#define MAX_CARTAS 54+1
#define MAX_DIAMANTES_CARTAS 13+1

/* El término "palo" equivale a "baraja". */
typedef enum {DIAMANTES, PICAS, TREVOLES, CORAZONES} tPalo;

typedef struct {
    char valor;
    tPalo palo;
} tCarta;

typedef struct {
    tCarta cartas[MAX_CARTAS];
    int nCartas;
} tCartasList;

/* Predeclaración de las funciones y acciones. */
void initList();
void insert(tCartasList *lista, tCarta carta, int indice);
void delete(tCartasList *lista, int indice);
void get(tCartasList lista, int indice, tCarta *carta);
bool isEnd(tCartasList lista, int pos);
bool isEmptyList(tCartasList lista);
bool isFullList(tCartasList lista);
void printList(tCartasList lista);
void getCartasByPalo(tCartasList lista, tPalo palo, tCartasList *listaByPalo);
void copiarCarta(tCarta *destino, tCarta origen);

/* Programa principal. */
int main(int argc, char **argv) {
    tCarta carta1, carta2, carta3, carta4, carta5;
    tCartasList listaCartas, listaCartasDiamantes;

    /* Creamos las dos listas. */
    initList(&listaCartas);
    initList(&listaCartasDiamantes);

    /* Definimos una serie de cartas. */
    carta1.valor = '3';
    carta1.palo = CORAZONES;
    carta2.valor = 'A';
    carta2.palo = DIAMANTES;
    carta3.valor = 'J';
    carta3.palo = TREVOLES;
    carta4.valor = '5';
    carta4.palo = DIAMANTES;
    carta5.valor = 'Q';
    carta5.palo = PICAS;

    /* Y las añadimos a la lista genérica de cartas. */
    insert(&listaCartas, carta1, 0);
    insert(&listaCartas, carta2, 1);
    insert(&listaCartas, carta3, 2);
    insert(&listaCartas, carta4, 3);
    insert(&listaCartas, carta5, 4);

    /* Mostramos el contenido de la lista de cartas
     * por pantalla mediante la acción printList. 
     */
    printf("Contenido de la lista 'listaCartas' :\n");
    printList(listaCartas);

    /* Ahora queremos filtrar la lista genérica de cartas con
     * uno de los palos posibles. Concretamente queremos separar
     * de la lista genérica de cartas aquellas que sean
     * del palo DIAMANTES; lo hacemos mediante la llamada a
     * la acción getCartasByPalo. Para ver su funcionamiento,
     * revisad el comentario hecho en la implementación de esta
     * acción.
     */
    getCartasByPalo(listaCartas, DIAMANTES, &listaCartasDiamantes);

    /* Y mostramos el contenido de la lista que contiene
     * únicamente las cartas del palo DIAMANTES. 
     */
    printf("Contenido de la lista 'listaCartasDiamantes' :\n");
    printList(listaCartasDiamantes);
    return 0;
}

/* Implementación de los métodos de la lista: se ha hecho un copy/paste
 * de la codificación C del ejemplo 19_12 de la xWiki, cambiando
 * el genérico "elem" por "tCarta", y el genérico "list" por "tCartesList",
 * ya que estos serán los elementos con los que trabajaremos
 * en este ejemplo.
 */
void initList(tCartasList *lista) {
    lista->nCartas = 0;
}

void insert(tCartasList *lista, tCarta carta, int indice) {
    int i;
    if (lista->nCartas == MAX_CARTAS) {
        printf("\n Full list \n");
    } else {
        for (i=lista->nCartas-1; i>=indice; i--) {
            lista->cartas[i+1] = lista->cartas[i];
        }
        lista->nCartas++;
        lista->cartas[indice]=carta;
    }
}

void delete(tCartasList *lista, int indice) {
    int i;
    if (lista->nCartas == 0) {
        printf("\n Empty list\n");
    } else {
        for (i=indice; i<lista->nCartas-1; i++) {
            lista->cartas[i] = lista->cartas[i+1];
        }
        lista->nCartas--;
    }
}

void get(tCartasList lista, int indice, tCarta *carta) {
    if (lista.nCartas == 0) {
        printf("\n Empty list \n");
    } else {
        copiarCarta(carta, lista.cartas[indice]);
    }
}

bool isEnd(tCartasList lista, int pos) {
    return (pos >= lista.nCartas);
}

bool isEmptyList(tCartasList lista) {
    return (lista.nCartas == 0);
}

bool isFullList(tCartasList lista) {
    return (lista.nCartas == MAX_CARTAS);
}

/* A continuación se implementarán dos nuevas acciones que
 * no salen en el ejemplo 19_12. La primera acción,
 * printList(), imprime por pantalla una lista. la segunda
 * acción, getCartesByPalo(), permite hacer un filtrado de
 * cartas sobre una lista.
 */
void printList(tCartasList lista) {
    int i;
    tCarta cartaAux;
    i = 0;
    while (!isEnd(lista, i)) {
        get(lista, i, &cartaAux);
        if (cartaAux.palo == DIAMANTES) {
            printf(" [%c] de DIAMANTES\n", cartaAux.valor);
        } else if (cartaAux.palo == PICAS) {
            printf(" [%c] de PICAS\n", cartaAux.valor);
        } else if (cartaAux.palo == TREVOLES) {
            printf(" [%c] de TREVOLES\n", cartaAux.valor);
        } else if (cartaAux.palo == CORAZONES) {
            printf(" [%c] de CORAZONES\n", cartaAux.valor);
        }
        i = i + 1;
    }
}

/* La siguiente acción, getCartesByPalo, recibe tres parámetros:
 * - tCartasList lista (in): lista sobre la que aplicaremos el filtro.
 * - tPalo tipo (in): corresponde al tipo de palo que utilizaremos 
 *   para hacer el filtrado; por ejemplo, si como palo indicamos
 *   DIAMANTES significa que el filtrado lo haremos
 *   sobre las cartas de tipo DIAMANTES.
 * - tCartasList listaByPalo (out): lista de salida en la 
 *   que se incluirán aquellas cartas de la lista de entrada que 
 *   son del palo tipo.
 */
void getCartasByPalo(tCartasList lista, tPalo tipo, tCartasList *listaByPalo) {
    int i, j;
    tCarta carta;

    initList(listaByPalo);
    i = 0;
    j = 0;

    /* Con un bucle y la función end(), controlamos que no 
     * hayamos llegado al final de la lista.
     */
    while (!isEnd(lista, i)) {

        /* Obtenemos la carta de la posición i */
        get(lista, i, &carta);

        /* Si la carta es del palo indicado por tipo, 
         * se añade a la lista de salida.
         */
        if (carta.palo == tipo) {
            insert(listaByPalo, carta, j);
            j = j + 1;
        }
        i = i + 1;
    }
}

/* Acción que permite copiar el contenido de una tupla
 * tCarta a otra tupla del mismo tipo.
 */
void copiarCarta(tCarta *destino, tCarta origen) {
    destino->valor = origen.valor;
    destino->palo = origen.palo;
}