Tema 8 - Anàlisi de Seqüències Biològiques

Percentatge GC i freqüència de bases

Escriu un programa que demani una seqüència d'ADN i mostri el percentatge GC i la freqüència de cada base.

#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 adn[501];  /* Array per emmagatzemar la seqüència d'ADN */
                    /* Mida 501: fins a 500 caràcters + '\0' */
                    /* Suficient per a una seqüència típica d'exercici */

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

    printf("Introdueix una sequencia d'ADN: ");  /* Demana la seqüència a l'usuari */
    scanf("%500s", adn);  /* Llegeix fins a 500 caràcters */
                          /* %500s limita la lectura per evitar desbordaments de buffer */
                          /* scanf() amb %s llegeix fins a trobar un espai en blanc */

    int longitud = strlen(adn);  /* Calcula la longitud de la seqüència introduïda */
                                 /* strlen() compta els caràcters fins a '\0' */
                                 /* No inclou el caràcter nul en el recompte */

    /* Arrays per comptar cada tipus de nucleòtid */
    /* Utilitzem un array de 4 posicions: índex 0=A, 1=C, 2=G, 3=T */
    int comptadors[4] = {0, 0, 0, 0};  /* Inicialitza tots els comptadors a 0 */
                                        /* {0, 0, 0, 0} assigna 0 a cada posició */

    int altres = 0;  /* Comptador per a caràcters no vàlids (N, R, Y, etc.) */
    int total_valides = 0;  /* Comptador de bases vàlides (A, C, G, T) */

    /* Bucle per recórrer la seqüència i comptar cada nucleòtid */
    for(int i = 0; i < longitud; i++){  /* Itera des de l'índex 0 fins a longitud-1 */
        char base = toupper(adn[i]);  /* Converteix el caràcter a majúscula */
                                      /* toupper() retorna la versió majúscula */
                                      /* Si ja és majúscula, la retorna igual */
                                      /* Això permet acceptar tant minúscules com majúscules */

        /* Classifica la base i incrementa el comptador corresponent */
        switch(base){  /* Avalua el caràcter actual */
            case 'A':  /* Si és Adenina */
                comptadors[0]++;  /* Incrementa el comptador d'A (índex 0) */
                total_valides++;  /* Incrementa el total de bases vàlides */
                break;  /* Surt de l'estructura switch */
            case 'C':  /* Si és Citosina */
                comptadors[1]++;  /* Incrementa el comptador de C (índex 1) */
                total_valides++;
                break;
            case 'G':  /* Si és Guanina */
                comptadors[2]++;  /* Incrementa el comptador de G (índex 2) */
                total_valides++;
                break;
            case 'T':  /* Si és Timina */
                comptadors[3]++;  /* Incrementa el comptador de T (índex 3) */
                total_valides++;
                break;
            default:  /* Si no és cap base estàndard (N, R, Y, S, W, etc.) */
                altres++;  /* Incrementa el comptador d'altres caràcters */
                break;
        }
    }

    /* Mostra els resultats de l'anàlisi */
    printf("\n=== RESULTATS DE L'ANALISI ===\n");
    printf("Sequencia: %s\n", adn);  /* Mostra la seqüència original */
    printf("Longitud total: %d caracters\n", longitud);  /* Longitud total */

    /* Taula de freqüències absolutes i relatives */
    printf("\n--- FREQUENCIA DE NUCLEOTIDS ---\n");
    char bases[] = {'A', 'C', 'G', 'T'};  /* Array amb les lletres de les bases */

    for(int i = 0; i < 4; i++){  /* Per a cada base (A, C, G, T) */
        float frequencia = 0.0;  /* Variable per al percentatge, inicialitzada a 0 */
        if(total_valides > 0)  /* Evita la divisió per zero si no hi ha bases vàlides */
            frequencia = (float)comptadors[i] / total_valides * 100;
            /* Converteix a float per obtenir decimals */
            /* Divideix pel total de bases vàlides i multiplica per 100 */

        printf("  %c: %3d  (%6.2f%%)", bases[i], comptadors[i], frequencia);
        /* Mostra: base, recompte absolut, percentatge amb 2 decimals */

        /* Afegeix una barra visual de freqüència */
        int barres = (int)(frequencia / 2);  /* Cada 2% = una barra */
        for(int j = 0; j < barres; j++)
            printf("|");  /* Imprimeix una barra per cada 2% */
        printf("\n");
    }

    /* Càlcul del percentatge GC */
    int gc = comptadors[1] + comptadors[2];  /* Suma de C (índex 1) i G (índex 2) */
    float pct_gc = 0.0;  /* Percentatge GC */
    if(total_valides > 0)
        pct_gc = (float)gc / total_valides * 100;

    printf("\n--- CONTINGUT GC ---\n");
    printf("  G + C: %d de %d bases valides\n", gc, total_valides);
    printf("  Percentatge GC: %.2f%%\n", pct_gc);

    /* Classificació del contingut GC */
    if(pct_gc > 60)
        printf("  Classificacio: ALT (ric en GC, possible genoma termofil)\n");
    else if(pct_gc > 40)
        printf("  Classificacio: MITJA (contingut GC tipic)\n");
    else
        printf("  Classificacio: BAIX (pobre en GC, possible genoma d'organisme mesofil)\n");

    /* Informació sobre caràcters no vàlids */
    if(altres > 0){
        printf("\n--- AVIS ---\n");
        printf("  S'han trobat %d caracters no estandard (no A,C,G,T).\n", altres);
        printf("  Aquests caracters s'han ignorat en els calculs de frequencia.\n");
    }

    /* Càlcul de la relació AT/GC */
    if(gc > 0){
        int at = comptadors[0] + comptadors[3];  /* Suma de A i T */
        float ratio_at_gc = (float)at / gc;  /* Relació AT/GC */
        printf("\n--- RELACIO AT/GC ---\n");
        printf("  AT/GC = %.2f\n", ratio_at_gc);
        if(ratio_at_gc > 1.5)
            printf("  La sequencia es rica en A i T.\n");
        else if(ratio_at_gc < 0.67)
            printf("  La sequencia es rica en G i C.\n");
        else
            printf("  La sequencia te una proporcio equilibrada.\n");
    }

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

