miércoles, 27 de enero de 2021

Mi primera infografía ¿o infograma?

La infografía es la ciencia que trata acerca de los infogramas. Y un infograma es un diagrama visual que resume o explica figurativamente informaciones o textos, empleando más variados medios visuales e incluso auditivos que el mero esquema o diagrama. Pero he notado que a veces se usa la palabra “Infografía” como sinónimo de “infograma”.

De todas formas he tenido la experiencia de crear mi primer infograma a partir de una herramienta en línea llamada Canva. En el pasado sí había usado muchas representaciones visuales pero este es el primer Infograma propiamente dicho.



viernes, 8 de enero de 2021

Los Miserables.

Había escuchado alguna vez un resumen de esta obra literaria en Mi novela favorita. En aquella ocasión no logró llamar mi atención. Pasado el tiempo, por casualidad encontré en un servicio de streaming la pelicula-musical del año 2012 y los primeros segundos fueron como un puñetazo en la cara con la escena de los reos remolcando el barco. De ahí en adelante me quedé enganchado hasta verla por completa.

Decididamente me emocioné. Investigué y encontré que es una novela de la cual se han hecho un sin fin de adaptaciones en la televisión, el cine y como musical. En YouTube se pueden encontrar varios musicales en español como este.

Finalmente, escuché la obra completa en audio-libro y me encantó. Es larga, pero por lo general me mantuvo atento, tuve algunas gratas sorpresas y a veces me conmoví hasta casi soltar una lagrimita. La escena donde se describe a Cossette de niña en la posada de los Thenardier me partió el corazón. Sin embargo, hubo dos escenas en donde se requiere discreción por su contenido un poco fuerte para los más pequeños: La caida de Fantine y la toma de la barricada. Pero en general, me gustó.

miércoles, 6 de enero de 2021

Intérprete para Logo

Hace ya varios años desarrollé un rústico interprete para el lenguaje de programación Logo. Lo bueno es que funciona. Lo malo es que usa demasiados recursos del sistema ya que se abusa de la recursividad. Hay que tener en cuenta que este programa lo creé cuando estaba mucho más crudo en programación. Para evitar tener que usar la recursividad se pueden usar pilas.

Las instrucciones que reconoce el interprete son las siguientes:

TO Marca el inicio de la función / archivo
END Marca el fin de la función / archivo
IF [condición] Ejecuta la linea si la condición se cumple.
FD [pasos] Fordward. Avanza la cantidad de pasos.
BK [pasos] Back. Retrocede la cantidad de pasos.
LT [grados] Left. Gira a la izquierda una cantidad de grados.
RT [grados] Right. Gira a la derecha una cantidad de grados.
CC [radio] Dibuja una circunferencia de acuerdo al radio
[archivo/función] Invoca una función / archivo
BYE Sale de la aplicación.

El programa llama el codigo fuente de logo que se encuentra almacenado en archivos. Los archivos no tienen extensiones. los siguientes los usé para probar el interprete:


El siguiente ejemplo pinta un cuadro en la pantalla. Se debe invocar como cuadro desde la pantalla.

CUADRO
TO :L
FD :L
RT 90
FD :L
RT 90
FD :L
RT 90
FD :L
END

Otro ejemplo más robusto de lo que puede ejecutar este interprete se llama copo y dibuja una imagen fractal de un copo de nieve . Nótese que es una función recursiva.

COPO
TO :T
IF ( :T > 2 ) FD :T , COPO ( :T / 2 ), BK :T , RT 60
IF ( :T > 2 ) FD :T , COPO ( :T / 3 ), BK :T , RT 60
IF ( :T > 2 ) FD :T , COPO ( :T / 3 ), BK :T , RT 60
IF ( :T > 2 ) FD :T , COPO ( :T / 2 ), BK :T , RT 60
IF ( :T > 2 ) FD :T , COPO ( :T / 3 ), BK :T , RT 60
IF ( :T > 2 ) FD :T , COPO ( :T / 3 ), BK :T , RT 60
END

Para ejecutarlo habría que escribir desde la aplicación lo siguiente: copo [valor del parámetro]; por ejemplo escribir copo 100.

Fotografía del resultado de ejecutar el archivo copo que muestra un copo de nieve generado de forma recursiva. ¿Por que no se usó una captura de pantalla? Porque el programa no lo permitió o más bien no se encontró la forma de dejarse capturar un pantallazo que hubiese sido más nitido. 

