Tema 9 - Comparació i Alineament de Seqüències

Comparació de dues seqüències d'ADN

Compara dues seqüències d'ADN introduïdes per l'usuari i mostra el percentatge d'identitat.

#include <stdio.h>  /* Inclou la biblioteca estàndard d'entrada/sortida */
                     /* Necessària per a printf() i scanf() */
#include <string.h>  /* Inclou la biblioteca per a funcions de cadenes */
                     /* Necessària per a strlen() */
#include <ctype.h>   /* Inclou la biblioteca per a classificació de caràcters */
                     /* Necessària per a toupper() */

int main(){  /* Funció principal del programa, punt d'entrada d'execució */

    char seq1[501];  /* Array per a la primera seqüència d'ADN */
                     /* Mida 501: fins a 500 caràcters + '\0' */
    char seq2[501];  /* Array per a la segona seqüència d'ADN */
                     /* Mateixa mida que la primera */

    printf("========================================\n");
    printf("  COMPARADOR DE SEQUENCIES D'ADN\n");
    printf("========================================\n\n");

    /* Lectura de les dues seqüències */
    printf("Introdueix la primera sequencia d'ADN: ");  /* Demana la primera seqüència */
    scanf("%500s", seq1);  /* Llegeix fins a 500 caràcters */
                           /* %500s limita la lectura per evitar desbordaments */

    printf("Introdueix la segona sequencia d'ADN: ");  /* Demana la segona seqüència */
    scanf("%500s", seq2);  /* Llegeix la segona seqüència */

    /* Calcula les longituds de les dues seqüències */
    int len1 = strlen(seq1);  /* strlen() retorna el nombre de caràcters (sense '\0') */
    int len2 = strlen(seq2);  /* Longitud de la segona seqüència */

    printf("\n=== INFORMACIO DE LES SEQUENCIES ===\n");
    printf("Sequencia 1: %s (longitud: %d)\n", seq1, len1);  /* Mostra la primera */
    printf("Sequencia 2: %s (longitud: %d)\n", seq2, len2);  /* Mostra la segona */

    /* Converteix ambdues seqüències a majúscules per comparació uniforme */
    for(int i = 0; i < len1; i++)
        seq1[i] = toupper(seq1[i]);  /* toupper() retorna la versió majúscula */
    for(int i = 0; i < len2; i++)
        seq2[i] = toupper(seq2[i]);  /* Converteix cada caràcter */

    /* Determina la longitud per a la comparació */
    /* Si les seqüències tenen longituds diferents, comparem fins a la més curta */
    int min_len = (len1 < len2) ? len1 : len2;  /* Operador ternari: si len1 len2) ? len1 : len2;  /* La longitud més llarga */

    int coincidencies = 0;  /* Comptador de posicions on coincideixen */
                            /* S'inicialitza a 0 per començar el recompte */
    int diferencies = 0;    /* Comptador de posicions on difereixen */
    int gaps = 0;           /* Comptador de posicions no comparables (diferència de longitud) */

    /* Bucle de comparació nucleòtid per nucleòtid */
    for(int i = 0; i < min_len; i++){  /* Recorre fins a la seqüència més curta */
        if(seq1[i] == seq2[i])  /* Compara els caràcters a la mateixa posició */
            coincidencies++;    /* Si són iguals, incrementa coincidències */
        else
            diferencies++;      /* Si són diferents, incrementa diferències */
    }

    /* Calcula les posicions no comparables (diferència de longitud) */
    gaps = max_len - min_len;  /* Les posicions extra de la seqüència més llarga */

    /* Calcula els percentatges */
    float pct_identitat = 0.0;  /* Percentatge d'identitat (coincidències) */
    if(max_len > 0)  /* Evita la divisió per zero */
        pct_identitat = (float)coincidencies / max_len * 100;
        /* Dividim pel max_len perquè les posicions no comparables compten com a diferències */

    float pct_diferencia = 0.0;  /* Percentatge de diferències */
    if(max_len > 0)
        pct_diferencia = (float)diferencies / max_len * 100;

    float pct_gaps = 0.0;  /* Percentatge de gaps (diferència de longitud) */
    if(max_len > 0)
        pct_gaps = (float)gaps / max_len * 100;

    /* Mostra els resultats de la comparació */
    printf("\n=== RESULTATS DE LA COMPARACIO ===\n");
    printf("Coincidencies: %d de %d (%.2f%%)\n", coincidencies, max_len, pct_identitat);
    printf("Diferencies:   %d de %d (%.2f%%)\n", diferencies, max_len, pct_diferencia);
    if(gaps > 0)
        printf("Gaps (longitud diferent): %d de %d (%.2f%%)\n", gaps, max_len, pct_gaps);

    /* Mostra un alineament visual simple */
    printf("\n=== ALINEAMENT VISUAL ===\n");
    printf("Seq1: %s", seq1);  /* Mostra la primera seqüència */
    if(len1 < max_len)
        for(int i = 0; i < gaps; i++) printf("-");  /* Afegeix guions si és més curta */
    printf("\n");

    /* Línia de coincidències: '|' si coincideixen, ' ' si no */
    printf("      ");  /* Espai per alinear */
    for(int i = 0; i < min_len; i++){
        if(seq1[i] == seq2[i])
            printf("|");  /* Barra vertical per a coincidències */
        else
            printf(" ");  /* Espai per a diferències */
    }
    if(gaps > 0)
        for(int i = 0; i < gaps; i++) printf(" ");  /* Espais per als gaps */
    printf("\n");

    printf("Seq2: %s", seq2);  /* Mostra la segona seqüència */
    if(len2 < max_len)
        for(int i = 0; i < gaps; i++) printf("-");  /* Afegeix guions si és més curta */
    printf("\n");

    /* Classificació del grau de similitud */
    printf("\n=== INTERPRETACIO BIOLOGICA ===\n");
    if(pct_identitat > 99.0)
        printf("  Identitat molt alta: possiblement la mateixa sequencia.\n");
    else if(pct_identitat > 90.0)
        printf("  Identitat alta: sequencies molt relacionades (mateix gen, especie propera).\n");
    else if(pct_identitat > 70.0)
        printf("  Identitat moderada: possible relacio evolutiva distant.\n");
    else if(pct_identitat > 50.0)
        printf("  Identitat baixa: possiblement gens diferents.\n");
    else
        printf("  Identitat molt baixa: sequencies no relacionades.\n");

    return 0;  /* Finalitza el programa amb èxit */
}