Identificació de codons ATG

Identifica tots els codons ATG en una seqüència i mostra les posicions on apareixen.

#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 */

    char adn[1001];  /* Array per emmagatzemar la seqüència d'ADN */
                     /* Mida 1001: fins a 1000 caràcters + '\0' */
    int posicions[500];  /* Array per emmagatzemar les posicions on apareix ATG */
                         /* Com a màxim 500 posicions (si tota la seqüència fos ATGATG...) */
    int total_atg = 0;   /* Comptador de codons ATG trobats */
                         /* S'inicialitza a 0 per començar el recompte */

    printf("========================================\n");
    printf("  CERCADOR DE CODONS ATG (START CODONS)\n");
    printf("========================================\n\n");

    printf("Introdueix una sequencia d'ADN: ");  /* Demana la seqüència */
    scanf("%1000s", adn);  /* Llegeix fins a 1000 caràcters */

    int longitud = strlen(adn);  /* Calcula la longitud de la seqüència */

    /* Converteix tota la seqüència a majúscules per a comparació uniforme */
    for(int i = 0; i < longitud; i++){
        adn[i] = toupper(adn[i]);  /* Converteix cada caràcter a majúscula */
    }

    printf("\nSequencia (majuscules): %s\n", adn);  /* Mostra la seqüència en majúscules */
    printf("Longitud: %d nucleotids\n\n", longitud);

    /* Cerca de codons ATG en tots els marcs de lectura possibles */
    /* Un codó són 3 nucleòtids consecutius */
    /* Busquem en les 3 fases (marcs de lectura 0, 1, 2) */

    printf("=== CERCA DE CODONS ATG EN TOTS ELS MARCS ===\n\n");

    for(int marc = 0; marc < 3; marc++){  /* Per a cada marc de lectura (0, 1, 2) */
        printf("--- Marc de lectura %d (comencant a posicio %d) ---\n", marc + 1, marc);
        /* marc+1 per mostrar 1, 2, 3 en lloc de 0, 1, 2 */

        total_atg = 0;  /* Reinicia el comptador per a cada marc */

        /* Recorre la seqüència en passos de 3 (cada codó) */
        /* Comença a la posició 'marc' i avança de 3 en 3 */
        for(int i = marc; i + 2 < longitud; i += 3){  /* i+2 < longitud: necessitem 3 nucleòtids */
                                                       /* i += 3: saltem de codó en codó */

            /* Comprova si els 3 nucleòtids consecutius formen ATG */
            if(adn[i] == 'A' && adn[i+1] == 'T' && adn[i+2] == 'G'){
                /* && és l'operador lògic AND: TOTES les condicions han de ser certes */
                /* Compara el primer nucleòtid amb 'A', el segon amb 'T' i el tercer amb 'G' */

                /* Emmagatzema la posició (basada en 1 per a l'usuari) */
                posicions[total_atg] = i + 1;  /* +1 per mostrar posicions 1-based */
                total_atg++;  /* Incrementa el comptador de ATG trobats */

                printf("  ATG trobat a la posicio %d (nucleotids %d-%d)\n", 
                       i + 1, i + 1, i + 3);
                /* Mostra la posició i el rang de nucleòtids */

                /* Mostra el context: 6 nucleòtids abans i 6 després */
                printf("    Context: ...");
                for(int j = i - 6; j < i; j++)  /* 6 nucleòtids abans */
                    if(j >= 0) printf("%c", adn[j]);  /* Si està dins de la seqüència */
                    else printf(" ");  /* Espais per alinear si està fora */
                printf("[ATG]");  /* El codó ATG trobat */
                for(int j = i + 3; j < i + 9 && j < longitud; j++)  /* 6 nucleòtids després */
                    printf("%c", adn[j]);
                printf("...\n");
            }
        }

        /* Mostra el resum per a aquest marc de lectura */
        printf("  Total ATG en marc %d: %d\n", marc + 1, total_atg);
        if(total_atg == 0)
            printf("  No s'ha trobat cap codó ATG en aquest marc.\n");
        printf("\n");
    }

    /* Cerca addicional: TOTS els ATG independentment del marc */
    printf("=== TOTS ELS ATG (INDEPENDENTMENT DEL MARC) ===\n");
    total_atg = 0;  /* Reinicia el comptador */

    for(int i = 0; i + 2 < longitud; i++){  /* Recorre cada posició (no només cada 3) */
        if(adn[i] == 'A' && adn[i+1] == 'T' && adn[i+2] == 'G'){
            posicions[total_atg] = i + 1;  /* Guarda la posició */
            total_atg++;
        }
    }

    printf("Total d'aparicions d'ATG: %d\n", total_atg);
    if(total_atg > 0){
        printf("Posicions: ");
        for(int i = 0; i < total_atg; i++){
            printf("%d", posicions[i]);  /* Mostra cada posició */
            if(i < total_atg - 1) printf(", ");  /* Separador entre posicions */
        }
        printf("\n");

        /* Calcula la distància entre ATG consecutius */
        if(total_atg > 1){
            printf("Distancies entre ATG consecutius: ");
            for(int i = 0; i < total_atg - 1; i++){
                printf("%d", posicions[i+1] - posicions[i]);  /* Diferència de posicions */
                if(i < total_atg - 2) printf(", ");
            }
            printf(" nucleotids\n");
        }
    }

    /* Informació sobre la importància biològica de ATG */
    printf("\n=== INFORMACIO BIOLOGICA ===\n");
    printf("ATG es el codo d'inici (start codon) en la majoria d'organismes.\n");
    printf("Codifica per l'aminoacid Metionina (Met, M).\n");
    printf("En procariotes, ATG codifica per N-formilmetionina (fMet).\n");
    printf("Altres codons d'inici menys comuns: GTG (Val), TTG (Leu) en alguns bacteris.\n");

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

Taula de traducció ampliada

Amplia la taula de traducció per incloure almenys 10 aminoàcids diferents.

#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 strncpy() */
#include <ctype.h>   /* Inclou la biblioteca per a classificació de caràcters */
                     /* Necessària per a toupper() */