El siguiente es el código fuente del interprete. Fue creado en Borland C++ y requiere la librería grafica para funcionar por consiguiente requiere acceso al driver correspondiente de la carpeta bgi.

logo.cpp
#include <graphics.h>
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <math.h>

#define ANCHOLINEA 100
#define ALTO 20

struct { char nombre[30];
	 char variable[30];
	 int tope;
	 char M[ALTO][ANCHOLINEA];
	 } bloque;

// declaraci¢n de las funciones
int ejecutalinea(char c[]);
int buscaarchivo(char archivo[]);
int ejecutaarchivo(char archivo[], char param[]);
void cambiar(char linea[],char variable[], char param[]);
void operar(char linea[]);
void haceroperacion(char c[]);
int estavacio(char c[]);
int hacerif(char c[]);
int determinarsi(char comp[]);
int ejecutabloque(char param[]);
int buscabloque(char c[]);


// variables globales
float or;
float xmax, ymax,cx,cy,fx,fy;
char error[400];

void main(void)
{
   int gdriver = DETECT, gmode, errorcode;
   char c1[ANCHOLINEA];
   or=90;
   initgraph(&gdriver, &gmode, "\\borlandc\\bgi");
   errorcode = graphresult();
   if (errorcode != grOk)
   {  printf("Error: %s\n", grapherrormsg(errorcode));
      getch();
      exit(1); }
   xmax = getmaxx();
   ymax = getmaxy();
   cx = xmax/2+50;
   cy = ymax/2;
   outtextxy(5,5," ::Bienvenido a LOGO:: ");
   do
   {
    strcpy(error,"");
    gotoxy(3,2);
    setviewport(5,15,280,100,1);  //estas instrucciones
    clearviewport();             //borran un pedazo
    setviewport(0,0,xmax,ymax,1);//de la pantalla
    printf(">> ");
    gets(c1);
    if (!ejecutalinea(c1))
     {
     printf(" %s\n Presione una tecla",error);
     getch();
     }
   }while((strcmp(c1,"BYE")!=0));
   closegraph();
}/* main */



int ejecutalinea( char c[])
{
   char c1[ANCHOLINEA],p2[ANCHOLINEA];
   float c2;
   int j=0,i=0;
   strupr(c);
   if (estavacio(c)) return 1;
   while ( c[i]!= ' ' && i<=strlen(c) && c[i]!= 10 && c[i]!= 13)
     {
     c1[i]=c[i];
     i++;
     }
   c1[i]=0;
   i++;
   while (i<=strlen(c))
    {
    p2[j]=c[i];
    i++;
    j++;
    }
   p2[j]=0;
   if (strcmp(c1,"BYE")==0) return (1);
   if (strcmp(c1,"IF")==0)
       return (hacerif(p2));
   else
     if (strcmp(c1,"FD")==0)
    	{
    	c2 = atof(p2);
    	fy = cy - (sin(M_PI * or / 180 ) * c2);  // se usan las funciones sin() y cos() para calcular los nuevos puntos de acuerdo a la orientacion y el avance
    	fx = cx + (cos(M_PI* or / 180 ) * c2);  // sin() y cos() trabajan en radianes no en grados es necesario convertir
    	line(cx,cy,fx,fy); // se dibuja el avance con una linea
    	cx = fx;
    	cy = fy;
    	}
     else
       if (strcmp(c1,"BK")==0)
        	{
        	c2 = atof(p2);
        	fy = cy + (sin(M_PI * or / 180 ) * c2);  // se usan las funciones sin() y cos() para calcular los nuevos puntos de acuerdo a la orientacion y el avance
        	fx = cx - (cos(M_PI* or / 180 ) * c2);  // sin() y cos() trabajan en radianes no en grados es necesario convertir
        	line(cx,cy,fx,fy); // se dibuja el avance con una linea
        	cx = fx;
        	cy = fy;
        	}
       else
	 if (strcmp(c1,"LT")==0)
	    {
	    c2 = atof(p2);
	    or = or+c2;
	    }
	 else
	   if (strcmp(c1,"CC")==0)
	    {
	    c2 = atof(p2);
	    circle(cx,cy,c2);
	    }
	   else
	    if (strcmp(c1,"RT")==0)
	     {
	     c2 = atof(p2);
	     or = or-c2;
	     }
	    else
	       if (buscabloque(c1))
		  {
		  return (ejecutabloque(p2));
		  }
	       else
		 if (buscaarchivo(c1))
		    {
		    return (ejecutaarchivo(c1,p2));
		    }
		 else
		    {
		    strcat(error,"\n No se reconoce este comando: ");
		    strcat(error,c1);
		    return(0);
		    }
return(1);
}


