Bueno, ya está el programa hecho. Dejo el código aquí debajo. Si alguien usa Linux, se compila con. Gcc bingo, c -o bingo -o3 -STD=c99
(-o3 es para que optimice todo lo que pueda y -STD=c99 para que me permita usar cierto dialecto estándar del c que se permite a partir de esa versión)
Luego lo lanzaríamos con.
Time./bingo.
Para que nos diga cuanto le ha costado terminar.
Ahora explico el programa en sí. He escogido la siguiente secuencia de letras:
Pcgauacucagagagcagacugacugagucugugtcgucacagaucgcac aoh.
Y he escrito un programa que se lanza a probar aleatoriamente combinaciones de letras, hasta llegar a esa secuencia. No por fuerza bruta (es decir, no probando cada posible combinación), sino aleatorizando cada vez todos los componentes, como ocurriría si los metiéramos en una bolsa y los sacudiéramos, o cómo si pusiéramos los componentes de una tortilla de patatas en una sartén y la revolviéramos. Hay muchas de esas pruebas que habrá sido la misma prueba (por ejemplo, puede que haya salido varias veces esa cadena ordenada alfabéticamente). Cada una de las pruebas incrementa un contador.
Simplemente le he pedido al programa que me avise cuando la cadena formada aleatoriamente coincide con la que quería que me avisara, y me diga el número de veces que ha sacudido la bolsa hasta lograrlo. Esto lo dejo claro porque no estoy programando ningún comportamiento dentro del sistema, sólo muevo la bolsa (que equivale a tener átomos dispersos en un charco interactuando entre ellos) y cuando han interactuado los 68 o 69 que componen la cadena, le pregunto si el resultado se parece al esperado. Si no, vuelve a intentarlo, con la orden time antes del programa, el sistema operativo me dice además cuánto tiempo ha tardado en calcularlo.
Éste es el resultado:
Marte@chisme$ time./probanding.
Arn de transferencia conseguido tras 1774618663 combinaciones aleatorias.
Real 143m36.637s.
User 93m6.161s.
Sys 0m6.026s.
Para analizar el resultado hay que tener en cuenta varias consideraciones, la primera, que esto es un simple notebook monoprocesador que trabaja secuencialmente, cuando la naturaleza trabaja en paralelo (podría hacer las 1774618663 combinaciones a la vez a lo largo y ancho de la tierra), la segunda, que obviamente en el proceso además se generarían cadenas más cortas y más largas, pero me he interesado por ésa en especial (luego explico por qué). Esas cadenas más cortas y más largas a su vez pueden no hacer nada o tener cierta funcionalidad interesante, la tercera, que en el mundo real es incluso más sencillo, puesto que, aunque las combinaciones sean aletorias, recordemos que los átomos y estas moléculas están imantadas de manera que, hay muchas combinaciones que no serían posibles y que mi programa las ha intentado de todas formas, la cuarta, que en el mundo real es todavía más rápido, puesto que aquí he preguntado cuanto tarda en conseguir aleatoriamente toda la cadena. En la vida real primero se conseguirían las bases a, c, g,t y u (si queréis, adapto el programa para pedirle esa información, pero las pruebas que he hecho con tan pocos elementos me daba la solución en un par de segundos como mucho), y de esas bases tendríamos parejas a-u g-c, y de esas parejas conseguiríamos la siguiente estructura. Aquí es donde mucha gente se equivoca pensando que al azar tiene que surgir todo mi ordenador personal después de romperlo y meterlo en una bolsa. Las estructuras orgánicas tienen puntos de anclaje que autoencajan cuando se encuentran con otras estructuras apropiadas (por eso nos pueden infectar los virus, acoplándose a las células, no se abren paso a dentelladas), la quinta es que en el mundo real se lo puede tomar todo con mucha más calma. El programa ha tardado 143 minutos en avisarme de que, tras meter las letras en una bolsa y agitarlas, ha salido la palabra en cuestión. Al estar usando procedimientos aleatorios, esto podría haber pasado a la primera, o pasar siglos sin que se diera esa combinación. Pero en el universo, si algo sobra, es tiempo. Aunque tardará milenios, daría con ella.
En resumen: mi bingo a avisado de que ha salido una molécula que es capaz de engancharse a otros aminoácidos y transportarlos, llamada arnt (arn transcriptasa, porque ayuda a replicar -transcribir- El código del ADN).
¿Para que sirve eso? Por sí mismo nada (total, ha sido puro azar), pero si en el siguiente nivel el azar la acerca a otra molécula surgida por azar (que no es mucho más complicada que ésta, aunque se habrá tomado su tiempo en aparecer, pero véase el punto quinto) que sea arn ribosómico, ya tenemos las bases para empezar a copiar ADN. El ADN parece muy complejo, pero si lo desmembramos de esta manera, veremos que para su origen no hace falta ninguna magia especial, ya que no sale todo de una vez, sino que se va formando a cachos.
Como curiosidad, escribiendo el programa muté sin querer como cuatro veces el arnt, equivocándome al escribir el código en el programa. Esto mismo, en el terreno de la naturaleza, sería equivalente a que algún accidente físico-químico estropeara o intercambiara alguna parte de la cadena.
Ahora, por fin, el código. Sé que es mejorable, pero anoche se hizo muy tarde y ya sabéis en que andaba entretenido a la vez al llegar hoy de clase de trompeta, el programa había terminado, imagino que en una máquina mejor podría probar más combinaciones más rápido, pero como comentaba antes, eso no garantiza nada. Podría pasar siglos sin llegar a esa cadena.
Código:
#include <stdio, h>.
#define arnt pcgauacucagagagcagacugacugagucugugtcgucacagaucgcacaoh.
Const int ilen = strlen(arnt).
Typedef structure tcelda.
{
Int ifinalpos;
Struct tcelda* pnext;
Struct tcelda* pprev;
} tlistaenlazada.
//////
// probamos combinaciones de bases aleatorias con los componentes originales.
//////
Void recombina (char* sinit)
{
Char itemp[ilen+1];
Strcpy(itemp, sinit).
Tlistaenlazada* pcabezalista = (tlistaenlazada*) malloc(sizeof(tlistaenlazada)),
Tlistaenlazada* panteriorelemento = pcabezalista;
Pcabezalista->ifinalpues = 0;
Pcabezalista->pnext = null;
Pcabezalista->pprev = null, for(int i=1, i<=ilen; ++i)
{
Tlistaenlazada* psiguienteelemento = (tlistaenlazada*) malloc(sizeof(tlistaenlazada)),
Psiguienteelemento->ifinalpues = i;
Panteriorelemento->pnext = psiguienteelemento;
Psiguienteelemento->pprev = panteriorelemento;
Psiguienteelemento->pnext = null;
Panteriorelemento = psiguienteelemento;
}.
Tlistaenlazada* ptemp = null;
For(int i=0, i<=ilen; ++i)
{
Int ipues = Rand() % (ilen-i+1),
Ptemp = pcabezalista;
Int ifinalpos=pcabezalista->ifinalpos, for(int j=1, j<Ipos; ++j)
{
Ptemp = ptemp->pnext;
Ifinalpos=ptemp->ifinalpos;
} if(ptemp==pcabezalista)
If (pcabezalista->pnext)
{
Pcabezalista = pcabezalista->pnext;
Pcabezalista->pprev = null;
} if(ptemp->pprev && ptemp->pnext)
{
Ptemp->pprev->pnext = ptemp->pnext;
Ptemp->pnext->pprev = ptemp->pprev;
} free (ptemp),
Ptemp = null, char c = itemp[ifinalpos];
Sinit[i] = c;
}
//printf(%s\n, sinit),
}.
/////
/// combina aleatoriamente un Vector desordenado hasta que coincida con uno de los posibles.
/// patrones con sentido.
////
Int main (int argc, const char * argv[])
{
Srand(time (null)),
Char sinit[ilen+1];
Strcpy(sinit,acghoptu),
Int iinitlen = strlen(sinit), if(iinitlen.= ilen)
{
Printf(metiste la pata al contar: %d/%d\n, iinitlen, ilen),
}
Else.
{
Int icontador=0;
While (strcmp(sinit, arnt).= 0)
{
Icontador++;
Recombina (&sinit),
}
Printf(arn de transferencia conseguido tras %d combinaciones aleatorias\n, icontador),
}
Return 0;
}.
He sacado la estructura del arnt de aquí: http://www.scielo, br/scielo.php?Scr...62008000400008.
Es la más simple de todas las que se puede encontrar de su tipo.
Si alguien necesita alguna explicación sobre alguna parte en concreto del programa, sólo tiene que preguntar.
Quod est demostrandum.