/* Definició de l'estructura per a un codó i el seu aminoàcid */
/* Una estructura agrupa el codó (3 nucleòtids) amb el seu significat */
struct Codo {
    char triplet[4];     /* El codó: 3 nucleòtids + '\0' (ex: "ATG") */
                         /* Mida 4 per emmagatzemar 3 caràcters + '\0' */
    char aminoacid;      /* La lletra de l'aminoàcid (codi d'una lletra) */
                         /* Ex: 'M' per Metionina, 'A' per Alanina */
    char nom[30];        /* Nom complet de l'aminoàcid */
                         /* Ex: "Metionina", "Alanina" */
    int hidrofobic;      /* Propietat: 1 = hidrofòbic, 0 = hidrofílic */
    float pes_molecular; /* Pes molecular en Daltons (Da) */
};

/* Funció per inicialitzar la taula de traducció */
/* Omple un array d'estructures Codo amb la informació genètica */
/* Retorna el nombre d'entrades a la taula */
int inicialitzar_taula(struct Codo taula[]){  /* Rep un array d'estructures */
                                              /* Retorna el nombre d'elements omplerts */

    int i = 0;  /* Índex per omplir la taula */

    /* Cada entrada: triplet, aminoàcid, nom, hidrofòbic?, pes molecular */

    /* Metionina (ATG és el codó d'inici) */
    strcpy(taula[i].triplet, "ATG");  /* Copia el triplet a l'estructura */
    taula[i].aminoacid = 'M';         /* Assigna la lletra de l'aminoàcid */
    strcpy(taula[i].nom, "Metionina");/* Copia el nom complet */
    taula[i].hidrofobic = 1;          /* 1 = és hidrofòbic */
    taula[i].pes_molecular = 149.2;   /* Pes molecular en Da */
    i++;  /* Avança a la següent posició de la taula */

    /* Alanina (4 codons: GCA, GCC, GCG, GCT) */
    strcpy(taula[i].triplet, "GCA");
    taula[i].aminoacid = 'A';
    strcpy(taula[i].nom, "Alanina");
    taula[i].hidrofobic = 1;
    taula[i].pes_molecular = 89.1;
    i++;

    strcpy(taula[i].triplet, "GCC");
    taula[i].aminoacid = 'A';
    strcpy(taula[i].nom, "Alanina");
    taula[i].hidrofobic = 1;
    taula[i].pes_molecular = 89.1;
    i++;

    strcpy(taula[i].triplet, "GCG");
    taula[i].aminoacid = 'A';
    strcpy(taula[i].nom, "Alanina");
    taula[i].hidrofobic = 1;
    taula[i].pes_molecular = 89.1;
    i++;

    strcpy(taula[i].triplet, "GCT");
    taula[i].aminoacid = 'A';
    strcpy(taula[i].nom, "Alanina");
    taula[i].hidrofobic = 1;
    taula[i].pes_molecular = 89.1;
    i++;

    /* Glicina (4 codons: GGA, GGC, GGG, GGT) */
    strcpy(taula[i].triplet, "GGA");
    taula[i].aminoacid = 'G';
    strcpy(taula[i].nom, "Glicina");
    taula[i].hidrofobic = 0;  /* No és hidrofòbica */
    taula[i].pes_molecular = 75.1;
    i++;

    strcpy(taula[i].triplet, "GGC");
    taula[i].aminoacid = 'G';
    strcpy(taula[i].nom, "Glicina");
    taula[i].hidrofobic = 0;
    taula[i].pes_molecular = 75.1;
    i++;

    strcpy(taula[i].triplet, "GGG");
    taula[i].aminoacid = 'G';
    strcpy(taula[i].nom, "Glicina");
    taula[i].hidrofobic = 0;
    taula[i].pes_molecular = 75.1;
    i++;

    strcpy(taula[i].triplet, "GGT");
    taula[i].aminoacid = 'G';
    strcpy(taula[i].nom, "Glicina");
    taula[i].hidrofobic = 0;
    taula[i].pes_molecular = 75.1;
    i++;

    /* Leucina (6 codons: TTA, TTG, CTA, CTC, CTG, CTT) */
    strcpy(taula[i].triplet, "TTA");
    taula[i].aminoacid = 'L';
    strcpy(taula[i].nom, "Leucina");
    taula[i].hidrofobic = 1;
    taula[i].pes_molecular = 131.2;
    i++;

    strcpy(taula[i].triplet, "TTG");
    taula[i].aminoacid = 'L';
    strcpy(taula[i].nom, "Leucina");
    taula[i].hidrofobic = 1;
    taula[i].pes_molecular = 131.2;
    i++;

    strcpy(taula[i].triplet, "CTA");
    taula[i].aminoacid = 'L';
    strcpy(taula[i].nom, "Leucina");
    taula[i].hidrofobic = 1;
    taula[i].pes_molecular = 131.2;
    i++;

    strcpy(taula[i].triplet, "CTC");
    taula[i].aminoacid = 'L';
    strcpy(taula[i].nom, "Leucina");
    taula[i].hidrofobic = 1;
    taula[i].pes_molecular = 131.2;
    i++;

    strcpy(taula[i].triplet, "CTG");
    taula[i].aminoacid = 'L';
    strcpy(taula[i].nom, "Leucina");
    taula[i].hidrofobic = 1;
    taula[i].pes_molecular = 131.2;
    i++;

    strcpy(taula[i].triplet, "CTT");
    taula[i].aminoacid = 'L';
    strcpy(taula[i].nom, "Leucina");
    taula[i].hidrofobic = 1;
    taula[i].pes_molecular = 131.2;
    i++;

    /* Valina (4 codons: GTA, GTC, GTG, GTT) */
    strcpy(taula[i].triplet, "GTA");
    taula[i].aminoacid = 'V';
    strcpy(taula[i].nom, "Valina");
    taula[i].hidrofobic = 1;
    taula[i].pes_molecular = 117.1;
    i++;

    strcpy(taula[i].triplet, "GTC");
    taula[i].aminoacid = 'V';
    strcpy(taula[i].nom, "Valina");
    taula[i].hidrofobic = 1;
    taula[i].pes_molecular = 117.1;
    i++;

    strcpy(taula[i].triplet, "GTG");
    taula[i].aminoacid = 'V';
    strcpy(taula[i].nom, "Valina");
    taula[i].hidrofobic = 1;
    taula[i].pes_molecular = 117.1;
    i++;

    strcpy(taula[i].triplet, "GTT");
    taula[i].aminoacid = 'V';
    strcpy(taula[i].nom, "Valina");
    taula[i].hidrofobic = 1;
    taula[i].pes_molecular = 117.1;
    i++;

    /* Serina (4 codons: TCA, TCC, TCG, TCT - només alguns) */
    strcpy(taula[i].triplet, "TCA");
    taula[i].aminoacid = 'S';
    strcpy(taula[i].nom, "Serina");
    taula[i].hidrofobic = 0;
    taula[i].pes_molecular = 105.1;
    i++;

    strcpy(taula[i].triplet, "TCC");
    taula[i].aminoacid = 'S';
    strcpy(taula[i].nom, "Serina");
    taula[i].hidrofobic = 0;
    taula[i].pes_molecular = 105.1;
    i++;

    /* Lisina (2 codons: AAA, AAG) */
    strcpy(taula[i].triplet, "AAA");
    taula[i].aminoacid = 'K';
    strcpy(taula[i].nom, "Lisina");
    taula[i].hidrofobic = 0;
    taula[i].pes_molecular = 146.2;
    i++;

    strcpy(taula[i].triplet, "AAG");
    taula[i].aminoacid = 'K';
    strcpy(taula[i].nom, "Lisina");
    taula[i].hidrofobic = 0;
    taula[i].pes_molecular = 146.2;
    i++;

    /* Arginina (2 codons: AGA, AGG - dels 6 possibles) */
    strcpy(taula[i].triplet, "AGA");
    taula[i].aminoacid = 'R';
    strcpy(taula[i].nom, "Arginina");
    taula[i].hidrofobic = 0;
    taula[i].pes_molecular = 174.2;
    i++;

    strcpy(taula[i].triplet, "AGG");
    taula[i].aminoacid = 'R';
    strcpy(taula[i].nom, "Arginina");
    taula[i].hidrofobic = 0;
    taula[i].pes_molecular = 174.2;
    i++;

    /* Prolina (4 codons: CCA, CCC, CCG, CCT) */
    strcpy(taula[i].triplet, "CCA");
    taula[i].aminoacid = 'P';
    strcpy(taula[i].nom, "Prolina");
    taula[i].hidrofobic = 1;
    taula[i].pes_molecular = 115.1;
    i++;

    strcpy(taula[i].triplet, "CCC");
    taula[i].aminoacid = 'P';
    strcpy(taula[i].nom, "Prolina");
    taula[i].hidrofobic = 1;
    taula[i].pes_molecular = 115.1;
    i++;

    /* Codons de parada (STOP codons) */
    strcpy(taula[i].triplet, "TAA");
    taula[i].aminoacid = '*';  /* Asterisc: símbol estàndard per a STOP */
    strcpy(taula[i].nom, "STOP (Ocre)");
    taula[i].hidrofobic = 0;
    taula[i].pes_molecular = 0.0;
    i++;

    strcpy(taula[i].triplet, "TAG");
    taula[i].aminoacid = '*';
    strcpy(taula[i].nom, "STOP (Ambre)");
    taula[i].hidrofobic = 0;
    taula[i].pes_molecular = 0.0;
    i++;

    strcpy(taula[i].triplet, "TGA");
    taula[i].aminoacid = '*';
    strcpy(taula[i].nom, "STOP (Opal)");
    taula[i].hidrofobic = 0;
    taula[i].pes_molecular = 0.0;
    i++;

    return i;  /* Retorna el nombre total d'entrades a la taula */
}