int buscaarchivo(char archivo[])
{
FILE *ma;
if ((ma = fopen(archivo, "r+")) == NULL)
   {
   strcat(error,"\n No se encuentra este archivo: ");
   strcat(error,archivo);
   return 0;
   }
fclose(ma);
return 1;
}


int ejecutaarchivo(char archivo[], char param[])
  {
  int i;
  FILE *in;
  char encabezado[ANCHOLINEA],variable[ANCHOLINEA];
  char M[ALTO][ANCHOLINEA];
  int res,j,l,tope=0;
  in = fopen(archivo, "r+");
  if (in == NULL) return (0);
  fgets(encabezado,sizeof(encabezado),in);
  j=0;
  for (i=3;i<strlen(encabezado);i++)
     {
     variable[j]=encabezado[i];
     j++;
     }
  variable[j-1]=0;
  strcpy(bloque.nombre,archivo);
  strcpy(bloque.variable,variable);
  do {
     fgets(M[tope],sizeof(M[tope]),in);
     if (!feof(in))
        {
        l = strlen(M[tope]);
        M[tope][l-1]=0;
        strcpy(bloque.M[tope],M[tope]);
        cambiar(M[tope],variable,param);
        operar(M[tope]);
        tope++;
        }
    } while (!feof(in));
  fclose(in);
  bloque.tope = tope;
  i=0;
  do {
      if ((strcmp(M[i],"END ")!=0)&&(strcmp(M[i],"END")!=0))
        {
        res = ejecutalinea(M[i]);
        }
      i++;
     } while ((i<tope)&&(res));
  if (!res)
     {
     strcat(error,"\n Error en : [");
     strcat(error,M[i-1]);
     strcat(error,"]");
     }
  return(res);
}


void cambiar(char linea[],char variable[], char param[])
{  int i,j,k;
   char linres[ANCHOLINEA];
   char temp[ANCHOLINEA];
   k=0;
   strcat(linea," ");
   for(i=0;i<=strlen(linea);i++)
     {
     if (linea[i]==':')
      	{
      	j=0;
      	while(((linea[i]!= ' ')&&(i<=strlen(linea)))&&(linea[i]!= ')') && (linea[i]!= EOF) )
      	   {
      	     temp[j]=linea[i];
      	     linea[i]= ' ';
      	     i++;
      	     j++;
      	   }
      	temp[j]=0;
      	if (strcmp(temp,variable)==0)
      		{
      		for(j=0;j< strlen(param);j++)
      		  {
      		  linres[k]=param[j];
      		  k++;
      		  }
      		linres[k]=0;
      		}
      	}
     else
        {
        linres[k] = linea[i];
        k++;
        }
    }
   linres[k]=0;
   strcpy(linea,linres);
}


void operar(char linea[])
  {  
  int i,j,k;
  char linres[ANCHOLINEA];
  char operacion[ANCHOLINEA];
  k=0;
  for(i=0;i<=strlen(linea);i++)
     {
     if (linea[i]=='(')
      	{
      	j=0;
      	i++;
      	while((linea[i]!= ')')&&(i<=strlen(linea)))
      	   {
      	     operacion[j]=linea[i];
      	     linea[i]= ' ';
      	     i++;
      	     j++;
      	   }
      	operacion[j]=0;
      	linea[i]=' ';
      	haceroperacion(operacion);
      	for(j=0;j< strlen(operacion);j++)
      	  {
      	  linres[k]=operacion[j];
      	  k++;
      	  }
      	}
     linres[k] = linea[i];
     k++;
    }
  strcpy(linea,linres);
}


