Serie ficheros virtuales 

 

 

 

C Ficheros virtuales

 



 

B.I.4 El servicio COMjvida para el juego de la vida. 

 

B.I.4.0 Introducción

 

B.I.4.1 El servicio SRVida como sintetización algorítmica del programa PVida de generación de evoluciones del juego de la vida

 

 B.I.4.1.1 Esquema de implementación

 B.I.4.1.2 Rutinas de inicialización

 B.I.4.1.3 Rutina de evolución generacional

 

 

B.I.4.2 El servicio COMjvida como interfaz de SRVida

 

                                                                                                            _________


B.I.4.0 Introducción

  

Como en el ejemplo anterior, en la parte II se presentó un programa para generar evoluciones del Juego de la Vida, con un interfaz Visual C++ 6.

 

Con el fin de incluir un temporizador, mejorar el interfaz e incluir recursos adicionales, se tomará el programa y se extraerá la parte algorítmica desarrollando una DLL.

 

A esta DLL, SRJvida, se le proporcionará un interfaz COM, COMJvida, que será finalmente utilizado en un programa de presentación escrito en Visual Basic NET. (Remitimos a este capítulo para ver el interfaz de presentación que comparte con el modelo COM).

 

                                                                                                            _________



 

B.I.4.1 El servicio SRVida como sintetización algorítmica del programa PVida de generación de evoluciones del juego de la vida


 

El servicio SRMagic resultante de sintetizar Pmagic implementa las siguientes funciones:

 

Apertura y cierre  

 

 La apertura crea los ficheros virtuales de soporte del proceso, que se cierran con la rutina close.

 

   long SRjvida_Open(void); 

   short int SRjvida_Close(void); 

 

 

Generación  

 

 En este epígrafe se encuadran las rutinas de Creación de nueva población, de evolución y de vaciado. 

 

   long SRjvida_New(long Nmax);   // Crea una nueva población de partida 

   long SRjvida_Gen(void);        // Invoca una nueva generación poblacional 

   short int SRjvida_CLRF(void);  // Elimina la población actual 

   

 

Acceso a datos 

 

 Permiten recuperar los datos de una celda (su estado de activación a) por acceso directo a una celda (i,j) o secuencial, por el número de orden solicitado.

 

 También se puede establecer el estado de una celda con la función write.

 

   short int SRjvida_Ocupada(long i, long j); 

   short int SRjvida_Read(long indice, long *i, long *j, short int *a); 

   long SRjvida_Write(long i, long j, short int a); 

  

 

Informativas 

 

 Permiten conocer el nº de ítems de la población así como el marco de referencia de los límites alcanzados en la evolución poblacional

 

   long SRjvida_Npob(void); 

   long SRjvida_Ref(long Nmax, long *i01, long *j01, long *i02, long *j02, long *i1,  long *j1,  long *i2,  long *j2); 

 

 

Control de visualización  

 

 El sistema genera una población que puede consultarse de forma global o por ventanas de amplitud NMAX.

 

 La población parte de un punto y se expande, el punto de partida puede quedar muy desfasado y ser conveniente actualizarlo.

 

 Las funciones de control de visualización siguientes permiten entonces desplazar el marco de referencia de visualización.

 

   void SRjvida_00(short int holgura); // Desplaza a posición 00 

   void SRjvida_i0(short int holgura); // Deja fija la fila actual y desplaza a columna 0 

   void SRjvida_0j(short int holgura); // Deja fija la columna actual y desplaza a fila 0

 

   void SRjvida_99(long Nmax, short int holgura); // Desplaza al extremo superior de la evolución 

   void SRjvida_i9(long Nmax, short int holgura); // Deja fija la fila actual y  desplaza al extremo 

   void SRjvida_9j(long Nmax, short int holgura); // Deja fija la columna actual y desplaza al extremo 

   void SRjvida_09(long Nmax, short int holgura); // Desplaza a la cuadrícula extrema derecha “09” 

   void SRjvida_90(long Nmax, short int holgura); // Desplaza a la cuadrícula extrema izquierda “90” 

 

   void SRjvida_H(long Desp);  // Desplazamiento horizontal 

   void SRjvida_HD(long Desp); // Desplazamiento horizontal derecho 

   void SRjvida_HI(long Desp); // Desplazamiento horizontal izquierdo 

   void SRjvida_V(long Desp);  // Desplazamiento vertical 

   void SRjvida_VI(long Desp); // Desplazamiento vertical inferior 

   void SRjvida_VS(long Desp); // Desplazamiento vertical superior 

 

                                                                                                            _________ 

 

