9 PAC6

9.1 Exemple: llistaCartes

El plantejament és el següent: imaginem que tenim una llista de cartes de tipus DIAMANTS, CORS, TREVOLS i PIQUES; el que volem aconseguir és filtrar aquesta llista per un tipus determinat de carta, DIAMANTS, i afegir totes aquestes cartes de DIAMANTS a una altra llista.

Una possible implementació seria:

/* Exemple CA0901 */
#include <stdio.h>
#include <stdbool.h>

/* Definició del model de cartes segons l'enllaç:
 *  https://ca.wikipedia.org/wiki/Joc_de_cartes#Baralla_francesa
 */

#define MAX_CARTES 54+1

/* El terme "coll" equival a "baraja". */
typedef enum {DIAMANTS, PIQUES, TREVOLS, CORS} tColl;

typedef struct {
    char valor;
    tColl coll;
} tCarta;

typedef struct {
    tCarta cartes[MAX_CARTES];
    int nCartes;
} tCartesList;

/* Predeclaració de les accions i les funcions. */
void initList();
void insert(tCartesList *llista, tCarta carta, int index);
void delete(tCartesList *llista, int index);
void get(tCartesList llista, int index, tCarta *carta);
bool isEnd(tCartesList llista, int pos);
bool isEmptyList(tCartesList llista);
bool isFullList(tCartesList llista);
void printList(tCartesList llista);
void getCartesByColl(tCartesList llista, tColl coll, tCartesList *llistaByColl);
void copiarCarta(tCarta *desti, tCarta origen);

/* Programa principal. */
int main(int argc, char **argv) {
    tCarta carta1, carta2, carta3, carta4, carta5;
    tCartesList llistaCartes, llistaCartesDiamants;

    /* Creem les dues llistes. */
    initList(&llistaCartes);
    initList(&llistaCartesDiamants);

    /* Definim una sèrie de cartes. */
    carta1.valor = '3';
    carta1.coll = CORS;
    carta2.valor = 'A';
    carta2.coll = DIAMANTS;
    carta3.valor = 'J';
    carta3.coll = TREVOLS;
    carta4.valor = '5';
    carta4.coll = DIAMANTS;
    carta5.valor = 'Q';
    carta5.coll = PIQUES;

    /* I les afegim a la llista genèrica de cartes. */
    insert(&llistaCartes, carta1, 0);
    insert(&llistaCartes, carta2, 1);
    insert(&llistaCartes, carta3, 2);
    insert(&llistaCartes, carta4, 3);
    insert(&llistaCartes, carta5, 4);

    /* Mostrem el contingut de la llista de cartes
     * per pantalla, amb l'acció printList.
     */
    printf("Contingut de la llista 'llistaCartes' :\n");
    printList(llistaCartes);

    /* Ara volem filtrar la llista genèrica de cartes amb
     * un dels colls possibles. Concretament volem separar 
     * de la llista genèrica de cartes aquelles que siguin 
     * del coll DIAMANTS; ho fem mitjançant la crida a 
     * l'acció getCartesByColl. Per veure el seu funcionament,
     * reviseu el comentari fet en la implementació d'aquesta
     * acció.
     */
    getCartesByColl(llistaCartes, DIAMANTS, &llistaCartesDiamants);

    /* I mostrem ara el contingut de la llista que conté
     * únicament les cartes del coll DIAMANTS.
     */
    printf("Contingut de la llista 'llistaCartesDiamants' :\n");
    printList(llistaCartesDiamants);
    return 0;
}

/* Implementació dels mètodes de la llista: he fet un copy/paste
 * de la codificació C de l'exemple 19_12 de la xWiki, canviant
 * el genèric "elem" per "tCarta", i el genèric "list" per "tCartesList",
 * ja que aquests seran els elements amb els que treballarem
 * en aquest exemple.
 */
void initList(tCartesList *llista) {
    llista->nCartes = 0;
}

void insert(tCartesList *llista, tCarta carta, int index) {
    int i;
    if (llista->nCartes == MAX_CARTES) {
        printf("\n Full list \n");
    } else {
        for (i=llista->nCartes-1; i>=index; i--) {
            llista->cartes[i+1] = llista->cartes[i];
        }
        llista->nCartes++;
        llista->cartes[index]=carta;
    }
}

void delete(tCartesList *llista, int index) {
    int i;
    if (llista->nCartes == 0) {
        printf("\n Empty list\n");
    } else {
        for (i=index; i<llista->nCartes-1; i++) {
            llista->cartes[i] = llista->cartes[i+1];
        }
        llista->nCartes--;
    }
}

void get(tCartesList llista, int index, tCarta *carta) {
    if (llista.nCartes == 0) {
        printf("\n Empty list \n");
    } else {
        copiarCarta(carta, llista.cartes[index]);
    }
}

bool isEnd(tCartesList llista, int pos) {
    return (pos >= llista.nCartes);
}

bool isEmptyList(tCartesList llista) {
    return (llista.nCartes == 0);
}

bool isFullList(tCartesList llista) {
    return (llista.nCartes == MAX_CARTES);
}

/* A continuació s'implementaran dues noves accions que
 * no surten ja a l'exemple 19_12. La primera acció, 
 * printList, imprimeix per pantalla una llista. La segona
 * acció, getCartesByColl, permet fer un filtratge de 
 * cartes sobre una llista. 
 */
void printList(tCartesList llista) {
    int i;
    tCarta cartaAux;
    i = 0;
    while (!isEnd(llista, i)) {
        get(llista, i, &cartaAux);
        if (cartaAux.coll == DIAMANTS) {
            printf(" [%c] de DIAMANTS\n", cartaAux.valor);
        } else if (cartaAux.coll == PIQUES) {
            printf(" [%c] de PIQUES\n", cartaAux.valor);
        } else if (cartaAux.coll == TREVOLS) {
            printf(" [%c] de TREVOLS\n", cartaAux.valor);
        } else if (cartaAux.coll == CORS) {
            printf(" [%c] de CORS\n", cartaAux.valor);
        }
        i = i + 1;
    }
}

/* La següent acció, getCartesByColl, rep tres paràmetres:
 * - tCartesList llista (in): llista sobre la qual aplicarem el filtre.
 * - tColl tipus (in): correspon al tipus de coll que utilitzarem per 
 *   fer el filtratge; per exemple, si com a coll indiquem 
 *   DIAMANTS significa que el filtratge el farem
 *   sobre les cartes de tipus DIAMANTS.
 * - tCartesList llistaByColl (out): llista de sortida en la qual 
 *   s'hi inclouran aquelles cartes de la llista d'entrada que 
 *   són del coll tipus.
 */
void getCartesByColl(tCartesList llista, tColl tipus, tCartesList *llistaByColl) {
    int i, j;
    tCarta carta;
    
    initList(llistaByColl);
    i = 0;
    j = 0;

    /* Amb un bucle i la funció end(), controlem que no 
     * hem arribat al final de la llista 
     */
    while (!isEnd(llista, i)) {

        /* Obtenim la carta de la posició i */
        get(llista, i, &carta);

        /* Si la carta és del coll indicat per tipus, 
         * s'afegeix a la llista de sortida .
         */
        if (carta.coll == tipus) {
            insert(llistaByColl, carta, j);
            j = j + 1;
        }
        i = i + 1;
    }
}

/* Acció que permet copiar el contingut d'una tupla 
 * tCarta a una altra tupla.
 */
void copiarCarta(tCarta *desti, tCarta origen) {
    desti->valor = origen.valor;
    desti->coll = origen.coll;
}