void haceroperacion(char c[])
  {
   char c1[ANCHOLINEA];
   char c2[ANCHOLINEA];
   char c3[ANCHOLINEA];
   char signo;
   int j=0,i=0;
   int num1,num2,res=0;
   while ((((c[i]!= '+')&&(c[i]!='-'))&&((c[i]!= '*')&&(c[i]!= '/')))&&i<=strlen(c))
     {
     c1[i]=c[i];
     i++;
     }
   if (! (i<=strlen(c)))
    	{
    	strcpy(c3,"( ");
    	strcat(c3,c);
    	strcat(c3," )");
    	strcpy(c,c3);
    	return;
    	}
   signo = c[i];
   c1[i]=0;
   i++;
   while (i<=strlen(c))
      {
      c2[j]=c[i];
      i++;
      j++;
      }
   c2[j]=0;
   num1 = atoi(c1);
   num2 = atoi(c2);
   switch(signo)
     {
     case '+':res = num1 + num2;
  	    break;
     case '-':res = num1 - num2;
  	    break;
     case '*':res = num1 * num2;
  	    break;
     case '/':if (num2 != 0)
  		 res = num1 / num2;
  	    else
  		 {
  		 strcpy(c,"NaN"); // Not a Number
  		 return;
  		 }
  	    break;
     }
   itoa(res,c,10);
}


int estavacio(char c[])
{
int i;
for(i=0;i<strlen(c);i++)
   {
   if (c[i] !=' ') return 0;
   }
return 1;
}


int hacerif(char c[])
  {
   char c1[ANCHOLINEA],p2[ANCHOLINEA];
   char M[ALTO][ANCHOLINEA];
   int tope,res=0;
   int j=0,i=1;

   while ( c[i]!= ')' && i<=strlen(c) )
     {
     c1[i-1]=c[i];
     i++;
     }
   c1[i]=0;
   i+=3;
   while (i<=strlen(c))
      {
      p2[j]=c[i];
      i++;
      j++;
      }
   p2[j]=0;
   j=0;
   if (determinarsi(c1))
      {
      tope = 0;
      for(i=0;i<=strlen(p2);i++)
      	{
      	if (p2[i] == ',')
      	    {
      	    tope++;
      	    j=0;
      	    i++;
      	    }
      	else
      	    {
      	    M[tope][j]=p2[i];
      	    j++;
      	    M[tope][j]=0;
      	    }
      	}
	tope++;
	i=0;
	do {
	  res = ejecutalinea(M[i]);
	  i++;
	}while ((i<tope)&&(res));
	if (!res)
	   {
	   strcat(error,"\n Error en : [");
	   strcat(error,M[i-1]);
	   strcat(error,"]");
	   }
      }
      else
	 res = 1;
return(res);
}


int determinarsi(char c[])
{
   char c1[ANCHOLINEA];
   char c2[ANCHOLINEA];
   char oper[3];
   int j=0,i=0;
   int num1,num2,ret=0;
   while ( c[i]!= '>' && c[i]!='<' && c[i]!= '=' && i<=strlen(c))
     {
     c1[i]=c[i];
     i++;
     }
   c1[i]=0;
   oper[0] = c[i];
   i++;
   oper[1] = c[i];
   oper[2] = 0;
   i++;
   while (i<=strlen(c))
    {
    c2[j]=c[i];
    i++;
    j++;
    }
   c2[j]=0;
   num1 = atoi(c1);
   num2 = atoi(c2);
   if (strcmp(oper,"> ")==0)
	    if (num1 > num2)
		 ret = 1;
	    else
		 ret = 0;
   else
   if (strcmp(oper,"< ")==0)
	    if (num1 < num2)
		 ret = 1;
	    else
		 ret = 0;
   else
   if (strcmp(oper,"= ")==0)
	    if (num1 == num2)
		 ret = 1;
	    else
		 ret = 0;
   else
   if (strcmp(oper,">=")==0)
	    if (num1 >= num2)
		 ret = 1;
	    else
		 ret = 0;
   else
   if (strcmp(oper,"<=")==0)
	    if (num1 == num2)
		 ret = 1;
	    else
		 ret = 0;
return ret;
}


int buscabloque(char c[])
{
int ret=0;
if (strcmp(c,bloque.nombre)==0)
     {
     ret = 1;
     }
return (ret);
}


int ejecutabloque(char param[])
{
char M[ALTO][ANCHOLINEA];
int i=0,res=0;
do {
  strcpy(M[i],bloque.M[i]);
  cambiar(M[i],bloque.variable,param);
  operar(M[i]);
  res = ejecutalinea(M[i]);
  i++;
}while ((i< bloque.tope)&&(res));
  if (!res)
     {
     strcat(error,"\n Error en : [");
     strcat(error,M[i-1]);
     strcat(error,"]");
     }
return(res);
}