Detecció de mutacions: transicions i transversions

Llegeix dues seqüències des d'un fitxer i detecta totes les mutacions, indicant si són transicions (A↔G, C↔T) o transversions (altres canvis).

#include <stdio.h>  /* Inclou la biblioteca estàndard d'entrada/sortida */
                     /* Necessària per a printf(), fopen(), fgets(), fclose() */
#include <string.h>  /* Inclou la biblioteca per a funcions de cadenes */
                     /* Necessària per a strlen(), strcpy() */
#include <ctype.h>   /* Inclou la biblioteca per a classificació de caràcters */
                     /* Necessària per a toupper() */

/* Estructura per emmagatzemar informació d'una mutació */
/* Una struct agrupa totes les dades rellevants d'una mutació */
struct Mutacio {
    int posicio;        /* Posició de la mutació (1-based per a l'usuari) */
    char base_original; /* Base en la primera seqüència (seqüència de referència) */
    char base_mutada;   /* Base en la segona seqüència (seqüència mutada) */
    char tipus[20];     /* Tipus de mutació: "Transicio" o "Transversio" */
};

/* Funció per determinar si un canvi és transició o transversió */
/* Retorna 1 si és transició, 0 si és transversió, -1 si és error */
int es_transicio(char b1, char b2){  /* Rep les dues bases a comparar */
    /* Converteix a majúscules per comparació uniforme */
    b1 = toupper(b1);  /* toupper() retorna la versió majúscula */
    b2 = toupper(b2);

    /* Si les bases són iguals, no és una mutació */
    if(b1 == b2) return -1;  /* -1 indica "no és mutació" */

    /* Transicions: canvi entre purines (A↔G) o entre pirimidines (C↔T) */
    /* Purines: Adenina (A) i Guanina (G) */
    if((b1 == 'A' && b2 == 'G') || (b1 == 'G' && b2 == 'A'))
        return 1;  /* És transició (A↔G) */

    /* Pirimidines: Citosina (C) i Timina (T) */
    if((b1 == 'C' && b2 == 'T') || (b1 == 'T' && b2 == 'C'))
        return 1;  /* És transició (C↔T) */

    /* Qualsevol altre canvi és transversió */
    /* Exemples: A↔C, A↔T, G↔C, G↔T (canvi purina↔pirimidina) */
    return 0;  /* És transversió */
}

/* Funció per classificar la mutació en text */
const char* nom_tipus_mutacio(int tipus){  /* Rep 1 (transició) o 0 (transversió) */
    if(tipus == 1)
        return "Transicio";    /* Canvi dins del mateix grup químic */
    else if(tipus == 0)
        return "Transversio";  /* Canvi entre grups químics diferents */
    else
        return "Desconegut";   /* Per seguretat */
}