B.I.4.1.1 Esquema de implementación

 

La implementación principal derivada de la original de la pantalla Pvida consiste en disponer de dos ficheros virtuales, “PVIDAC” con la población en curso y “PVIDAA” con la población anterior.

 

En cada nueva partida se regenera una versión inicial de “PVIDAC” que evoluciona con ayuda de “PVIDAA” que sirve de paso de una generación a otra

 

Tenemos entonces el siguiente esquema principal de implementación:

 

Inicio:

 

 SRvida_Open

 

 

Ciclo:

 

 SRvida_New

 

 

 Subciclo:

 

   SRvida_Gen

 

     Copia PVIDAC a PVIDAA

     Añade envoltura de frontera a PVIDAA

     Limpia destino PVIDAC

     Recorre PVIDAA volcando a PVIDAC siguiendo las reglas del juego de la vida

 

 

Fin:

 

 SRvida_Close

 

 

En cada subciclo, el contenido de PVIDAC queda disponible para su presentación en el programa interfaz elegido, utilizando las rutinas de acceso a datos y control de visualización.

 

 

Implementación

 

Veamos ahora el código núcleo de la implementación, que es mucho más asequible que su equivalente del ejemplo anterior dedicado a Sudokus y cuadrados mágicos, pues su algorítmica es más sencilla:

 

                                                                                                            _________

  

B.I.4.1.2 Rutinas de inicialización 

 

Distinguimos entre las rutinas dedicadas a la apertura, la regeneración y el vaciado poblacional:

 

 