/* Funció per buscar un codó a la taula de traducció */
/* Retorna l'aminoàcid corresponent, o '?' si no el troba */
char traduir_codo(const char triplet[], struct Codo taula[], int mida_taula){
    /* Paràmetres:
       - triplet: cadena de 3 caràcters amb el codó
       - taula: array d'estructures Codo amb la taula genètica
       - mida_taula: nombre d'entrades a la taula */

    for(int i = 0; i < mida_taula; i++){  /* Cerca lineal a la taula */
        if(strcmp(triplet, taula[i].triplet) == 0)  /* Compara el triplet */
            return taula[i].aminoacid;  /* Si el troba, retorna l'aminoàcid */
    }
    return '?';  /* Si no el troba, retorna '?' (desconegut) */
}

/* Funció per mostrar la taula de traducció */
void mostrar_taula(struct Codo taula[], int mida){
    printf("\n=== TAULA DE TRADUCCIO GENETICA ===\n");
    printf("Total de codons definits: %d\n\n", mida);
    printf("%-6s %-5s %-20s %-10s %-10s\n", "CODO", "AA", "NOM", "HIDROFOBIC", "PES (Da)");
    printf("--------------------------------------------------------------\n");

    for(int i = 0; i < mida; i++){
        printf("%-6s %-5c %-20s %-10s %10.1f\n",
               taula[i].triplet,       /* El codó */
               taula[i].aminoacid,     /* La lletra de l'aminoàcid */
               taula[i].nom,          /* El nom complet */
               taula[i].hidrofobic ? "Si" : "No",  /* Si és hidrofòbic */
               taula[i].pes_molecular); /* El pes molecular */
    }
}

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

    struct Codo taula[50];  /* Array per a la taula de traducció */
                            /* 50 entrades és suficient per a l'exercici */
                            /* El codi genètic complet té 64 codons */

    /* Inicialitza la taula de traducció */
    int mida_taula = inicialitzar_taula(taula);
    printf("Taula de traduccio inicialitzada amb %d entrades.\n", mida_taula);

    /* Mostra la taula completa */
    mostrar_taula(taula, mida_taula);

    /* Demostració de traducció */
    printf("\n=== DEMOSTRACIO DE TRADUCCIO ===\n");

    char sequencia[200];
    printf("Introdueix una sequencia d'ADN per traduir: ");
    scanf("%199s", sequencia);

    int longitud = strlen(sequencia);
    printf("\nSequencia: %s\n", sequencia);
    printf("Traduccio: ");

    /* Tradueix la seqüència codó a codó */
    for(int i = 0; i + 2 < longitud; i += 3){  /* Avança de 3 en 3 */
        char codo[4];  /* Buffer per al codó actual */
        strncpy(codo, sequencia + i, 3);  /* Copia 3 caràcters */
        codo[3] = '\0';  /* Afegeix el caràcter nul */

        char aa = traduir_codo(codo, taula, mida_taula);  /* Tradueix */
        printf("%c", aa);  /* Mostra l'aminoàcid */

        if(aa == '*') break;  /* Si és STOP, acaba la traducció */
    }
    printf("\n");

    /* Estadístiques d'aminoàcids de la taula */
    printf("\n=== ESTADISTIQUES DE LA TAULA ===\n");
    int hidrofobics = 0, hidrofilics = 0;
    for(int i = 0; i < mida_taula; i++){
        if(taula[i].aminoacid != '*'){  /* No comptar STOP */
            if(taula[i].hidrofobic)
                hidrofobics++;
            else
                hidrofilics++;
        }
    }
    printf("Codons hidrofobics: %d\n", hidrofobics);
    printf("Codons hidrofilics: %d\n", hidrofilics);

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