int main(){  /* Funció principal */

    char seq1[501];  /* Array per a la seqüència de referència */
    char seq2[501];  /* Array per a la seqüència a comparar */
    struct Mutacio mutacions[500];  /* Array per emmagatzemar les mutacions */
                                    /* Com a màxim 500 mutacions (una per posició) */
    int total_mutacions = 0;  /* Comptador de mutacions trobades */
    int transicions = 0;      /* Comptador de transicions */
    int transversions = 0;    /* Comptador de transversions */

    printf("========================================\n");
    printf("  DETECTOR DE MUTACIONS PUNTUALS\n");
    printf("========================================\n\n");

    /* Intenta obrir el fitxer de seqüències */
    FILE *fitxer = fopen("sequencies_mutacions.txt", "r");  /* Obre en mode lectura */
    if(fitxer == NULL){  /* Si el fitxer no existeix */
        printf("No s'ha trobat el fitxer 'sequencies_mutacions.txt'.\n");
        printf("Creant fitxer d'exemple...\n");

        /* Crea un fitxer d'exemple amb dues seqüències */
        fitxer = fopen("sequencies_mutacions.txt", "w");  /* Obre en mode escriptura */
        if(fitxer == NULL){
            printf("Error en crear el fitxer.\n");
            return 1;
        }
        /* Escriu dues seqüències d'exemple amb diverses mutacions */
        fprintf(fitxer, "ATGGCGATCGATCG\n");  /* Primera seqüència (referència) */
        fprintf(fitxer, "ATGGCAATCGATGG\n");  /* Segona seqüència (amb mutacions) */
        fclose(fitxer);

        /* Torna a obrir en mode lectura */
        fitxer = fopen("sequencies_mutacions.txt", "r");
        if(fitxer == NULL) return 1;
        printf("Fitxer d'exemple creat. Executa de nou el programa.\n");
        fclose(fitxer);
        return 0;
    }

    /* Llegeix les dues seqüències del fitxer */
    fgets(seq1, 500, fitxer);  /* Llegeix la primera línia (primera seqüència) */
    fgets(seq2, 500, fitxer);  /* Llegeix la segona línia (segona seqüència) */
    fclose(fitxer);  /* Tanca el fitxer */

    /* Elimina els salts de línia de les seqüències llegides */
    int len1 = strlen(seq1);  /* Longitud de la primera seqüència */
    if(len1 > 0 && seq1[len1-1] == '\n')
        seq1[len1-1] = '\0';  /* Substitueix '\n' per '\0' */

    int len2 = strlen(seq2);  /* Longitud de la segona seqüència */
    if(len2 > 0 && seq2[len2-1] == '\n')
        seq2[len2-1] = '\0';  /* Substitueix '\n' per '\0' */

    /* Actualitza les longituds després d'eliminar '\n' */
    len1 = strlen(seq1);
    len2 = strlen(seq2);

    /* Converteix a majúscules */
    for(int i = 0; i < len1; i++) seq1[i] = toupper(seq1[i]);
    for(int i = 0; i < len2; i++) seq2[i] = toupper(seq2[i]);

    printf("Sequencia de referencia: %s (longitud: %d)\n", seq1, len1);
    printf("Sequencia a comparar:    %s (longitud: %d)\n\n", seq2, len2);

    /* Determina la longitud mínima per a la comparació */
    int min_len = (len1 < len2) ? len1 : len2;
    if(len1 != len2)
        printf("NOTA: Les sequencies tenen longituds diferents. Es compararan %d posicions.\n\n", min_len);

    /* Compara les seqüències nucleòtid per nucleòtid */
    printf("=== MUTACIONS DETECTADES ===\n");
    printf("%-10s %-10s %-10s %-15s\n", "POSICIO", "ORIGINAL", "MUTADA", "TIPUS");
    printf("---------------------------------------------\n");

    for(int i = 0; i < min_len; i++){  /* Recorre les posicions comparables */
        if(seq1[i] != seq2[i]){  /* Si les bases són diferents (hi ha mutació) */
            int tipus = es_transicio(seq1[i], seq2[i]);  /* Determina el tipus */

            /* Emmagatzema la informació de la mutació */
            mutacions[total_mutacions].posicio = i + 1;  /* Posició 1-based */
            mutacions[total_mutacions].base_original = seq1[i];
            mutacions[total_mutacions].base_mutada = seq2[i];
            strcpy(mutacions[total_mutacions].tipus, nom_tipus_mutacio(tipus));

            /* Mostra la mutació per pantalla */
            printf("%-10d %c -> %c    %-15s\n", 
                   i + 1, seq1[i], seq2[i], nom_tipus_mutacio(tipus));

            /* Actualitza els comptadors segons el tipus */
            if(tipus == 1)
                transicions++;     /* Incrementa transicions */
            else if(tipus == 0)
                transversions++;   /* Incrementa transversions */

            total_mutacions++;  /* Incrementa el total de mutacions */
        }
    }

    /* Mostra el resum estadístic */
    printf("\n=== RESUM ESTADISTIC ===\n");
    printf("Total de posicions comparades: %d\n", min_len);
    printf("Total de mutacions: %d\n", total_mutacions);
    printf("  Transicions:  %d (%.1f%%)\n", 
           transicions, 
           total_mutacions > 0 ? (float)transicions/total_mutacions*100 : 0);
    printf("  Transversions: %d (%.1f%%)\n", 
           transversions, 
           total_mutacions > 0 ? (float)transversions/total_mutacions*100 : 0);

    /* Calcula la taxa de mutació */
    float taxa_mutacio = (float)total_mutacions / min_len * 100;
    printf("\nTaxa de mutacio: %.2f%%\n", taxa_mutacio);

    /* Interpretació de la relació transicions/transversions */
    printf("\n=== INTERPRETACIO BIOLOGICA ===\n");
    if(transversions > 0){
        float ratio = (float)transicions / transversions;
        printf("Ratio transicions/transversions: %.2f\n", ratio);
        if(ratio > 2.0)
            printf("  Ratio alt: esperat en sequencies relacionades (purificacio).\n");
        else if(ratio > 1.0)
            printf("  Ratio normal: mutacions aleatories tipiques.\n");
        else
            printf("  Ratio baix: possible saturacio de mutacions.\n");
    }

    /* Informació sobre la importància biològica */
    printf("\n=== INFORMACIO ADDICIONAL ===\n");
    printf("Transicions (A<->G, C<->T):\n");
    printf("  - Canvi dins del mateix grup quimic (purina<->purina o pirimidina<->pirimidina)\n");
    printf("  - Mes frequents en l'evolucio molecular\n");
    printf("  - Menys probables de causar canvis en la proteina\n\n");
    printf("Transversions (altres canvis):\n");
    printf("  - Canvi entre grups quimics diferents (purina<->pirimidina)\n");
    printf("  - Menys frequents pero mes impactants\n");
    printf("  - Major probabilitat de canviar l'aminoacid codificat\n");

    return 0;  /* Finalitza el programa */
}

Matriu de substitució simple per aminoàcids

Implementa una matriu de substitució simple per a aminoàcids (hidrofòbic, polar, carregat) i calcula la similitud entre dues proteïnes curtes.

#include <stdio.h>  /* Inclou la biblioteca estàndard d'entrada/sortida */
                     /* Necessària per a printf() i scanf() */
#include <string.h>  /* Inclou la biblioteca per a funcions de cadenes */
                     /* Necessària per a strlen() i strchr() */
#include <ctype.h>   /* Inclou la biblioteca per a classificació de caràcters */
                     /* Necessària per a toupper() */

/* Constants per a les categories d'aminoàcids */
/* #define crea constants simbòliques que el compilador substitueix */
#define HIDROFOBIC 0   /* Aminoàcids hidrofòbics (apolars) */
#define POLAR 1        /* Aminoàcids polars (sense càrrega) */
#define CARREGAT 2     /* Aminoàcids carregats (positiva o negativa) */
#define ESPECIAL 3     /* Aminoàcids amb propietats especials (cisteïna, glicina, prolina) */