Apertura 

 

   //----------------------------------------------------------------------------- 

   // Apertura común 

   // 

   // Open se encarga de crear las bases de datos virtuales de soporte y de  

   // cebar el generador de números aleatorios 

   // 

   //  Retorno: 0 = Error (Memoria agotada) 

   //          >0 Generación OK. Devuelve el identificador del vFile “PVIDAC” 

   //----------------------------------------------------------------------------- 

   long SRjvida_Open(void

   { 

    long lNID = 0;   // Nid asignado al fichero de soporte de datos 

    long lNID01=0;   // Nid asignado al lógico ji 

  

    // Crea ficheros virtuales de soporte. En curso y anterior  

    lNID = SRRCW_NEW("PVIDAC", sizeof(sDsK), sizeof(sDsKD)); 

    lNID01 = SRRCW_CRTLF("PVIDAC01", "PVIDAC", 1 + sizeof(sDsK), sizeof(sDsK01)); 

    lNID = SRRCW_NEW("PVIDAA", sizeof(sDsK), sizeof(sDsKD)); 

    lNID01 = SRRCW_CRTLF("PVIDAA01", "PVIDAA", 1 + sizeof(sDsK), sizeof(sDsK01)); 

 

    // Ceba el generador de nºs aleatorios con el time actual para que las  

    // cantidades generadas sean distintas cada vez que se ejcute el programa 

     

    srand( (unsigned)time( NULL ) ); 

    return lNID

  

    

 

Regeneración 

 

   //----------------------------------------------------------------------------- 

   // Nueva generación 

   // 

   // New se encarga de reiniciar el sistema con una nueva población de partida 

   // 

   // New devuelve el tamaño de la población inicial 

   // 

   //----------------------------------------------------------------------------- 

   long SRjvida_New(long Nmax

   { 

    short int er = 0;   // Control de errores 

    long i = 0, j = 0;  // Contadores de for 

    long lresul = 0;    // Control de resultados 

    double dRand = 0.0; // Rand utilizado (0,1) 

    double dPunto=0.67; // Punto selector 

 

    // Reinicio generacional 

    NGEN = 1;    // Contador generacional 

    ISUM = KSUM; // “Hiperespacio” I 

    JSUM = KSUM; // “Hiperespacio” J 

 

    // Inicializa ficheros virtuales de soporte 

    er = SRjvida_CLRF(); 

 

    // Ciclo de proceso de nueva población inicial 

    for (i=1;i<=Nmax;++i

     for (j=1;j<=Nmax;++j

    

      // Genera un nº aleatorio entre 0 y 1 

      dRand = (double) rand() / (double) RAND_MAX; 

 

      // Graba un ítem 2 de cada 3 veces en promedio 

      if (dRand < dPunto) lresul = SRjvida_Write(i, j, 1); 

     

 

    // Devuelve el tamaño poblacional de partida  

    er = SRRCW_INF("PVIDAC", &iDimC, &lDimD, &lNITEM, &lBAJAS, &lNIDD); 

 

    return (lNITEM - lBAJAS); 

   } 

 

 

Vaciado poblacional 

 

   //----------------------------------------------------------------------------- 

   // Vacia los ficheros virtuales de soporte, en las regeneraciones 

   //----------------------------------------------------------------------------- 

   short int SRjvida_CLRF(void) 

  

    short int er = 0; // Control de errores. Valor de retorno 

    er  = SRRCW_CLRF("PVIDAA"); 

    er  = SRRCW_CLRF("PVIDAC"); 

    return er

   } 

                                                                                                            _________

 

B.I.4.1.3 Rutina de evolución generacional 

 

En cuanto al código para la evolución poblacional, donde concretamente se implementan las reglas del juego de la vida, se expone a continuación: 

 

   //----------------------------------------------------------------------------- 

   // Algoritmo de nueva generación poblacional 

   // 

   // Gen se encarga de evolucionar una población a la siguiente generación 

   // 

   // Gen devuelve el contador de generaciones poblacionales  

   //----------------------------------------------------------------------------- 

   long SRjvida_Gen(void

   { 

    short int er = 0;   // Control de errores 

    short int nvec = 0; // Contador de vecinos ocupados en población anterior 

    short int a = 0;    // 0/1 celda activa 

    long i = 0, j = 0;  // Contadores de for 

    long k = 0;         // Contador de READ 

    long lresul = 0;    // Control de resultados 

    double dRand = 0.0; // Rand utilizado (0,1) 

 

    // NºGeneración  

    ++ NGEN; 

 

    // Paso 1. Vuelca situación actual como anterior y limpia situación actual 

    lresul = SRRCW_CPY("PVIDAC", "PVIDAA"); 

 

    // Paso 2. Genera envoltura de exploración en población anterior 

    lresul = 0; 

    for(k=1;;++k) 

    { 

     er = SRRCW_READ("PVIDAC", k, &DSc); 

     if (er) break

     SRRCAL_lLexi(&DSc.DK.li);  // Intercambia peso por valor (Ver capítulo estructuras) 

     i = DSc.DK.li - ISUM; 

     SRRCAL_lLexi(&DSc.DK.lj); 

     j = DSc.DK.lj - JSUM; 

     lresul += PrEvolAnt(i, j); 

    } 

 

    // Paso 3. Limpia destino 

    er = SRRCW_CLRF("PVIDAC"); 

 

    // Paso 4. Núcleo algorítmico. Reglas del "juego de la vida de John H.Conway

    for(k=1;;++k) 

    { 

     // Lee población anterior+envoltura recién generada hasta su agotamiento 

     er = SRRCW_READ("PVIDAA", k, &DSa); 

     if (er) break

 

     // Pasa valor de claves y datos 

     SRRCAL_lLexi(&DSa.DK.li); // Intercambia peso por valor (Ver capítulo estructuras) 

     i = DSa.DK.li - ISUM; 

     SRRCAL_lLexi(&DSa.DK.lj); 

     j = DSa.DK.lj - JSUM; 

     a = DSa.DD.a

 

     // Nº de vecinos ocupados 

     nvec = PrNvec(i, j); 

 

     // Si una celda vacia tiene 3 vecinos exactamente, se ocupa 

     if (!a && nvec == 3) 

     { 

      lresul = SRjvida_Write(i, j, 1); 

      continue

     } 

 

     // Si una celda ocupada tiene menos de 2 vecinos muere por aislamiento 

     if (a && nvec < 2) continue

 

     // Si una celda ocupada tiene más de 3 vecinos muere por superpoblación 

     if (a && nvec > 3) continue

 

     // El resto de celdas se mantiene como estaba 

     if (!a) continue; 

     lresul = SRjvida_Write(i, j, 1); 

     continue

    } 

  

    // Devuelve el nº de generación alcanzado 

    return NGEN; 

   } 

 

El resto del código, trascripción directa de la pantalla original, puede encontrarse en el apartado dedicado al fuente completo

 

                                                                                                            _________

 

 

B.I.4.2 El servicio COMjvida como interfaz de SRjvida 

 

Para SRjvida se puede definir COMjvida con un interfaz estandarizado ISRjvida apto para la familia de lenguajes MS con los siguientes métodos para acceso a las funciones de SRjvida:

 

__interface ISRjvida : IDispatch 

 [id(1), helpstring("method Open")] HRESULT Open([out] LONG* lNID); 

 [id(2), helpstring("method Close")] HRESULT Close([out] LONG* lErro); 

 [id(3), helpstring("method New")] HRESULT New([in] LONG lNmax, [out] LONG* lNpob); 

 [id(4), helpstring("method Gen")] HRESULT Gen([out] LONG* lNgen); 

 [id(5), helpstring("method Npob")] HRESULT Npob([out] LONG* lNpob); 

 [id(6), helpstring("method Ocupada")] HRESULT Ocupada([in] LONG i, [in] LONG j, [out] LONG* lResul); 

 [id(7), helpstring("method Ref")] HRESULT Ref([in] LONG lNmax, [out] LONG* i01,  

                                               [out] LONG* j01, [out] LONG* i02,    

                                               [out] LONG* j02, [out] LONG* i1,   

                                               [out] LONG* j1,  [out] LONG* i2,  

                                               [out] LONG* j2, 

                                               [out] LONG* lSizeDiagonal); 

 [id(8), helpstring("method Write")] HRESULT Write([in] LONG i, [in] LONG j, [in] LONG activar, [out] LONG* lResul); 

 [id(9), helpstring("method V00")] HRESULT V00([in] LONG holgura); 

 [id(10), helpstring("method i0")] HRESULT i0([in] LONG holgura); 

 [id(11), helpstring("method V0j")] HRESULT V0j([in] LONG holgura); 

 [id(12), helpstring("method Vi0")] HRESULT Vi0([in] LONG holgura); 

 [id(13), helpstring("method V99")] HRESULT V99([in] LONG lNmax, LONG holgura); 

 [id(14), helpstring("method Vi9")] HRESULT Vi9([in] LONG lNmax, LONG holgura); 

 [id(15), helpstring("method V9j")] HRESULT V9j([in] LONG lNmax, LONG holgura); 

 [id(16), helpstring("method V09")] HRESULT V09([in] LONG lNmax, LONG holgura); 

 [id(17), helpstring("method V90")] HRESULT V90([in] LONG lNmax, LONG holgura); 

 [id(18), helpstring("method H")] HRESULT H([in] LONG lDesplazamiento); 

 [id(19), helpstring("method HI")] HRESULT HI([in] LONG lDesplazamiento); 

 [id(20), helpstring("method HD")] HRESULT HD([in] LONG lDesplazamiento); 

 [id(21), helpstring("method V")] HRESULT V([in] LONG lDesplazamiento); 

 [id(22), helpstring("method VI")] HRESULT VI([in] LONG lDesplazamiento); 

 [id(23), helpstring("method VS")] HRESULT VS([in] LONG lDesplazamiento); 

 [id(24), helpstring("method CLRF")] HRESULT CLRF([out] LONG* lError); 

 [id(25), helpstring("method Read")] HRESULT Read([in] LONG Indice, [out] LONG* EndOfFile, [out] LONG* i,

                                                  [out] LONG* j, [out] LONG* a); 

};

 

Para construir este interfaz hay que proceder de la misma forma que se siguió en el capítulo dedicado al servicio COMw, interfaz COM de SRRCW para uso en Visual Basic.

                                                                                                            _________

 

El código completo de esta serie se encuentra en el apéndice

"C5 Relación de programas de muestra desarrollados en el libro"

 

                                                                                                            _________