Mini Projecte – Analitzador de seqüències

Escriu un programa complet que llegeixi una seqüència d'ADN, calculi estadístiques, identifiqui ORFs en els tres marcs de lectura i generi 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(), realloc(), free(), qsort() */
#include <string.h>  /* Inclou la biblioteca per a funcions de cadenes */
                     /* Necessària per a strlen(), strcpy(), strncpy(), strcat(), strcmp() */
#include <ctype.h>   /* Inclou la biblioteca per a classificació de caràcters */
                     /* Necessària per a toupper() */

/* Constants del programa */
#define MAX_SEQ 10000      /* Longitud màxima de la seqüència */
#define MAX_ORF 500        /* Nombre màxim d'ORFs a detectar */
#define MAX_LINIA 1000     /* Longitud màxima d'una línia del fitxer */

/* Estructura per emmagatzemar un ORF (Open Reading Frame) */
typedef struct {
    int marc;              /* Marc de lectura (0, 1 o 2) */
    int inici;             /* Posició d'inici (1-based) */
    int final;             /* Posició final (1-based) */
    int longitud_adn;      /* Longitud en nucleòtids */
    int longitud_aa;       /* Longitud en aminoàcids */
    char *sequencia_aa;    /* Seqüència d'aminoàcids (memòria dinàmica) */
    float pes_molecular;   /* Pes molecular aproximat */
} ORF;  /* 'ORF' és ara un tipus vàlid gràcies a typedef */

/* Variables globals */
char sequencia[MAX_SEQ];   /* Seqüència d'ADN carregada */
int longitud_seq = 0;      /* Longitud real de la seqüència */
ORF orfs[MAX_ORF];         /* Array d'ORFs trobats */
int total_orfs = 0;        /* Nombre total d'ORFs trobats */

/* Prototips de les funcions */
int carregar_sequencia(const char *nom_fitxer);  /* Carrega la seqüència d'un fitxer */
void analitzar_composicio();                      /* Calcula %GC i freqüències */
void identificar_orfs();                          /* Troba tots els ORFs */
void mostrar_orfs();                              /* Mostra els ORFs per pantalla */
void guardar_informe(const char *nom_fitxer);     /* Guarda l'informe en un fitxer */
void alliberar_orfs();                            /* Allibera la memòria dels ORFs */

/* Funcions auxiliars per a la traducció */
char traduir_codo(const char *codo);              /* Tradueix un codó a aminoàcid */
int es_codo_inici(const char *codo);              /* Comprova si és ATG (START) */
int es_codo_stop(const char *codo);              /* Comprova si és TAA, TAG o TGA */

/* Funció de comparació per ordenar ORFs per longitud (qsort) */
int comparar_orfs_per_longitud(const void *a, const void *b);

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

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

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

    /* Demana el fitxer amb la seqüència */
    printf("Nom del fitxer amb la sequencia d'ADN: ");
    scanf("%199s", nom_fitxer);

    /* Carrega la seqüència */
    if(carregar_sequencia(nom_fitxer) == 0){
        printf("Error en carregar la sequencia. Finalitzant.\n");
        return 1;
    }

    printf("Sequencia carregada: %d nucleotids.\n", longitud_seq);

    /* Menú d'opcions */
    do{
        printf("\n--- MENU D'ANALISI ---\n");
        printf("  1. Mostrar composicio nucleotidica\n");
        printf("  2. Identificar ORFs en tots els marcs\n");
        printf("  3. Mostrar ORFs trobats\n");
        printf("  4. Guardar informe complet\n");
        printf("  0. Sortir\n");
        printf("  Opcio: ");
        scanf("%d", &opcio);
        getchar();  /* Consumeix el '\n' */

        switch(opcio){
            case 1:
                analitzar_composicio();
                break;
            case 2:
                identificar_orfs();
                printf("S'han identificat %d ORFs.\n", total_orfs);
                break;
            case 3:
                mostrar_orfs();
                break;
            case 4:
                guardar_informe("informe_analisi.txt");
                break;
            case 0:
                printf("\nAlliberant memoria...\n");
                alliberar_orfs();
                printf("Adeu!\n");
                break;
            default:
                printf("Opcio no valida.\n");
        }
    } while(opcio != 0);

    return 0;  /* Finalitza el programa */
}