/* Funció per classificar un aminoàcid en una categoria */
/* Retorna la categoria: HIDROFOBIC, POLAR, CARREGAT o ESPECIAL */
int categoria_aminoacid(char aa){  /* Rep la lletra de l'aminoàcid (codi d'una lletra) */
    aa = toupper(aa);  /* Converteix a majúscula per uniformitat */

    /* Classificació basada en les propietats químiques de la cadena lateral */
    switch(aa){
        /* Aminoàcids hidrofòbics: cadenes laterals apolars */
        case 'A': case 'V': case 'L': case 'I':  /* Alanina, Valina, Leucina, Isoleucina */
        case 'M': case 'F': case 'W':           /* Metionina, Fenilalanina, Triptòfan */
            return HIDROFOBIC;  /* Retorna la constant HIDROFOBIC (0) */

        /* Aminoàcids polars: cadenes laterals polars sense càrrega */
        case 'S': case 'T': case 'N': case 'Q':  /* Serina, Treonina, Asparagina, Glutamina */
        case 'Y':                                 /* Tirosina */
            return POLAR;  /* Retorna la constant POLAR (1) */

        /* Aminoàcids carregats: cadenes laterals amb càrrega elèctrica */
        case 'K': case 'R':  /* Lisina, Arginina (càrrega positiva) */
        case 'D': case 'E':  /* Aspartat, Glutamat (càrrega negativa) */
        case 'H':            /* Histidina (càrrega positiva a pH fisiològic) */
            return CARREGAT;  /* Retorna la constant CARREGAT (2) */

        /* Aminoàcids especials: propietats úniques */
        case 'C':  /* Cisteïna: forma ponts disulfur */
        case 'G':  /* Glicina: molt petita, flexible */
        case 'P':  /* Prolina: estructura rígida, trenca hèlixs */
            return ESPECIAL;  /* Retorna la constant ESPECIAL (3) */

        default:
            return -1;  /* Aminoàcid no reconegut */
    }
}

/* Funció per obtenir la puntuació de similitud entre dos aminoàcids */
/* Retorna: 3 = idèntics, 2 = mateixa categoria, 1 = categories compatibles, 0 = molt diferents, -1 = error */
int puntuacio_similitud(char aa1, char aa2){  /* Rep dues lletres d'aminoàcids */
    aa1 = toupper(aa1);  /* Converteix a majúscula */
    aa2 = toupper(aa2);

    /* Si són el mateix aminoàcid, màxima puntuació */
    if(aa1 == aa2) return 3;  /* Identitat: puntuació màxima */

    int cat1 = categoria_aminoacid(aa1);  /* Obté la categoria del primer */
    int cat2 = categoria_aminoacid(aa2);  /* Obté la categoria del segon */

    /* Si algun no és reconegut, retorna -1 */
    if(cat1 < 0 || cat2 < 0) return -1;

    /* Si pertanyen a la mateixa categoria, bona puntuació */
    if(cat1 == cat2) return 2;  /* Mateixa categoria: canvi conservatiu */

    /* Matriu de compatibilitat entre categories */
    /* Hidrofòbic <-> Polar: poden ser compatibles en certs contextos */
    if((cat1 == HIDROFOBIC && cat2 == POLAR) || 
       (cat1 == POLAR && cat2 == HIDROFOBIC))
        return 1;  /* Categories compatibles: canvi semi-conservatiu */

    /* Polar <-> Carregat: poden ser compatibles */
    if((cat1 == POLAR && cat2 == CARREGAT) || 
       (cat1 == CARREGAT && cat2 == POLAR))
        return 1;  /* Categories compatibles */

    /* Hidrofòbic <-> Carregat: generalment incompatible */
    if((cat1 == HIDROFOBIC && cat2 == CARREGAT) || 
       (cat1 == CARREGAT && cat2 == HIDROFOBIC))
        return 0;  /* Categories incompatibles: canvi no conservatiu */

    /* Especial amb qualsevol altre: baixa compatibilitat */
    return 1;  /* Per defecte, puntuació intermèdia */
}

/* Funció per obtenir el nom de la categoria en text */
const char* nom_categoria(int cat){  /* Rep el número de categoria */
    switch(cat){
        case HIDROFOBIC: return "Hidrofobic";  /* Apolar */
        case POLAR:      return "Polar";        /* Polar sense càrrega */
        case CARREGAT:   return "Carregat";     /* Amb càrrega */
        case ESPECIAL:   return "Especial";     /* Propietats úniques */
        default:         return "Desconegut";   /* No classificat */
    }
}