lunes, 4 de enero de 2021

Obras literarias que han pasado por mi vida

Estas son obras de la literatura, libros, publicaciones que recuerdo haber leido completas. Anoto la impresión que me ha producido cada una de ellas.

  • Cien años de soledad. Leida de principio a fin cuando era un adolescente. Me parece que el personaje principal es Ursula. Trata del ascenso y caida del linaje Buendía. Es interesante la descripción que hace del entorno y las costumbres de antaño de la zona caribe. Y, por supuesto, es una ejemplo de una obra perteneciente al realismo mágico. Al lector de esta obra debe tener en cuenta el lenguaje que algunas veces se usa y algunas escenas bastante fuertes.
  • Alguien desordena estas Rosas. La parte que más me gustó, desde el punto de vista literario, es esta: 

"Yo estaba cubierto de polvo y telaraña cuando ella abrió la puerta y en alguna parte de la habitación guardó silencio el grillo que había estado cantando durante veinte años."

  • La idea que da vueltas. Otro cuento de Gabriel García Marquez.
  • Crónica de una muerte anunciada. Esta novela tiene una película. Siempre quedaré con la duda si Santiago Nazar fue culpable o no. Según la pelicula si lo era, pero el libro no lo deja claro. Nuevamente, el lenguaje puede ser bastante altisonante y la descripción de la muerte bastante gráfica.
  • El coronel no tiene quie le escriba. Me parece que esta es la novela más triste y desesperanzadoras del autor.
  • La increíble y triste historia de la Cándida Eréndira y de su abuela desalmada. El título lo dice todo. Misma anotación en cuanto a lenguaje y descripciones.
  • Los funerales de la mamá grande. Otro cuento corto con descripciones costumbristas.

Llegado a este punto me estoy sorprendiendo de todas la literatura de este autor que leí durante mi juventud. Sin embargo, no es un autor favorito debido al lenguaje usado, a las descripciones y a la misma temáticas. Pero no niego que desde un punto de vista estrictamente literario es un excelente autor.

  • Otro de esos autores que leí en mi juventud: Edgar allan Poe. Aunque literariamente fue muy bueno ocurre algo parecido que con el anterior. Recuerdo que pensé que tuvo que estar loco. El hundimiento de la casa Husher, El Cuervo, El corazón delator  Las aventuras de Arthur Gordon Pym.
    • Cuentos de la selva. Horacio Quiroga. Siempre pensé que un Yacaré era una especie de cocodrilo. No estaba tan mal: Es una especie de caimán. (La guerra de los yacarés).
    • María. Jorge Isaac. Esta novela me enseño lo que es una garúa.
    • Las aventuras de Alicia en el país de las maravillas. Lewis Carroll.

    • La cabaña del tío Tom. Novela de Harriet Beecher Stowe. Después de leer la novela fue una grata sorpresa enterarme que Harriet Beecher Stowe fue una mujer.
    • Manual de Automoviles. Manuel Arias Paz. Es que una vez quise ser mecánico. 
    • La divina comedia. Dante Alighieri. Que lo haya leido todo no significa que esté de acuerdo con su contenido.
    • la Odisea. Homero. Una de las primeras lecturas sobre aventuras.
    • Lazarillo de Tormes. Anónimo.
    • La isla del tesoro. Novela de Robert Louis Stevenson. 
    • Las aventuras de Tom Sawyer.  Mark Twain.
    • Las aventuras de Huckleberry Finn. Mark Twain.
    • La vuelta al mundo en ochenta días.  Julio Verne.
    • Crimen y Castigo. Fedor Dostoiewski. Un lento descenso hacia la mente de un asesino. Lamento haberla leído.
    • Orgullo y prejuicio. Jane Austen. Creo que es la novela más hermosa que he leído.
    • Sentido y sensibilidad. Jane Austen.  
    • Don Quijote de la Mancha (Parte I y II). Miguel de Cervantes. Para ser honesto no la leí directamente y creo que mi paciencia no habría dado para tanto. La primera parte la escuché en audiolibro y la segunda la escuche en forma de resumen - analisis.
    • La Biblia. La mejor de todas.