/* Funció per carregar la seqüència des d'un fitxer */
int carregar_sequencia(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...\n");

        /* Crea un fitxer d'exemple */
        fitxer = fopen(nom_fitxer, "w");
        if(fitxer == NULL) return 0;

        fprintf(fitxer, "ATGGCCGCTTGATAG\n");
        fprintf(fitxer, "CCGATGCTAGCTTAA\n");
        fprintf(fitxer, "GGGCCCAAATTTTGA\n");
        fclose(fitxer);

        fitxer = fopen(nom_fitxer, "r");
        if(fitxer == NULL) return 0;
        printf("Fitxer d'exemple creat.\n");
    }

    char linia[MAX_LINIA];
    sequencia[0] = '\0';  /* Inicialitza la seqüència com a buida */

    /* 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';

        /* Ignora línies que comencen amb '>' (format FASTA) */
        if(linia[0] == '>') continue;

        /* Converteix a majúscules i afegeix a la seqüència */
        for(int i = 0; linia[i] != '\0'; i++){
            linia[i] = toupper(linia[i]);
        }
        strcat(sequencia, linia);  /* Concatena la línia */
    }

    fclose(fitxer);
    longitud_seq = strlen(sequencia);  /* Calcula la longitud total */

    /* Filtra només els caràcters vàlids (A, C, G, T) */
    int j = 0;  /* Índex d'escriptura */
    for(int i = 0; i < longitud_seq; i++){
        if(sequencia[i] == 'A' || sequencia[i] == 'C' || 
           sequencia[i] == 'G' || sequencia[i] == 'T'){
            sequencia[j] = sequencia[i];  /* Conserva només bases vàlides */
            j++;
        }
    }
    sequencia[j] = '\0';  /* Finalitza la cadena filtrada */
    longitud_seq = j;     /* Actualitza la longitud */

    return longitud_seq;  /* Retorna la longitud (0 si està buida) */
}

/* Funció per analitzar la composició nucleotídica */
void analitzar_composicio(){
    if(longitud_seq == 0){
        printf("No hi ha sequencia carregada.\n");
        return;
    }

    int a = 0, c = 0, g = 0, t = 0;  /* Comptadors per a cada base */

    /* Compta cada nucleòtid */
    for(int i = 0; i < longitud_seq; i++){
        switch(sequencia[i]){
            case 'A': a++; break;
            case 'C': c++; break;
            case 'G': g++; break;
            case 'T': t++; break;
        }
    }

    int total = a + c + g + t;  /* Total de bases vàlides */

    printf("\n=== COMPOSICIO NUCLEOTIDICA ===\n");
    printf("Longitud de la sequencia: %d nucleotids\n\n", longitud_seq);

    printf("%-10s %8s %10s\n", "BASE", "NOMBRE", "PERCENTATGE");
    printf("--------------------------------\n");

    if(total > 0){
        printf("%-10s %8d %9.2f%%\n", "Adenina (A)", a, (float)a/total*100);
        printf("%-10s %8d %9.2f%%\n", "Citosina (C)", c, (float)c/total*100);
        printf("%-10s %8d %9.2f%%\n", "Guanina (G)", g, (float)g/total*100);
        printf("%-10s %8d %9.2f%%\n", "Timina (T)", t, (float)t/total*100);
    }

    printf("--------------------------------\n");
    printf("%-10s %8d\n", "TOTAL", total);

    /* Contingut GC */
    int gc = c + g;
    float pct_gc = (total > 0) ? (float)gc/total*100 : 0;
    printf("\nContingut GC: %.2f%%\n", pct_gc);
    printf("Relacio AT/GC: %.2f\n", (total > 0 && gc > 0) ? (float)(a+t)/gc : 0);
}

/* Funció per identificar tots els ORFs en els 3 marcs de lectura */
void identificar_orfs(){
    if(longitud_seq == 0){
        printf("No hi ha sequencia carregada.\n");
        return;
    }

    /* Allibera ORFs anteriors si n'hi ha */
    alliberar_orfs();
    total_orfs = 0;

    /* Busca en cada marc de lectura (0, 1, 2) */
    for(int marc = 0; marc < 3; marc++){
        int posicio = marc;  /* Comença a la posició del marc */

        /* Recorre la seqüència en aquest marc */
        while(posicio + 2 < longitud_seq){
            char codo[4];  /* Buffer per al codó actual */
            strncpy(codo, sequencia + posicio, 3);
            codo[3] = '\0';

            /* Si troba un codó d'inici (ATG) */
            if(es_codo_inici(codo)){
                int inici_orf = posicio;  /* Guarda la posició d'inici */
                int longitud_orf = 3;     /* Comença amb 3 nucleòtids (ATG) */

                /* Avança codó a codó fins trobar un STOP o final de seqüència */
                posicio += 3;
                int stop_trobat = 0;

                while(posicio + 2 < longitud_seq){
                    strncpy(codo, sequencia + posicio, 3);
                    codo[3] = '\0';

                    if(es_codo_stop(codo)){  /* Si troba un codó de parada */
                        longitud_orf += 3;   /* Afegeix el codó STOP */
                        stop_trobat = 1;
                        break;  /* Surt del bucle interior */
                    }

                    longitud_orf += 3;  /* Afegeix la longitud del codó */
                    posicio += 3;       /* Avança al següent codó */
                }

                /* Si l'ORF és significatiu (mínim 30 nucleòtids = 10 aminoàcids) */
                if(longitud_orf >= 30 && total_orfs < MAX_ORF){
                    ORF *orf = &orfs[total_orfs];  /* Punter a l'ORF actual */

                    orf->marc = marc;
                    orf->inici = inici_orf + 1;     /* Posició 1-based */
                    orf->final = inici_orf + longitud_orf;  /* Posició final */
                    orf->longitud_adn = longitud_orf;
                    orf->longitud_aa = (stop_trobat) ? (longitud_orf / 3) - 1 : longitud_orf / 3;
                    /* Si hi ha STOP, resta 1 (el codó STOP no es tradueix a aminoàcid) */
                    /* Si no hi ha STOP, tots els codons es tradueixen */

                    /* Reserva memòria per a la seqüència d'aminoàcids */
                    orf->sequencia_aa = (char*)malloc((orf->longitud_aa + 1) * sizeof(char));
                    orf->pes_molecular = 0.0;

                    /* Tradueix l'ORF a aminoàcids */
                    if(orf->sequencia_aa != NULL){
                        int aa_idx = 0;  /* Índex per a la seqüència d'aminoàcids */
                        for(int i = 0; i < orf->longitud_adn - 3; i += 3){
                            /* No tradueix l'últim codó si és STOP */
                            char codo_trad[4];
                            strncpy(codo_trad, sequencia + inici_orf + i, 3);
                            codo_trad[3] = '\0';

                            char aa = traduir_codo(codo_trad);
                            orf->sequencia_aa[aa_idx] = aa;

                            /* Acumula el pes molecular */
                            orf->pes_molecular += pes_aminoacid(aa);
                            aa_idx++;
                        }
                        orf->sequencia_aa[aa_idx] = '\0';  /* Finalitza la cadena */
                    }

                    total_orfs++;  /* Incrementa el comptador d'ORFs */
                }

                /* Si no s'ha trobat STOP, posicio ja està al final */
                if(!stop_trobat) break;  /* Surt del bucle exterior per a aquest marc */
            } else {
                posicio += 3;  /* Avança al següent codó si no és ATG */
            }
        }
    }

    /* Ordena els ORFs per longitud (de més llarg a més curt) */
    qsort(orfs, total_orfs, sizeof(ORF), comparar_orfs_per_longitud);

    printf("Analisi completada: %d ORFs identificats.\n", total_orfs);
}