int main(){  /* Funció principal */

    char prot1[101];  /* Array per a la primera proteïna */
    char prot2[101];  /* Array per a la segona proteïna */

    printf("========================================\n");
    printf("  CALCUL DE SIMILITUD ENTRE PROTEINES\n");
    printf("========================================\n\n");

    printf("Introdueix la primera sequencia d'aminoacids: ");
    scanf("%100s", prot1);  /* Llegeix la primera seqüència */

    printf("Introdueix la segona sequencia d'aminoacids: ");
    scanf("%100s", prot2);  /* Llegeix la segona seqüència */

    int len1 = strlen(prot1);  /* Longitud de la primera */
    int len2 = strlen(prot2);  /* Longitud de la segona */

    /* Converteix a majúscules */
    for(int i = 0; i < len1; i++) prot1[i] = toupper(prot1[i]);
    for(int i = 0; i < len2; i++) prot2[i] = toupper(prot2[i]);

    printf("\n=== SEQUENCIES ===\n");
    printf("Proteina 1: %s (longitud: %d)\n", prot1, len1);
    printf("Proteina 2: %s (longitud: %d)\n", prot2, len2);

    /* Determina la longitud per a la comparació */
    int min_len = (len1 < len2) ? len1 : len2;
    int max_len = (len1 > len2) ? len1 : len2;

    /* Variables per a l'anàlisi de similitud */
    int puntuacio_total = 0;       /* Suma de puntuacions */
    int puntuacio_maxima = min_len * 3;  /* Màxima puntuació possible (tots idèntics) */
    int identics = 0;              /* Comptador de posicions idèntiques */
    int conservatius = 0;          /* Comptador de canvis conservatius */
    int no_conservatius = 0;       /* Comptador de canvis no conservatius */

    printf("\n=== ALINEAMENT I PUNTUACIO ===\n");
    printf("%-5s %-5s %-5s %-12s %-12s\n", "POS", "AA1", "AA2", "PUNTUACIO", "TIPUS");
    printf("------------------------------------------\n");

    for(int i = 0; i < min_len; i++){  /* Recorre les posicions comparables */
        int punt = puntuacio_similitud(prot1[i], prot2[i]);  /* Calcula la puntuació */

        puntuacio_total += punt;  /* Acumula la puntuació */

        /* Classifica el tipus de coincidència */
        const char *tipus = "";  /* Text descriptiu */
        if(punt == 3){
            tipus = "Identic";
            identics++;
        } else if(punt == 2){
            tipus = "Conservatiu";
            conservatius++;
        } else if(punt == 1){
            tipus = "Semi-conserv.";
            conservatius++;  /* Comptabilitzat com a conservatiu */
        } else {
            tipus = "No conserv.";
            no_conservatius++;
        }

        printf("%-5d %-5c %-5c %-12d %-12s (cat: %s <-> %s)\n",
               i + 1, prot1[i], prot2[i], punt, tipus,
               nom_categoria(categoria_aminoacid(prot1[i])),
               nom_categoria(categoria_aminoacid(prot2[i])));
    }

    /* Calcula el percentatge de similitud */
    float pct_similitud = 0.0;
    if(puntuacio_maxima > 0)
        pct_similitud = (float)puntuacio_total / puntuacio_maxima * 100;

    float pct_identitat = 0.0;
    if(min_len > 0)
        pct_identitat = (float)identics / min_len * 100;

    /* Mostra el resum */
    printf("\n=== RESUM DE SIMILITUD ===\n");
    printf("Posicions comparades: %d\n", min_len);
    printf("Puntuacio total: %d de %d possibles\n", puntuacio_total, puntuacio_maxima);
    printf("Percentatge de similitud: %.1f%%\n", pct_similitud);
    printf("\nDesglossament:\n");
    printf("  Identics: %d (%.1f%%)\n", identics, pct_identitat);
    printf("  Conservatius: %d\n", conservatius);
    printf("  No conservatius: %d\n", no_conservatius);

    if(len1 != len2)
        printf("\nNota: Les proteines tenen longituds diferents (%d vs %d).\n", len1, len2);

    /* Interpretació biològica */
    printf("\n=== INTERPRETACIO ===\n");
    if(pct_identitat > 70)
        printf("  Alta identitat: probablement proteines homologues.\n");
    else if(pct_identitat > 40)
        printf("  Identitat moderada: possible relacio evolutiva distant.\n");
    else if(pct_similitud > 50)
        printf("  Baixa identitat pero similitud estructural conservada.\n");
    else
        printf("  Baixa similitud: probablement proteines no relacionades.\n");

    return 0;  /* Finalitza el programa */
}

Mini Projecte – Alineador de seqüències

Escriu un programa complet que llegeixi dues seqüències, generi un alineament visual, detecti mutacions i guardi un informe.

#include <stdio.h>  /* Inclou la biblioteca estàndard d'entrada/sortida */
                     /* Necessària per a printf(), scanf(), fopen(), fprintf(), fgets(), fclose() */
#include <stdlib.h>  /* Inclou la biblioteca estàndard */
                     /* Necessària per a malloc(), free() */
#include <string.h>  /* Inclou la biblioteca per a funcions de cadenes */
                     /* Necessària per a strlen(), strcpy(), strncpy(), strcat(), strchr() */
#include <ctype.h>   /* Inclou la biblioteca per a classificació de caràcters */
                     /* Necessària per a toupper() */

/* Constants del programa */
#define MAX_SEQ 2000       /* Longitud màxima de cada seqüència */
#define MAX_MUTACIONS 1000  /* Nombre màxim de mutacions a detectar */
#define MAX_LINIA 2000      /* Longitud màxima d'una línia del fitxer */

/* Estructura per emmagatzemar informació d'una mutació */
typedef struct {
    int posicio;           /* Posició de la mutació (1-based) */
    char base_original;    /* Base en la seqüència de referència */
    char base_mutada;      /* Base en la seqüència comparada */
    char tipus[20];        /* "Transicio" o "Transversio" */
    char classe[30];       /* "Substitucio", "Insercio" o "Delecio" */
} Mutacio;  /* 'Mutacio' és ara un tipus vàlid gràcies a typedef */

/* Variables globals */
char seq1[MAX_SEQ];        /* Primera seqüència (referència) */
char seq2[MAX_SEQ];        /* Segona seqüència (a comparar) */
int len1 = 0;              /* Longitud de la primera seqüència */
int len2 = 0;              /* Longitud de la segona seqüència */
Mutacio mutacions[MAX_MUTACIONS];  /* Array de mutacions */
int total_mutacions = 0;   /* Comptador de mutacions */
int transicions_count = 0; /* Comptador de transicions */
int transversions_count = 0; /* Comptador de transversions */
int substitucions = 0;     /* Comptador de substitucions */
int insercions = 0;        /* Comptador d'insercions */
int delecions = 0;         /* Comptador de delecions */

/* Prototips de les funcions principals */
int carregar_sequencies(const char *nom_fitxer);  /* Carrega seqüències del fitxer */
void comparar_sequencies();                        /* Compara i detecta mutacions */
void mostrar_alineament();                         /* Genera alineament visual */
void mostrar_mutacions();                          /* Llista les mutacions */
void mostrar_resum();                              /* Mostra resum estadístic */
void guardar_informe(const char *nom_fitxer);      /* Desa l'informe en fitxer */

/* Funcions auxiliars */
int es_transicio(char b1, char b2);  /* Determina si és transició */
const char* obtenir_tipus_mutacio(char b1, char b2);  /* Classifica la mutació */

int main(){  /* Funció principal del programa */

    char nom_fitxer[200];  /* Nom del fitxer d'entrada */
    int opcio;             /* Opció del menú */

    printf("========================================\n");
    printf("  ALINEADOR DE SEQUENCIES D'ADN\n");
    printf("========================================\n\n");

    /* Demana el fitxer amb les seqüències */
    printf("Nom del fitxer amb les sequencies: ");
    scanf("%199s", nom_fitxer);

    /* Carrega les seqüències */
    if(carregar_sequencies(nom_fitxer) == 0){
        printf("Error en carregar les sequencies. Finalitzant.\n");
        return 1;
    }

    printf("Sequencies carregades correctament.\n");
    printf("  Sequencia 1 (referencia): %d nucleotids\n", len1);
    printf("  Sequencia 2 (comparada):  %d nucleotids\n", len2);

    /* Compara les seqüències i detecta mutacions */
    comparar_sequencies();

    /* Menú d'opcions */
    do{
        printf("\n--- MENU D'OPCIONS ---\n");
        printf("  1. Mostrar sequencies originals\n");
        printf("  2. Mostrar alineament visual\n");
        printf("  3. Llistar totes les mutacions\n");
        printf("  4. Mostrar resum estadistic\n");
        printf("  5. Guardar informe complet\n");
        printf("  0. Sortir\n");
        printf("  Opcio: ");
        scanf("%d", &opcio);
        getchar();  /* Consumeix el '\n' */

        switch(opcio){
            case 1:
                printf("\nSequencia 1: %s\n", seq1);
                printf("Sequencia 2: %s\n", seq2);
                break;
            case 2:
                mostrar_alineament();
                break;
            case 3:
                mostrar_mutacions();
                break;
            case 4:
                mostrar_resum();
                break;
            case 5:
                guardar_informe("informe_mutacions.txt");
                break;
            case 0:
                printf("\nAdeu!\n");
                break;
            default:
                printf("Opcio no valida.\n");
        }
    } while(opcio != 0);

    return 0;  /* Finalitza el programa */
}

/* Funció per carregar les seqüències des d'un fitxer */
int carregar_sequencies(const char *nom_fitxer){
    FILE *fitxer = fopen(nom_fitxer, "r");  /* Obre en mode lectura */
    if(fitxer == NULL){
        printf("Error: No s'ha pogut obrir el fitxer '%s'.\n", nom_fitxer);
        printf("Creant fitxer d'exemple 'seq_alinear.txt'...\n");

        /* Crea un fitxer d'exemple amb dues seqüències */
        fitxer = fopen(nom_fitxer, "w");
        if(fitxer == NULL) return 0;

        /* Escriu dues seqüències amb diverses mutacions */
        fprintf(fitxer, ">sequencia_referencia\n");
        fprintf(fitxer, "ATGGCGATCGATCGATCG\n");
        fprintf(fitxer, ">sequencia_comparada\n");
        fprintf(fitxer, "ATGGCAATCGATGGATCG\n");
        fclose(fitxer);

        printf("Fitxer d'exemple creat. Executa de nou el programa.\n");
        return 0;
    }

    char linia[MAX_LINIA];
    int llegint_seq1 = 1;  /* Bandera: 1 = llegint primera seqüència, 0 = segona */
    seq1[0] = '\0';  /* Inicialitza les seqüències com a buides */
    seq2[0] = '\0';

    /* Llegeix el fitxer línia per línia */
    while(fgets(linia, MAX_LINIA, fitxer) != NULL){
        /* Elimina el salt de línia */
        int len = strlen(linia);
        if(len > 0 && linia[len-1] == '\n')
            linia[len-1] = '\0';

        /* Si és una capçalera FASTA, canvia a la segona seqüència */
        if(linia[0] == '>'){
            if(strlen(seq1) > 0)  /* Si ja tenim la primera seqüència */
                llegint_seq1 = 0;  /* Passem a llegir la segona */
            continue;  /* Ignora la línia de capçalera */
        }

        /* Converteix a majúscules i afegeix a la seqüència corresponent */
        for(int i = 0; linia[i] != '\0'; i++)
            linia[i] = toupper(linia[i]);

        if(llegint_seq1)
            strcat(seq1, linia);  /* Afegeix a la primera seqüència */
        else
            strcat(seq2, linia);  /* Afegeix a la segona seqüència */
    }

    fclose(fitxer);

    /* Filtra només les bases vàlides (A, C, G, T) */
    char temp1[MAX_SEQ], temp2[MAX_SEQ];
    int j1 = 0, j2 = 0;

    for(int i = 0; seq1[i] != '\0'; i++)
        if(strchr("ACGT", seq1[i]) != NULL)  /* strchr() busca un caràcter en una cadena */
            temp1[j1++] = seq1[i];  /* Conserva només bases vàlides */
    temp1[j1] = '\0';  /* Finalitza la cadena filtrada */

    for(int i = 0; seq2[i] != '\0'; i++)
        if(strchr("ACGT", seq2[i]) != NULL)
            temp2[j2++] = seq2[i];
    temp2[j2] = '\0';

    strcpy(seq1, temp1);  /* Copia les seqüències filtrades */
    strcpy(seq2, temp2);

    len1 = strlen(seq1);  /* Calcula les longituds */
    len2 = strlen(seq2);

    return (len1 > 0 && len2 > 0) ? 1 : 0;  /* Retorna 1 si ambdues tenen dades */
}