/* Funció per mostrar els ORFs trobats */
void mostrar_orfs(){
    if(total_orfs == 0){
        printf("No s'han identificat ORFs. Executa primer l'opcio 2.\n");
        return;
    }

    printf("\n=== ORFs IDENTIFICATS (ordenats per longitud) ===\n\n");
    printf("%-5s %-5s %-8s %-8s %-8s %-8s %-12s %s\n",
           "NUM", "MARC", "INICI", "FINAL", "LONG_ADN", "LONG_AA", "PES_MOLEC", "SEQUENCIA AA");
    printf("--------------------------------------------------------------------------------\n");

    for(int i = 0; i < total_orfs; i++){
        printf("%-5d %-5d %-8d %-8d %-8d %-8d %-10.1f %s\n",
               i + 1,
               orfs[i].marc + 1,
               orfs[i].inici,
               orfs[i].final,
               orfs[i].longitud_adn,
               orfs[i].longitud_aa,
               orfs[i].pes_molecular,
               orfs[i].sequencia_aa ? orfs[i].sequencia_aa : "N/A");
    }
}

/* 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;
    }

    /* Escriu la capçalera de l'informe */
    fprintf(fitxer, "========================================\n");
    fprintf(fitxer, "  INFORME D'ANALISI DE SEQUENCIA D'ADN\n");
    fprintf(fitxer, "========================================\n\n");

    /* Informació general de la seqüència */
    fprintf(fitxer, "--- DADES GENERALS ---\n");
    fprintf(fitxer, "Longitud de la sequencia: %d nucleotids\n", longitud_seq);
    fprintf(fitxer, "Sequencia (primers 100 nt): %.100s%s\n\n", 
            sequencia, longitud_seq > 100 ? "..." : "");

    /* Composició nucleotídica */
    int a = 0, c = 0, g = 0, t = 0;
    for(int i = 0; i < longitud_seq; i++){
        switch(sequencia[i]){
            case 'A': a++; break;
            case 'C': c++; break;
            case 'G': g++; break;
            case 'T': t++; break;
        }
    }
    int total = a + c + g + t;
    float pct_gc = (total > 0) ? (float)(c+g)/total*100 : 0;

    fprintf(fitxer, "--- COMPOSICIO NUCLEOTIDICA ---\n");
    fprintf(fitxer, "Adenina (A): %d (%.2f%%)\n", a, (float)a/total*100);
    fprintf(fitxer, "Citosina (C): %d (%.2f%%)\n", c, (float)c/total*100);
    fprintf(fitxer, "Guanina (G): %d (%.2f%%)\n", g, (float)g/total*100);
    fprintf(fitxer, "Timina (T): %d (%.2f%%)\n", t, (float)t/total*100);
    fprintf(fitxer, "Contingut GC: %.2f%%\n\n", pct_gc);

    /* ORFs identificats */
    fprintf(fitxer, "--- ORFs IDENTIFICATS ---\n");
    fprintf(fitxer, "Nombre total d'ORFs: %d\n\n", total_orfs);

    if(total_orfs > 0){
        fprintf(fitxer, "%-6s %-6s %-8s %-8s %-8s %-8s %-12s %s\n",
                "NUM", "MARC", "INICI", "FINAL", "LONG_ADN", "LONG_AA", "PES_MOLEC", "SEQUENCIA AA");
        fprintf(fitxer, "--------------------------------------------------------------------------------\n");

        for(int i = 0; i < total_orfs; i++){
            fprintf(fitxer, "%-6d %-6d %-8d %-8d %-8d %-8d %-10.1f %s\n",
                    i + 1,
                    orfs[i].marc + 1,
                    orfs[i].inici,
                    orfs[i].final,
                    orfs[i].longitud_adn,
                    orfs[i].longitud_aa,
                    orfs[i].pes_molecular,
                    orfs[i].sequencia_aa ? orfs[i].sequencia_aa : "N/A");
        }

        /* Detall de cada ORF */
        fprintf(fitxer, "\n--- DETALL DELS ORFs ---\n\n");
        for(int i = 0; i < total_orfs; i++){
            fprintf(fitxer, "ORF %d:\n", i + 1);
            fprintf(fitxer, "  Marc de lectura: %d\n", orfs[i].marc + 1);
            fprintf(fitxer, "  Posicio: %d - %d\n", orfs[i].inici, orfs[i].final);
            fprintf(fitxer, "  Longitud ADN: %d nucleotids\n", orfs[i].longitud_adn);
            fprintf(fitxer, "  Longitud proteica: %d aminoacids\n", orfs[i].longitud_aa);
            fprintf(fitxer, "  Pes molecular estimat: %.1f Da\n", orfs[i].pes_molecular);
            if(orf[i].sequencia_aa){
                fprintf(fitxer, "  Sequencia d'aminoacids: %s\n", orfs[i].sequencia_aa);
            }
            fprintf(fitxer, "\n");
        }
    }

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

/* Funció per alliberar la memòria dels ORFs */
void alliberar_orfs(){
    for(int i = 0; i < total_orfs; i++){
        if(orfs[i].sequencia_aa != NULL){
            free(orfs[i].sequencia_aa);  /* Allibera la seqüència d'aminoàcids */
            orfs[i].sequencia_aa = NULL;  /* Evita punters penjants */
        }
    }
    total_orfs = 0;  /* Reinicia el comptador */
}