/* Funció per comparar les seqüències i detectar mutacions */
void comparar_sequencies(){
    total_mutacions = 0;
    transicions_count = 0;
    transversions_count = 0;
    substitucions = 0;
    insercions = 0;
    delecions = 0;

    int min_len = (len1 < len2) ? len1 : len2;  /* Longitud mínima */

    /* Detecta substitucions (posicions comparables amb bases diferents) */
    for(int i = 0; i < min_len; i++){
        if(seq1[i] != seq2[i]){  /* Si les bases són diferents */
            Mutacio *m = &mutacions[total_mutacions];  /* Punter a la mutació actual */
            m->posicio = i + 1;  /* Posició 1-based */
            m->base_original = seq1[i];
            m->base_mutada = seq2[i];
            strcpy(m->classe, "Substitucio");

            /* Determina el tipus (transició o transversió) */
            if(es_transicio(seq1[i], seq2[i])){
                strcpy(m->tipus, "Transicio");
                transicions_count++;
            } else {
                strcpy(m->tipus, "Transversio");
                transversions_count++;
            }

            total_mutacions++;
            substitucions++;
        }
    }

    /* Detecta insercions (seq2 més llarga) */
    if(len2 > len1){
        for(int i = min_len; i < len2; i++){
            Mutacio *m = &mutacions[total_mutacions];
            m->posicio = i + 1;
            m->base_original = '-';  /* No hi ha base en la referència */
            m->base_mutada = seq2[i];
            strcpy(m->tipus, "Insercio");
            strcpy(m->classe, "Insercio");
            total_mutacions++;
            insercions++;
        }
    }

    /* Detecta delecions (seq2 més curta) */
    if(len1 > len2){
        for(int i = min_len; i < len1; i++){
            Mutacio *m = &mutacions[total_mutacions];
            m->posicio = i + 1;
            m->base_original = seq1[i];
            m->base_mutada = '-';  /* No hi ha base en la comparada */
            strcpy(m->tipus, "Delecio");
            strcpy(m->classe, "Delecio");
            total_mutacions++;
            delecions++;
        }
    }
}

/* Funció per mostrar l'alineament visual */
void mostrar_alineament(){
    int max_len = (len1 > len2) ? len1 : len2;

    printf("\n=== ALINEAMENT VISUAL ===\n\n");

    /* Mostra la primera seqüència en blocs de 50 caràcters */
    printf("Ref: ");
    for(int bloc = 0; bloc < max_len; bloc += 50){
        for(int i = bloc; i < bloc + 50 && i < max_len; i++){
            if(i < len1)
                printf("%c", seq1[i]);  /* Base de la referència */
            else
                printf("-");  /* Gap si la referència és més curta */
        }
        printf("\n     ");
    }
    printf("\n");

    /* Línia de coincidències */
    printf("     ");
    for(int bloc = 0; bloc < max_len; bloc += 50){
        for(int i = bloc; i < bloc + 50 && i < max_len; i++){
            if(i < len1 && i < len2){
                if(seq1[i] == seq2[i])
                    printf("|");  /* Coincidència */
                else
                    printf(" ");  /* Diferència */
            } else {
                printf(" ");  /* Gap */
            }
        }
        printf("\n     ");
    }
    printf("\n");

    /* Mostra la segona seqüència */
    printf("Cmp: ");
    for(int bloc = 0; bloc < max_len; bloc += 50){
        for(int i = bloc; i < bloc + 50 && i < max_len; i++){
            if(i < len2)
                printf("%c", seq2[i]);  /* Base de la comparada */
            else
                printf("-");  /* Gap si la comparada és més curta */
        }
        printf("\n     ");
    }
    printf("\n");

    /* Llegenda */
    printf("\n  | = coincidencia     espai = diferencia     - = gap\n");

    /* Estadístiques ràpides */
    int coincidencies = 0;
    int min_len = (len1 < len2) ? len1 : len2;
    for(int i = 0; i < min_len; i++)
        if(seq1[i] == seq2[i]) coincidencies++;

    printf("\n  Coincidencies: %d/%d (%.1f%%)\n", 
           coincidencies, max_len, 
           max_len > 0 ? (float)coincidencies/max_len*100 : 0);
}

/* Funció per llistar totes les mutacions */
void mostrar_mutacions(){
    if(total_mutacions == 0){
        printf("\nNo s'han detectat mutacions.\n");
        return;
    }

    printf("\n=== MUTACIONS DETECTADES (%d total) ===\n\n", total_mutacions);
    printf("%-8s %-8s %-8s %-15s %-15s\n", "POSICIO", "ORIG.", "MUT.", "TIPUS", "CLASSE");
    printf("-----------------------------------------------------\n");

    for(int i = 0; i < total_mutacions; i++){
        printf("%-8d %-8c %-8c %-15s %-15s\n",
               mutacions[i].posicio,
               mutacions[i].base_original,
               mutacions[i].base_mutada,
               mutacions[i].tipus,
               mutacions[i].classe);
    }
}

/* Funció per mostrar el resum estadístic */
void mostrar_resum(){
    printf("\n=== RESUM ESTADISTIC ===\n\n");

    printf("--- INFORMACIO GENERAL ---\n");
    printf("Longitud sequencia de referencia: %d nucleotids\n", len1);
    printf("Longitud sequencia comparada:     %d nucleotids\n", len2);

    int min_len = (len1 < len2) ? len1 : len2;
    int max_len = (len1 > len2) ? len1 : len2;

    int coincidencies = 0;
    for(int i = 0; i < min_len; i++)
        if(seq1[i] == seq2[i]) coincidencies++;

    printf("Posicions comparades: %d\n", min_len);
    printf("Coincidencies: %d\n", coincidencies);
    printf("Percentatge d'identitat: %.2f%%\n", 
           max_len > 0 ? (float)coincidencies/max_len*100 : 0);

    printf("\n--- CLASSIFICACIO DE MUTACIONS ---\n");
    printf("Total de mutacions detectades: %d\n", total_mutacions);
    printf("  Substitucio: %d\n", substitucions);
    printf("    Transicions:  %d (%.1f%%)\n", 
           transicions_count,
           substitucions > 0 ? (float)transicions_count/substitucions*100 : 0);
    printf("    Transversions: %d (%.1f%%)\n", 
           transversions_count,
           substitucions > 0 ? (float)transversions_count/substitucions*100 : 0);
    printf("  Insercions: %d\n", insercions);
    printf("  Delecions: %d\n", delecions);

    if(substitucions > 0 && transversions_count > 0){
        float ratio = (float)transicions_count / transversions_count;
        printf("\n  Ratio Transicions/Transversions: %.2f\n", ratio);
        if(ratio > 2.0)
            printf("  Interpretacio: Alta fidelitat evolutiva (purificacio negativa).\n");
        else if(ratio > 1.0)
            printf("  Interpretacio: Mutacio aleatoria tipica.\n");
        else
            printf("  Interpretacio: Possible saturacio de mutacions.\n");
    }
}

/* Funció per guardar l'informe complet en un fitxer */
void guardar_informe(const char *nom_fitxer){
    FILE *fitxer = fopen(nom_fitxer, "w");  /* Obre en mode escriptura */
    if(fitxer == NULL){
        printf("Error: No s'ha pogut crear el fitxer '%s'.\n", nom_fitxer);
        return;
    }

    /* Capçalera de l'informe */
    fprintf(fitxer, "========================================\n");
    fprintf(fitxer, "  INFORME D'ALINEAMENT I MUTACIONS\n");
    fprintf(fitxer, "========================================\n\n");

    /* Dades generals */
    fprintf(fitxer, "--- DADES GENERALS ---\n");
    fprintf(fitxer, "Sequencia de referencia: %s\n", seq1);
    fprintf(fitxer, "Sequencia comparada:     %s\n", seq2);
    fprintf(fitxer, "Longitud referencia: %d nt\n", len1);
    fprintf(fitxer, "Longitud comparada:  %d nt\n\n", len2);

    /* Alineament visual */
    fprintf(fitxer, "--- ALINEAMENT VISUAL ---\n");
    int max_len = (len1 > len2) ? len1 : len2;

    fprintf(fitxer, "Ref: ");
    for(int i = 0; i < max_len; i++){
        if(i < len1) fprintf(fitxer, "%c", seq1[i]);
        else fprintf(fitxer, "-");
    }
    fprintf(fitxer, "\n     ");
    for(int i = 0; i < max_len; i++){
        if(i < len1 && i < len2){
            if(seq1[i] == seq2[i]) fprintf(fitxer, "|");
            else fprintf(fitxer, " ");
        } else {
            fprintf(fitxer, " ");
        }
    }
    fprintf(fitxer, "\nCmp: ");
    for(int i = 0; i < max_len; i++){
        if(i < len2) fprintf(fitxer, "%c", seq2[i]);
        else fprintf(fitxer, "-");
    }
    fprintf(fitxer, "\n\n");

    /* Estadístiques */
    int coincidencies = 0;
    int min_len = (len1 < len2) ? len1 : len2;
    for(int i = 0; i < min_len; i++)
        if(seq1[i] == seq2[i]) coincidencies++;

    fprintf(fitxer, "--- ESTADISTIQUES ---\n");
    fprintf(fitxer, "Posicions comparades: %d\n", min_len);
    fprintf(fitxer, "Coincidencies: %d\n", coincidencies);
    fprintf(fitxer, "Percentatge d'identitat: %.2f%%\n", 
            max_len > 0 ? (float)coincidencies/max_len*100 : 0);
    fprintf(fitxer, "Total de mutacions: %d\n", total_mutacions);
    fprintf(fitxer, "  Transicions:  %d\n", transicions_count);
    fprintf(fitxer, "  Transversions: %d\n", transversions_count);
    fprintf(fitxer, "  Insercions: %d\n", insercions);
    fprintf(fitxer, "  Delecions: %d\n\n", delecions);

    /* Llista detallada de mutacions */
    fprintf(fitxer, "--- LLISTA DE MUTACIONS ---\n");
    fprintf(fitxer, "%-8s %-8s %-8s %-15s %-15s\n", "POSICIO", "ORIG.", "MUT.", "TIPUS", "CLASSE");
    fprintf(fitxer, "-----------------------------------------------------\n");

    for(int i = 0; i < total_mutacions; i++){
        fprintf(fitxer, "%-8d %-8c %-8c %-15s %-15s\n",
                mutacions[i].posicio,
                mutacions[i].base_original,
                mutacions[i].base_mutada,
                mutacions[i].tipus,
                mutacions[i].classe);
    }

    fclose(fitxer);
    printf("\nInforme guardat a '%s'.\n", nom_fitxer);
}

/* Funció auxiliar: determina si un canvi és transició */
int es_transicio(char b1, char b2){
    b1 = toupper(b1);
    b2 = toupper(b2);

    if(b1 == b2) return -1;  /* No és mutació */

    /* Transició: A<->G (purines) o C<->T (pirimidines) */
    if((b1 == 'A' && b2 == 'G') || (b1 == 'G' && b2 == 'A'))
        return 1;
    if((b1 == 'C' && b2 == 'T') || (b1 == 'T' && b2 == 'C'))
        return 1;

    return 0;  /* És transversió */
}

/* Funció auxiliar: retorna el tipus de mutació en text */
const char* obtenir_tipus_mutacio(char b1, char b2){
    int tipus = es_transicio(b1, b2);
    if(tipus == 1) return "Transicio";
    if(tipus == 0) return "Transversio";
    return "Identic";
}