/* Funció per traduir un codó a aminoàcid */
char traduir_codo(const char *codo){
    /* Taula de traducció simplificada */
    /* Aminoàcids representats pel codi d'una lletra */
    if(strcmp(codo, "GCA")==0 || strcmp(codo, "GCC")==0 || 
       strcmp(codo, "GCG")==0 || strcmp(codo, "GCT")==0) return 'A';  /* Alanina */
    if(strcmp(codo, "TGC")==0 || strcmp(codo, "TGT")==0) return 'C';  /* Cisteina */
    if(strcmp(codo, "GAC")==0 || strcmp(codo, "GAT")==0) return 'D';  /* Aspartat */
    if(strcmp(codo, "GAA")==0 || strcmp(codo, "GAG")==0) return 'E';  /* Glutamat */
    if(strcmp(codo, "TTC")==0 || strcmp(codo, "TTT")==0) return 'F';  /* Fenilalanina */
    if(strcmp(codo, "GGA")==0 || strcmp(codo, "GGC")==0 || 
       strcmp(codo, "GGG")==0 || strcmp(codo, "GGT")==0) return 'G';  /* Glicina */
    if(strcmp(codo, "CAC")==0 || strcmp(codo, "CAT")==0) return 'H';  /* Histidina */
    if(strcmp(codo, "ATA")==0 || strcmp(codo, "ATC")==0 || 
       strcmp(codo, "ATT")==0) return 'I';  /* Isoleucina */
    if(strcmp(codo, "AAA")==0 || strcmp(codo, "AAG")==0) return 'K';  /* Lisina */
    if(strcmp(codo, "TTA")==0 || strcmp(codo, "TTG")==0 || 
       strcmp(codo, "CTA")==0 || strcmp(codo, "CTC")==0 || 
       strcmp(codo, "CTG")==0 || strcmp(codo, "CTT")==0) return 'L';  /* Leucina */
    if(strcmp(codo, "ATG")==0) return 'M';  /* Metionina (START) */
    if(strcmp(codo, "AAC")==0 || strcmp(codo, "AAT")==0) return 'N';  /* Asparagina */
    if(strcmp(codo, "CCA")==0 || strcmp(codo, "CCC")==0 || 
       strcmp(codo, "CCG")==0 || strcmp(codo, "CCT")==0) return 'P';  /* Prolina */
    if(strcmp(codo, "CAA")==0 || strcmp(codo, "CAG")==0) return 'Q';  /* Glutamina */
    if(strcmp(codo, "AGA")==0 || strcmp(codo, "AGG")==0 || 
       strcmp(codo, "CGA")==0 || strcmp(codo, "CGC")==0 || 
       strcmp(codo, "CGG")==0 || strcmp(codo, "CGT")==0) return 'R';  /* Arginina */
    if(strcmp(codo, "TCA")==0 || strcmp(codo, "TCC")==0 || 
       strcmp(codo, "TCG")==0 || strcmp(codo, "TCT")==0 || 
       strcmp(codo, "AGC")==0 || strcmp(codo, "AGT")==0) return 'S';  /* Serina */
    if(strcmp(codo, "ACA")==0 || strcmp(codo, "ACC")==0 || 
       strcmp(codo, "ACG")==0 || strcmp(codo, "ACT")==0) return 'T';  /* Treonina */
    if(strcmp(codo, "GTA")==0 || strcmp(codo, "GTC")==0 || 
       strcmp(codo, "GTG")==0 || strcmp(codo, "GTT")==0) return 'V';  /* Valina */
    if(strcmp(codo, "TGG")==0) return 'W';  /* Triptòfan */
    if(strcmp(codo, "TAC")==0 || strcmp(codo, "TAT")==0) return 'Y';  /* Tirosina */
    if(strcmp(codo, "TAA")==0 || strcmp(codo, "TAG")==0 || 
       strcmp(codo, "TGA")==0) return '*';  /* STOP */
    return 'X';  /* Desconegut */
}

/* Funció: comprova si un codó és d'inici (ATG) */
int es_codo_inici(const char *codo){
    return (strcmp(codo, "ATG") == 0);  /* Retorna 1 si és ATG, 0 si no */
}

/* Funció: comprova si un codó és de parada */
int es_codo_stop(const char *codo){
    return (strcmp(codo, "TAA") == 0 || 
            strcmp(codo, "TAG") == 0 || 
            strcmp(codo, "TGA") == 0);
}

/* Funció: retorna el pes molecular aproximat d'un aminoàcid */
float pes_aminoacid(char aa){
    switch(aa){
        case 'A': return 89.1;   /* Alanina */
        case 'C': return 121.2;  /* Cisteina */
        case 'D': return 133.1;  /* Aspartat */
        case 'E': return 147.1;  /* Glutamat */
        case 'F': return 165.2;  /* Fenilalanina */
        case 'G': return 75.1;   /* Glicina */
        case 'H': return 155.2;  /* Histidina */
        case 'I': return 131.2;  /* Isoleucina */
        case 'K': return 146.2;  /* Lisina */
        case 'L': return 131.2;  /* Leucina */
        case 'M': return 149.2;  /* Metionina */
        case 'N': return 132.1;  /* Asparagina */
        case 'P': return 115.1;  /* Prolina */
        case 'Q': return 146.2;  /* Glutamina */
        case 'R': return 174.2;  /* Arginina */
        case 'S': return 105.1;  /* Serina */
        case 'T': return 119.1;  /* Treonina */
        case 'V': return 117.1;  /* Valina */
        case 'W': return 204.2;  /* Triptòfan */
        case 'Y': return 181.2;  /* Tirosina */
        default:  return 110.0;  /* Pes mitjà per a desconeguts */
    }
}

/* Funció de comparació per a qsort (ordenar ORFs per longitud descendent) */
int comparar_orfs_per_longitud(const void *a, const void *b){
    const ORF *orf_a = (const ORF*)a;  /* Converteix void* a ORF* */
    const ORF *orf_b = (const ORF*)b;

    /* Ordena de més llarg a més curt (descendent) */
    if(orf_a->longitud_adn > orf_b->longitud_adn)
        return -1;  /* a va abans si és més llarg */
    else if(orf_a->longitud_adn < orf_b->longitud_adn)
        return 1;   /* a va després si és més curt */
    else
        return 0;   /* Mateixa longitud */
}