domingo, 5 de febrero de 2017

JSON con python (parte I)


·        JSON (JavaScript Object Notation):

Es un formato para el intercambio de información entre aplicaciones, a pesar de que en sus inicios fue considerado como parte de JavaScript,  es reconocido por una gran variedad de lenguajes de programación (incluido python) ya que es independiente al lenguaje que utilicemos.


Actualmente es empleado para el intercambio de información entre servicios web y APIs y es uno de los formatos alternativos al XML más utilizado por los desarrolladores. Entre los módulos propios de python contamos con el modulo: json, utilizado para trabajar con este formato.


·        Objeto JSON: 

Puede definirse como una entidad que posee propiedades, las cuales pueden ser definidas por nosotros según los datos que necesitemos representar, en el caso de quienes utilizamos el lenguaje python podemos comparar la estructura de un objeto json, con la estructura de un formulario python.


·        Sintaxis objeto JSON:

{“propiedad1” : ”valor1” , ”propiedad2” : ”valor2” , ”propiedad n” : ”valor n”}

Donde la propiedad es una especie de llave a través de la cual podemos acceder a su valor asociado.


·        Valores permitidos por el objeto JSON:

o   Para la propiedad: debe utilizarse una cadena de caracteres, la cual debe colocarse entre comillas dobles.

o   Para los valores podemos usar los siguientes tipos de datos:

§   Números (enteros o float).
§   Un string entre comillas dobles.
§  Un arreglo.
§  Un objeto JSON (entre llaves).


·        Ejemplo básico:

Supongamos que necesitamos crear un objeto para representar un automóvil, para el cual debemos reflejar; marca, modelo y primer 
año que  estuvo disponible en el  mercado, nos quedaría el siguiente objeto JSON:


auto {"marca":"toyota","modelo":"celica","iniciop":"1970"}.

  • Ejemplo práctico:


     Un objeto json, puede contener en su interior otros objetos json, como      veremos en el siguiente ejemplo en el cual simularemos la recepción de  información en formato json, la cual extraeremos del archivo llamado  prueba.json.

 Para los datos que recibiremos, se plantea representar automóviles, los cuales deben agruparse según su marca y a su vez  necesitamos saber el modelo   y el  año en el que inicio la producción de cada auto, la estructura básica de  la información y los datos que utilizaremos se muestran a continuación:

Autos:

Toyota:

1.      Modelo: toyota 4runner, Primer año: 1984.
2.      Modelo: toyota corolla, Primer año: 1971.
3.     Modelo: toyota celica, Primer año: 1970.

              Chevrolet:
1.     Modelo: chevrolet camaro, Primer año: 1967.
2.     Modelo: chevrolet chevelle, Primer año: 1964.
3.     Modelo: chevrolet corvette c4, Primer año: 1984. 
              Ford:
1.     Modelo: ford mustang, Primer año: 1964.
2.     Modelo: ford shelby gr-1, Primer año: 2005.
3.     Modelo: ford T, Primer año: 1908.



El objeto JSON que representa los datos anteriores se muestra a continuación: 


{"autos":
 [
  {"toyota":
     [
      {"modelo":"toyota 4runner","iniciop":"1984"},
      {"modelo":"toyota corolla","iniciop":"1971"},
      {"modelo":"toyota celica","iniciop":"1970"}
     ]
  },
  {"chevrolet":
     [
      {"modelo":"chevrolet camaro","iniciop":"1967"},
      {"modelo":"chevrolet chevelle","iniciop":"1964"},
      {"modelo":"chevrolet corvette C4","iniciop":"1984"}
     ]
  },
  {"ford":
     [
      {"modelo":"ford mustang","iniciop":"1964"},
      {"modelo":"ford shelby gr-1","iniciop":"2005"},
      {"modelo":"ford t","iniciop":"1908"}
     ]
  }
 ]
}



  • Cargar datos de archivo .json usando python:

     
Como indique anteriormente, python cuenta con el modulo: json,  el cual nos  ofrece métodos para trabajar con el formato JSON,a continuación procedo a obtener los datos del archivo: prueba.json para lo cual podemos usar cualquiera de los siguientes métodos:


o   json.load(): recibe como parámetro un archivo que contiene objetos json, y devuelve un diccionario python , con las propiedades y valores indicadas en el objeto  json.

   import json

datos=json.load(open('prueba.json','r'))
print type(datos)


   <type 'dict'>


o   json.loads(): recibe como parametro una cadena de caracteres que contiene un objeto json y devuelve un diccionario python , con las propiedades indicadas en el objeto json.    


   import json

datos=open('prueba.json','r').read()
print type(datos)
datos=json.loads(datos)
print type(datos)


   <type 'str'>
  <type 'dict'>

·        Acceder a elementos de un objeto json:
          Una  vez cargado nuestro objeto json, podemos acceder a sus elementos, solo tenemos que tener claro su estructura, en el caso de nuestro archivo : prueba.json , está formado por un objeto json de clave: "autos" y cuyos valores , son 3 objetos json cuyas claves son : "toyota", "chevrolet" y "ford", a su vez cada una de las marcas está formada por 3 objetos json que contienen la información de los automóviles. A continuación muestro una representación gráfica del objeto json: "autos":
    Supongamos que deseamos obtener los datos del auto: toyota 4runner, lo hacemos con el siguiente código:



  import json

datos=open('prueba.json','r').read()
datos=json.loads(datos)
print datos["autos"][0]["toyota"][0]


  {u'iniciop':u'1984',u'modelo':u'toyota 4runner'}



    Si queremos imprimir los datos de todos los autos de una marca  específica, podemos hacerlo de la siguiente manera:

  import json


llave_marca="toyota"
indice_marca=0

datos=open('prueba.json','r').read()
datosjson.loads(datos)

for auto in datos["autos"][indice_marca][llave_marca]:
 print"############################################"
 print"Modelo: ",auto["modelo"]
 print"Inicio produccion en:" ,auto["iniciop"]
 print"\n"


######################################
Modelo : toyota 4runner
Inicio produccion en : 1984
 
###################################### 
Modelo : toyota corolla
Inicio produccion en : 1971

######################################
Modelo : toyota celica
Inicio produccion en : 1970      

    
    Si queremos imprimir los datos de todo el objeto: "autos" una posible solución es la siguiente:


  import json


datos=open('prueba.json','r').read()

datos=json.loads(datos);

for indice_marca in datos["autos"]:
 for marca in indice_marca.keys():
  for auto in indice_marca[marca]:
   print"######################################"
   print "Modelo: ",auto["modelo"]
   print "Inicio produccion: ",auto["iniciop"]
   print"\n"


######################################
Modelo : toyota 4runner
Inicio produccion en : 1984
 
###################################### 
Modelo : toyota corolla
Inicio produccion en : 1971

######################################
Modelo : toyota celica
Inicio produccion en : 1970 

######################################
Modelo : chevrolet camaro
Inicio produccion en : 1967 

######################################
Modelo : chevrolet chevelle
Inicio produccion en : 1964

######################################
Modelo : chevrolet corvette C4 
Inicio produccion en : 1984

######################################
Modelo : ford mustang 
Inicio produccion en : 1964

######################################
Modelo : ford shelby gr-1 
Inicio produccion en : 2005

######################################
Modelo : ford t 
Inicio produccion en : 1908     


     Referencias:


lunes, 23 de enero de 2017

Sobre las variedades de Python y su interoperabilidad

Retomo nuevamente este blog después de una larga pausa exponiendo sobre el tema de las distintas variedades de Python, sobre las cuales seguramente habrán oído: CPython (no confundir con Cython), Jython, RPython, IronPython, Brython, etc. En realidad, nunca me he puesto a profundizar sobre el tema hasta que me topé con un artículo en el blog de Toptal sobre esto titulado '¿Porqué hay tantos Pythons?'. Toptal es un sitio que reúne los mejores freelancers de la industria del diseño y el desarrollo de software y aplicaciones web, con especialistas en desarrollo para Android, JavaScript, Java, Data Science y por supuesto, Python. Toptal tiene un blog, con algunos artículos traducidos al español, que vale la pena mirar.

Detrás de esta discusión sobre las distintas "variedades" de Python está el tema de cómo Python "compila" el código de un script para generar bytecode que luego es interpretado por una máquina virtual que interactúa directamente con el compilador. Entonces debemos entrar en el tema del bytecode, de las máquinas virtuales, de los compiladores y de los interpretes y sobre todo, como estos conceptos se aplican a lo que es Python realmente - ¿es un compilador o un interprete? Toda esta discusión es llevada de manera muy amena y sencilla por el autor del mencionado artículo. El entender estos temas ayuda a comprender la gran popularidad de Python entre la comunidad de desarrolladores y a qué se debe su gran versatilidad e interoperabilidad.


Python y sus máquinas virtuales - Blog Toptal

El simple hecho de que una vez que se "compila" el código en Python a bytecode (que es independiente de la máquina física) y luego este sea interpretado por una máquina virtual que interactúa directamente con la máquina física abre muchas posibilidades de interoperabilidad para Python. Por ejemplo, usando Jython, que es un Python cuya máquina virtual corre en Java, es teóricamente posible escribir aplicaciones para Android. Jython compila el código Python a bytecode de Java, es decir, a archivos .class. Para desarrollar aplicaciones para Android, uno recompilaría el bytecode de Java a bytecode de Dalvik, el cual debería correr en Android siempre y cuando el código no dependa de API's de Java que Android no provea. Ojo, yo personalmente no he probado nada de esto pero según lo que he leído (consultar fuentes), es teóricamente factible.

De igual manera, con Brython u otras variedades similares, la máquina virtual traduce el bytecode de Python a Javascript, con lo cual se abren posibilidades interesantes para desarrollar aplicaciones en la web con Python. Nuevamente, esto es territorio aún desconocido para mi. Si algún lector tiene experiencia en estos temas, mucho le agradecería que nos cuente en los comentarios de esta entrada.

Referencias

martes, 4 de marzo de 2014

La Cueva del Tiempo- otro videojuego de texto

En el afán de explorar las posibilidades de la consola de texto para elaborar vídeo juegos, consideraremos los juegos de aventura basados en texto, de los cuales el legendario Zork es el más conocido exponente. En los juegos de aventura de texto, se le presenta al jugador la descripción de un lugar y mediante comandos sencillos con estructura verbo-objeto (por ejemplo, "go west","open door","go down", etc.), el jugador participa activamente en un mundo ficticio y controla el desenlace de una narrativa no lineal. Zork se hizo muy popular a principios de la década de los 80 con las primeras computadoras personales, aunque ciertamente, no fue el primer juego de su tipo- esta distinción le corresponde a Colossal Cave Adventure, un juego de aventura de texto desarrollado en FORTRAN para computadoras mainframe a mediados de los años 70. Si quiere tener una idea de cómo eran estos juegos, puede jugar Zork en su navegador Web accediendo a la siguiente dirección: http://thcnet.net/zork/.

Desde el punto de vista de la programación, hacer un juego como Zork es algo un tanto complejo para abordar la eseñanza de la programación en Python para principiantes. Quizás emprenda un juego de aventura en una entrada futura de este blog. Por los momentos, tengo en mente implementar una versión más sencilla de estos juegos, basada en los libros de ficción interactiva tipo "Elige tu Propia Aventura" ("Choose Your Own Adventure"). Estos libros también se hicieron muy famosos a principios de la década de los 80's y forman parte de los recuerdos nostálgicos de las personas de mi generación. La serie original "Choose Your Own Adventure" consiste en 185 titulos publicados desde 1979 hasta 1998. El primero de estos titulos fue "La Cueva del Tiempo" (The Cave of Time), ecrito por Edward Packard y magnificamente ilustrado (ver las ilustraciones en este post) por Paul Granger (seudónimo de Don Hedin). Este es el libro que vamos a versionar en Python en esta oportunidad.

Los libros de este genero de "ficción interactiva" utilizan el medio impreso (el libro, cuya invención se remonta a los albores de la Historia) de una forma bastante novedosa e inusitada. Uno no lee estos libros de forma lineal, desde la primera página hasta la última en orden consecutivo. Más bien, al iniciar su lectura, pronto se le presenta al lector una decisión, un punto de bifurcación en la narrativa. Entonces, según la decisión que toma el lector, debe saltar a la página correspondiente que se señala en el texto. De esta forma, el lector va saltando de página en página hasta que llega al final del hilo de la narrativa. "La Cueva del Tiempo", por ejemplo, tiene 40 finales o hilos de narrativa contenidos en las 115 páginas que conforman el libro. Décadas antes de los libros de Harry Potter, no se imaginan lo entretenido que resultaba la lectura de estos libros para los chamos de mi generación y es por ello que quise presentarles como tributo una versión de este libro desarrollada como video juego en Python.


En la gráfica anterior se muestra un texto característico de estos libros. En la página 6 se describe, mediante una narrativa en segunda persona, la situación en la cual estás y en la parte inferior de esa página te indican las opciones. Según aceptes o rechaces la invitación al castillo del Rey, debes saltar a la página 22 o a la 114, respectivamente. ¿Cómo se implementaria esto en código Python? Una primera aproximación a este problema sería implementar una serie de condicionales (if's) anidados. Por ejemplo:

print "Estás en un cuarto con tres puertas numeradas 1,2 y 3. ¿Qué quieres hacer?"
print "Escoge una de las siguientes opciones:"
print "'1' para abrir la puerta número 1"
print "'2' para abrir la puerta número 2"
print "'3' para abrir la puerta número 3"
print "'4' si deseas esperar y no abrir ninguna puerta"
seleccion=raw_input(": ")
while not(seleccion in ['1','2','3','4']):
    print "Selección no válida. Vuelva a escoger."
    seleccion=raw_input(": ")
if seleccion=='1':
    print "Abres la puerta 1 lentamente. Al pasar por el umbral de la puerta,"
    print "descubres que has entrado en el Infierno. FIN"
elif seleccion=='2':
    print "La puerta 2 conduce a un pasadizo al cabo del cual sales del"
    print "calabozo. !Eres libre! FIN"
elif seleccion=='3':
    print "Entras en una sala en el medio del cual hay un cofre de tesoro."
    print "Hay otras tres puertas aqui. Agarras el cofre del tesoro y"
    print "eliges ir por una de esas puertas..."
    :
    :
    :
elif seleccion=='4':
    print "Te mueres de hambre esperando. Para tí, es el ... FIN"

En el código anterior, los puntos suspensivos verticales (:) al cabo del último print en la selección '3' denotan código adicional en el cual se le da al jugador a escoger más opciones que a su vez van desencadenando en otros desenlaces. Es decir, dentro de esta parte del código se anidarían otros condicionales y dentro de estos condicionales se anidarían otros y así hasta agotar el hilo narrativo. Imagínense lo complicado que puede resultar esta estrategia de codificación para estos libros de ficción interactiva. Otro inconveniente de esta estrategia es que no puedes implementar bucles en la narración - imagínense por ejemplo al abrir la puerta 3, y luego de varias decisiones tomadas, vuelves al mismo punto de partida en el cual se te dan a escoger entre abrir 3 puertas o esperar y no abrir ninguna. Esto nos obliga a considerar utilizar alguna estructura de datos que nos permita navegar por esta especie de arbol en el cual los nodos son las descripciones narrativas y los arcos a otros nodos son las posibles opciones que tenemos en cada punto. Permítanme entonces hablarles de los diccionarios en Python ...

Los diccionarios son un tipo de estructura de datos que aún no he abordado en este blog. Un diccionario es parecido a una lista en el sentido en que consiste de una secuencia de elementos. Sin embargo, a diferencia de las listas, los elementos de un diccionario se pueden acceder haciendo referencia a un campo clave. Piensa por ejemplo en una libreta de direcciones:

libreta = {'Pedro' : 'pedroperez@hotmail.com', 'Diablodado' : 'diablodado@enanosiniestro.com', 'Nicolas' : 'maduro@burrosoy.gob.ve'}

de modo que si se quiere consultar el correo de Nicolas, escribiríamos libreta['Nicolas'] . El objeto 'libreta' definido arriba es en efecto un diccionario de Python. Nótese el uso de corchetes ( {} ) y las secuencias de claves : valores. La sintaxis general para definir un diccionario es:

mi_diccionario = { clave1 : valor1, clave2 : valor2, clave3 : valor3, ... }

Las claves pueden ser cadenas o números (generalmente son cadenas). Los valores pueden ser de cualquier tipo de datos en Python: cadenas, números, listas, tuplas o inclusive otros diccionarios. Para borrar un elemento del diccionario, utilizamos la instrucción "del". Así por ejemplo, para borrar a 'Nicolas' de nuestra libreta (ojalá fuese tan fácil), escribiríamos:

del libreta['Nicolas']

Si queremos agregar un elemento nuevo a 'libreta', basta con hacer una asignación como esta:

libreta['Maricori']='maricori@cia.gov'

Podemos verificar si tenemos a un elemento específico en nuestro diccionario:

'Diosdado' in libreta

Lo cual retornaría False, pues 'Diosdado' no está en nuestra libreta (quien está es 'Diablodado'). Ahora volviendo al asunto que nos ocupa, que es el de hacer un juego tipo "elige tu aventura". Debido a que estoy creando una versión en Python de un libro impreso y que dentro del libro, las opciones hacen referencia a otros números de páginas, creí conveniente representar esta estructura de hipertexto como un diccionario, en el cual las claves son los números de página (datos tipo cadena y no numérico). Estas opciones (los valores en el diccionario) las defino como una lista de tuplas, en la cual cada tupla consiste de dos valores: la cadena a imprimir para esa decisión y el número de página (como cadena) hacia el cual el lector se dirige en caso de tomar esa decisión. Cuando en una página no hay opciones sino que el texto indica ir a la siguiente página, escribo la palabra 'Siguiente' como el primer elemento de una tupla en la lista de decisiones para esa página. Cuando el hilo narrativo termina en una página, la lista de decisiones consta de una sola tupla: ('FIN','0'). De este modo, el programa esperará a que el usuario presione ENTER y volverá a comenzar en la página '0', que es la portada del libro. Para darles una idea de cómo funciona todo, reproduzco parte del código donde se define la estructura del libro (con puntos suspensivos verticales entre el renglón de '4' y '111' para indicar que hay más código):

libro={
'0' : [('Siguiente','1')], 
'1' : [('Siguiente','2')],
'2' : [('Siguiente','3')], 
'3' : [('Si decides volver a casa, pasa a la página 4.','4'), \
('Si decides esperar, pasa a la página 5.','5')], 
'4' : [('Si sigues hacía el rancho, pasa a la página 8.','8'), \
('Si vuelves a entrar en la cueva, pasa a la pagina 10.','10')], 
:
:
'111' : [('Siguiente','112')],
'112' : [('FIN','0')],
'113' : [('FIN','0')],
'114' : [('Siguiente','61')],
'115' : [('FIN','0')] \
}

Quizás se pregunte porque no hay texto en cada página. La respuesta es que el texto de cada página se encuentra en su respectivo archivo de texto: '0.txt' , '1.txt', '2.txt', etc. El hecho que el nombre de cada archivo sea el número de página seguido de la extensión '.txt' facilita las cosas, pues los números de clave son las páginas dentro del diccionario 'libro'. El bucle principal consiste en visualizar la página, imprimir cada una de las opciones en "libro" para esa página ('Siguiente' y 'FIN' son casos especiales), solicitar la opción al jugador mediante raw_input, y dirigirse a la nueva página. Para comenzar a jugar el juego "La Cueva del Tiempo" y comenzar a ver cómo se implementa en Python, puede descargar la carpeta comprimida con el código fuente en "libro.py" y los archivos de texto en este enlace. A continuación una captura de pantalla del juego:


Puede observar que el texto de algunas páginas contiene "gráficos" en ASCII. Opté por incorporar las ilustraciones originales de Paul Granger como arte ASCII junto con el texto, y no como gráficos, para mantener el juego completamente en modo texto y darle un toque "retro" al programa. Para visualizar correctamente el juego, debe configurar su terminal con una fuente de espaciado uniforme (tipo "Courier" o "monospace" por ejemplo), con un tamaño lo suficientemente pequeño como para que quepan 128 caracteres por línea. También debe colocar el color de fondo de la pantalla en blanco, con el texto en negro (ver captura de pantalla arriba).



Permítanme darles unos tips sobre cómo crear arte ASCII. Cada ilustración, en forma de archivo PNG o JPEG, se puede convertir a texto ASCII mediante la opción "Exportar" de GIMP (un software libre para el manejo de archivos gráficos muy bueno). Así por ejemplo: Para cada imagen, primero invertí los colores mediante "Invertir Colores" en el menú correspondiente, luego reduje cada imagen a 120 pixeles de ancho por la cantidad proporcional de pixeles de alto y finalmente reduje el tamaño vertical a un poco menos de la mitad sin reducir el tamaño horizontal, lo cual me daba imágenes aplastadas que se visualizaban correctamente cuando las exportaba a texto ASCII. Para crear las letras grandes, utilicé un programa de línea de comandos en Linux llamado "figlet". Así por ejemplo:

figlet Bibliografia

 ____  _ _     _ _                        __ _      
| __ )(_) |__ | (_) ___   __ _ _ __ __ _ / _(_) __ _
|  _ \| | '_ \| | |/ _ \ / _` | '__/ _` | |_| |/ _` |
| |_) | | |_) | | | (_) | (_| | | | (_| |  _| | (_| |
|____/|_|_.__/|_|_|\___/ \__, |_|  \__,_|_| |_|\__,_|
                         |___/             
         


  • Packard, E. (1983). La Cueva del Tiempo. Editorial TIMUN MAS, S.A., Barcelona.
  • Swinehart, C. (2013). One Book. Many Readings. Disponible en: http://samizdat.cc/cyoa
  • Choose Your Own Adventure. (2014, February 19). En Wikipedia, The Free Encyclopedia. Disponible en: http://en.wikipedia.org/w/index.php?title=Choose_Your_Own_Adventure.
  • Choose Your Own Pyventure. (2013, October 19). Wikibooks, The Free Textbook Project. Disponible en: http://en.wikibooks.org/w/index.php?title=Choose_Your_Own_Pyventure.
  • List of Choose Your Own Adventure books. (2013, December 13). En Wikipedia, The Free Encyclopedia. Disponible en: http://en.wikipedia.org/w/index.php?title=List_of_Choose_Your_Own_Adventure_books

jueves, 6 de febrero de 2014

Juegos de texto sencillos: las torres de Hanoi

He desarrollado una versión en modo texto del juego de las torres de Hanoi, que consiste en mover discos de distintos tamaños desde una torre a otra.  La ventaja de desarrollar juegos en modo texto cuando e está aprendiendo a programar es que se utilizan sólo las instrucciones básicas como print y raw_input (Python 2.*) que se enseñan en las primeras lecciones. Utilizar gráficos y no texto supone el manejo de herramientas y librerías que son algo más complicadas para un novato (por ejemplo, PyGame).  Fuera de las razones pedagógicas para comenzar a enseñar la creación de video juegos a novatos usando como ejemplos de clase juegos de texto, están las razones "nostálgicas"- cuando yo aprendí a programar en BASIC, los primeros video juegos que uno hacia eran juegos en modo texto. Creo que aún hay mucho por explotar en cuanto a las herramientas de manejo de texto en lo que respecta a sus potencialidades para crear video juegos. En esta y en sucesivas entradas trataré de publicar video juegos en modo texto que puedan ser utilizados para las primeras lecciones de un curso de programación en Python.

El juego que les presento a continuación tiene todos los elementos de un video juego más complejo:. Hay un "mundo", que en este caso es la posición que ocupan los tres discos de distintos tamaños. Como programador, uno tiene que vérselas con el problema de encontrar la representación más adecuada (en términos de estructuras de datos) para el "mundo". Para este programa, yo escogí representar al mundo como una matriz de 4 filas y 3 columnas. Las columnas son las torres y en cada torre hay espacio hasta para 4 discos montados uno sobre otro. Como en este juego solo hay 3 discos, el último espacio de cada torre siempre estará vacio. En esta matriz, he escogido representar el lugar vacio como "0", y los discos de distintos tamaños como los números 1,2 y 3 (el 1 es el disco más pequeño y el 3 el más grande). La matriz en sí se representa en Python como una lista de listas (ver código).



Otro elemento importante de un video juego es visualizar el mundo en la pantalla, para que el jugador lo pueda ver.  En este caso yo imprimo las 3 torres y los discos mediante instrucciones print (ver las funciones dibuja_celda y dibujar_torres en el código fuente).  Y también está presente el solicitar al jugador cuál será su jugada en cada turno. Se verifica si esa jugada es válida y se realiza la jugada, lo cual cambia la posición de los discos. Este ciclo se repite hasta que el usuario haya puesto todos los discos en la posición final requerida.

A continuación el código:


# -*- coding: utf-8 -*-
#juego de las TORRES DE HANOI
#Autor: José Romero, 29/1/2014 a las 11:50pm

def dibuja_celda(disco):
 if disco==0:
  print "     |     ",
 elif disco==1:
  print "    OOO    ",
 elif disco==2:
  print "   OOOOO   ",
 elif disco==3:
  print "  OOOOOOO  ",

def dibujar_torres():
#esta función dibuja las torres (mundo)
 #primero, borra la pantalla introduciendo varias líneas en blanco
 print "\n"*40
 #luego, dibuja el "mundo"
 for fila in mundo:
  for columna in fila:
   dibuja_celda(columna)
  print
 print "************"*3
 print "     1     ","     2     ","     3     "

def encuentra_disco_de_arriba(col):
#esta función retorna el disco (1-3) en la columna indicada.
#si la columna está vacia, retorna un 0
 fila=0
 while fila<=3 and mundo[fila][col]==0:
  fila+=1
 if fila<=3:
  return mundo[fila][col]
 else:
  return 0

def encuentra_proximo_espacio_en_blanco(col):
#esta función indica el número de la fila (1-3) del lugar vacio
#en la columna debajo del cual hay un disco
 fila=0
 while fila<=3 and mundo[fila][col]==0:
  fila+=1
 return fila-1

def elimina_disco_superior(col):
#Esta función quita el disco superior en una columna
 fila=0
 while fila<=3 and mundo[fila][col]==0:
  fila+=1
 mundo[fila][col]=0


def verifica_si_termino():
#verifca si los discos estan todos en su posición final
 return mundo==objetivo

mundo = [[0,0,0],[1,0,0],[2,0,0],[3,0,0]]
objetivo = [[0,0,0],[0,0,1],[0,0,2],[0,0,3]]

movimientos=0
while not(verifica_si_termino()):
 #dibuja el mundo en la pantalla
 dibujar_torres()
 #solicita la jugada 
 c0=raw_input("Mover disco desde la torre # : ")
 c0=int(c0)-1
 c1=raw_input("Mover disco a la torre #     : ")
 c1=int(c1)-1
 #validar la jugada
 hayerror=False
 if (c0<0 data-blogger-escaped-c0="" data-blogger-escaped-or="">2):
  print "Torre 'desde' inválida"
  hayerror=True
 elif (c1<0 data-blogger-escaped-c1="" data-blogger-escaped-or="">2):
  print "Torre 'hasta' inválida"
  hayerror=True
 elif encuentra_disco_de_arriba(c0)==0:
  print "No hay discos en la torre #",c0+1
  hayerror=True
 elif encuentra_disco_de_arriba(c1)>0 and encuentra_disco_de_arriba(c0)>encuentra_disco_de_arriba(c1):
  print "Intenta colocar un disco más grande sobre uno más pequeño"
  hayerror=True
 #Si la jugada es válida, efectuar la jugada
 if not(hayerror):
  disco1=encuentra_disco_de_arriba(c0)
  elimina_disco_superior(c0)
  mundo[encuentra_proximo_espacio_en_blanco(c1)][c1]=disco1
  movimientos+=1
 else:
  raw_input("Preione [ENTER] para continuar")

dibujar_torres()
print "Felicitaciones! Ha terminado en",movimientos,"movimientos."


¡Disfruten!

jueves, 27 de junio de 2013

Resolución de problemas con restricciones: el acertijo de Einstein

En esta entrada del blog nos proponemos resolver un acertijo atribuido a Alfred Einstein, quien afirmaba que 98% de la población mundial no sería capaz de resolverlo.  El acertijo reza así:

Tenemos 5 casas de cinco colores diferentes y en cada una de ellas vive una persona de una nacionalidad diferente. Cada uno de los dueños bebe una bebida diferente, fuma una marca de cigarrillos diferente y tiene una mascota diferente.

Tenemos las siguientes condiciones:

  • El británico vive en la casa roja.
  • El sueco tiene un perro.
  • El danés toma té.
  • La casa verde esta a la izquierda de la blanca.
  • El dueño de la casa verde toma café.
  • La persona que fuma Pall Mall tiene un pájaro.
  • El dueño de la casa amarilla fuma Dunhill.
  • El que vive en la casa del centro toma leche.
  • El noruego vive en la primera casa.
  • La persona que fuma Blends vive junto a la que tiene un gato.
  • La persona que tiene un caballo vive junto a la que fuma Dunhill.
  • El que fuma Bluemasters bebe cerveza.
  • El alemán fuma prince.
  • El noruego vive junto a la casa azul.
  • El que fuma Blends tiene un vecino que toma agua.

Y por ultimo la pregunta:

¿Quién es el dueño del pez?
Podemos abordar este problema planteando un sistema de 25 variables (los 5 colores de casa, las 5 nacionalidades, las 5 bebidas, etc.).  Cada variable asume un valor entero entre 1 y 5, indicando el número de casa con ese color, ocupante de determinada nacionalidad, etc.  Si no hay restricciones, se tienen 5^25=2,980232239×10¹⁷ soluciones posibles.  Bajo las condiciones según las cuales cada casa tiene un ocupante de nacionalidad distinta, con un color distinto, que toma una bebida distinta, con una mascota distinta y que fuma una marca de cigarrillo distinta se reduce el universo de posibles soluciones a (5!)^5=24.883.200.000, lo cual sigue siendo un tamaño de espacio de búsqueda considerable.  El resto de las restricciones presuntamente reducen el universo de posibles soluciones a una única solución. Se trata pues de un problema de búsqueda combinatoria.

Solución del acertijo de Einstein en Python


En mis intentos por resolver esto "a mano" y a fuerza de lógica, me preguntaba si sería posible escribir un programa para resolver esto de forma automática, mediante el computador.  Me acordé del lenguaje Prolog, el cual está específicamente diseñado para realizar cómputos con símbolos y relaciones entre símbolos. Sin embargo, pensaba que sin duda sería posible realizar este trabajo en Python.  Fue así como me enteré de un módulo llamado "constraints" para resolver problemas con restricciones en Python.  Seguidamente les expongo el código fuente del script que resuelve el acertijo de Einstein:

from constraint import *

acertijo = Problem()

#Funciones relacionales

def a_la_izquierda_de(a,b):
    return a < b
def a_la_derecha_de(a,b):
    return not left_of(a,b)
def vecino_de(a,b):
    return abs(a - b) == 1

#Variables

color = ["blanca","roja","verde","amarilla","azul"]
nacionalidad = ["Danes","Sueco","Britanico","Noruego","Aleman"]
bebida = ["te","cafe","cerveza","agua","leche"]
fuma = ["Dunhill","Pall_mall","Bluemaster","Blends","Prince"]
mascota = ["caballo","pez","pajaro","perro","gato"]
variables = color+nacionalidad+bebida+fuma+mascota
#Dominio de las variables
casa = [1,2,3,4,5]
#Agregar las variables al objeto "acertijo"
acertijo.addVariables(variables, casa)

#Cada vecino tiene casas de colores distintos, toma una bebida distinta,
#fuma una marca de cirgarrillo distinto, tiene mascotas diferentes y
#es de nacionalidad distinta.

for i in (color, nacionalidad, bebida, fuma, mascota):
    acertijo.addConstraint(AllDifferentConstraint(),i)
#El britanico vive en la casa roja
acertijo.addConstraint(lambda Britanico, roja: Britanico == roja,\
    ("Britanico", "roja"))
#El sueco tiene el perro
acertijo.addConstraint(lambda Sueco, perro: Sueco == perro,\
    ("Sueco", "perro"))
#El danés bebe té
acertijo.addConstraint(lambda Danes, te: Danes == te, ("Danes", "te"))
#La casa verde está a la izquierda de la casa blanca
acertijo.addConstraint(lambda verde, blanca: vecino_de(verde, blanca) \
    and a_la_izquierda_de(verde, blanca),("verde", "blanca"))
#El dueño de la casa verde toma café
acertijo.addConstraint(lambda verde, cafe: verde == cafe, \
    ("verde", "cafe"))
#La persona que fuma Pall Mall tiene un pájaro
acertijo.addConstraint(lambda Pall_mall, pajaro: Pall_mall == pajaro, \
    ("Pall_mall", "pajaro"))
#El dueño de la casa amarilla fuma Dunhill                  
acertijo.addConstraint(lambda amarillo, Dunhill: amarillo == Dunhill, \
    ("amarilla", "Dunhill"))
#El de la casa del centro (casa N° 3) toma leche
acertijo.addConstraint(InSetConstraint([3]), ["leche"])
#El Noruego vive en la primera casa
acertijo.addConstraint(InSetConstraint([1]), ["Noruego"])
#La persona que fuma Blends vive junto a la que tiene un gato
acertijo.addConstraint(lambda Blends, gato: vecino_de(Blends, gato),\
    ("Blends", "gato"))
#La persona que tiene un caballo vive junto a la que fuma Dunhill
acertijo.addConstraint(lambda caballo, Dunhill: \
    vecino_de(caballo, Dunhill), ("caballo", "Dunhill"))
#El que fuma Bluemasters bebe cerveza
acertijo.addConstraint(lambda Bluemaster, cerveza: \
    Bluemaster == cerveza, ("Bluemaster", "cerveza"))
#El Aleman fuma Prince
acertijo.addConstraint(lambda Aleman, Prince: Aleman == Prince, \
    ("Aleman","Prince"))
#EL Noruego vive junto a la casa azul
acertijo.addConstraint(lambda Noruego, azul: \
    vecino_de(Noruego, azul), ("Noruego", "azul"))
#El que fuma Blends tiene un vecino que toma agua
acertijo.addConstraint(lambda Blends, agua: \
    vecino_de(Blends, agua), ("Blends", "agua"))

#La respuesta
respuesta = acertijo.getSolution()
print respuesta

#Imprime la solución de una forma más legible
ver_respuesta = {}
for i in casa:
    ver_respuesta[i] = {}

for k,v in respuesta.items():
    if k in color:
        tmp = k
        if k.__len__()<7:
            tmp=tmp+"\t"
        ver_respuesta[v]['color'] = tmp
    elif k in nacionalidad:
        tmp = k
        if k.__len__()<8:
            tmp=tmp+"\t"
        ver_respuesta[v]['nacionalidad'] = tmp
    elif k in bebida:
        ver_respuesta[v]['bebida'] = k
    elif k in fuma:
        tmp = k
        if k.__len__()<9:
            tmp=tmp+"\t"
        ver_respuesta[v]['fuma'] = tmp
    elif k in mascota:
        ver_respuesta[v]['mascota'] = k


print "Respuesta:\n"
print "Casa\tColor\t\tNacionalidad\tBebida\t\tFuma\t\tMascota"
print "="*80
for i in casa:
    print str(i)+"\t"+ver_respuesta[i]['color']+"\t"+\
        ver_respuesta[i]['nacionalidad']+"\t"+ \
        ver_respuesta[i]['bebida']+"\t\t"+ver_respuesta[i]['fuma']+"\t"+\
        ver_respuesta[i]['mascota']


El script produce la solución al acertijo, como se manifiesta en su salida:

{'amarilla': 1, 'Noruego': 1, 'Dunhill': 1, 'Sueco': 5, 'agua': 1, 'Britanico': 3, 'azul': 2, 'verde': 4, 'Bluemaster': 5, 'cerveza': 5, 'leche': 3, 'cafe': 4, 'Pall_mall': 3, 'caballo': 2, 'roja': 3, 'blanca': 5, 'Danes': 2, 'pajaro': 3, 'pez': 4, 'Aleman': 4, 'gato': 1, 'perro': 5, 'te': 2, 'Prince': 4, 'Blends': 2}


Respuesta:

Casa    Color       Nacionalidad    Bebida        Fuma            Mascota
================================================================================
1       amarilla    Noruego         agua          Dunhill         gato
2       azul        Danes           te            Blends          caballo
3       roja        Britanico       leche         Pall_mall       pajaro
4       verde       Aleman          cafe          Prince          pez
5       blanca      Sueco           cerveza       Bluemaster      perro


Donde se puede ver que el alemán, quien vive en una casa verde, toma café y fuma cigarrillos de marca "Prince", es quien tiene al pez como mascota.  Ahora que tengo su atención, permítanme comentarles algo sobre este super-genial módulo de Python.


Primeramente, para su instalación deben descargar el archivo .tar, descomprimirlo y ejecutar el script de setup, para lo cual debe ejecutar lo siguiente en la consola de Linux:

wget http://labix.org/download/python-constraint/python-constraint-1.1.tar.bz2
bzip2 -cd python-constraint-1.1.tar.bz2 | tar xvf -
cd python-constraint-1.1
python setup.py install


Como se puede ver en el script de arriba, este módulo trabaja con una clase llamada "Problem" (problema), que contiene una definición de las variables del problema (en este caso, 25 variables), junto con el dominio (conjunto finito de valores posibles) para cada variable y las restricciones, que se agregan mediante el método addConstraint.  Existen algunas restricciones de uso común definidas en el módulo (consulte la documentación en http://labix.org/doc/constraint/).  Las restricciones del problema también se pueden definir mediante expresiones de cálculo lambda, tal como se especifican en la mayoría de las restricciones del acertijo.

El método getSolution() devuelve un diccionario en el cual las claves son las variables y estan apuntan al número de la casa (1 al 5) asociada a esta variable.  De esta forma, a cada casa se le asocia un color, una nacionalidad del ocupante, una bebida, una marca de cigarrillo y una mascota diferente.  Sin embargo, el diccionario que se devuelve no permite visualizar esto fácilmente, por lo cual seguidamente se recorre para organizar la información por número de casa.  Si un problema tiene más de una solución, el método getSolutions() (con s al final por el plural de soluciones) devuelve una lista de diccionarios, en donde cada diccionario es una de las posibles soluciones.


Posibles aplicaciones del módulo constraints

Si lo examinamos bien, este problema es muy parecido al problema de resolver un Sudoku.  En Sudoku también existen restricciones con respecto a la forma de rellenar cada casilla con un dígito del 1 al 9.  No se pueden repetir dígitos en una fila, columna o subcuadro.  Como reto les planteo escribir un script en Python (usando el módulo constraints)  que resuelva crucigramas de Sudoku.

Si se nos presenta un problema en la vida real en el cual se manejan elementos finitos (discretos) (unidades de transporte, manejo de personal, etc.) que se deben distribuir o alocar de una manera óptima, este módulo podría sernos de utilidad.  Otra posible aplicación de este módulo es en los problemas de programación entera.







martes, 23 de abril de 2013

Un video-juego que quiero que vean - Defensor

Un estudiante de la primera edición del curso de programación en Python que dictaba en la UNEFA, José Tayupo, me hizo llegar un juego que recién elaboró.  Se llama "Defensor" y está inspirado en dos video juegos clásicos: Space Invaders y Galaga. 


El juego consta de 11 niveles. Al final, tendrán que vérselas con el jefe de los malos- muaaajjaaaaa.  Necesitan la librería Pygame para poderlo correr.

José Tayupo hizo la programación y los gráficos. El y su hermano Moises Cegerra trabajaron conjuntamente en el diseño del juego. Tayupo me dice que es posible que el juego tenga algunos bugs todavía, de modo que si alǵun lector encuentra uno le agradecemos nos lo haga saber a través de los comentarios en esta página.

Enlace para descarga de la carpeta comprimida del juego aqui.

martes, 11 de septiembre de 2012

Halzo tu mism@ en Python


La ubicuidad de la tecnología de la información y los niveles en los que su uso ha permeado nuestra cotidianidad - telefonos celulares, correo electrónico, realización de tramites por Internet, blogs, Facebook, Twitter, etc. - hacen necesario que el ciudadano común aprenda ciertos conocimientos básicos sobre su utilización.  De hecho, estos conocimientos son tan importantes como la lectura, la escritura y la aritmética para poder desenvolverse en una sociedad moderna; quien carece de ellos es en cierta forma un analfabeta.  ¿Es adecuada la educación en tecnologías de información que se imparte en las escuelas e inclusive en la universidad? ¿Es necesario "profundizar" sobre estos conocimientos y aprender a programar, por ejemplo? En tal caso, ¿porqué debería enseñarse un lenguaje de programación como Python? ¿Es la programación una actividad solo para especialistas y profesionales en el área informática? ¿Qué ganaría una persona común con aprender a programar (en Python)? Estas son las interrogantes que abordaré en este ensayo, pero vamos a empezar por enmarcar este tema desde una perspectiva histórica y algo nostálgica.


Hace poco menos de 40 años, en 1975, salió al mercado la primera computadora personal, la Altair (Fig. 1.a.), con 1024 bytes de memoria y un procesador Intel 8008.  Hasta ese entonces, las computadoras eran unas máquinas misteriosas solamente asequibles para las grandes corporaciones o instituciones del gobierno.  Hasta ese entonces, nadie pensaba que un ciudadano común pudiese tener algo así como una computadora personal.  A decir verdad, la Altair todavía distaba mucho de ser una computadora "amigable" que podía ser manejada por una ama de casa o uin niño.  Los primeros usuarios eran entusiastas de la electrónica que habían tenido cierta exposición a las computadoras grandes (los mainframes) y que deseaban experimentar con una computadora en casa.  Programar la Altair era un proceso complicado: a través del panel frontal, el usuario cargaba código máquina directamente en determinadas posiciones de la memoria mediante suiches.  Por toda salida de estos programas, la computadora prendia ciertos LEDs en el panel frontal (Fig. 1.b).  Muy pronto se desarrollarían interfaces para conectar la máquina a un terminal de teletipo, con teclado y pantalla, así como también dispositivos de almacenamiento secundario.  Los fabricantes de la Altair recibieron ese mismo año una propuesta para crear un interprete de lenguaje BASIC para la máquina.  La propuesta venía de Paul Allen y Bill Gates, quienes eventualmente fundarían una compañía llamada Microsoft (entonces era Micro-soft).


Fig 1.a. La Altair












Fig 1.b. Panel frontal de la Altair

Con la Altair llegó la Era de la Computadora Personal.  Seguidamente, en 1977 Steve Wozniack y el recien fallecido Steve Jobs crearon una computadora, la Apple II (Fig. 2.a), cuyo debut en el mercado fue muy exitoso.  La Apple II, con un microprocesador MOS 6052, tenía un interprete BASIC incorporado en la memoria ROM, un teclado, 4096 bytes de memoria RAM y se podia acoplar a un televisor normal. Después de la Apple II surgieron muchos otros modelos de distintos fabricantes, todas eran computadoras orientadas al uso personal o del hogar, pero tenian algo en común- un interprete BASIC.


Fig 2.a. La Apple II

Fig 2.b. Atari 800 XL con casetera. La casetera era el dispositivo de almacenamiento secundario más común.

Cada una de estas máquinas tenía una ámplia selección de software disponible: videjuegos, programas educativos, procesadores de palabra, aplicaciones para ayudar con el control de las finanzas del hogar, etc.  Sin embargo, a differencia de los dispositivos de hoy en día - los dispositivos móviles y sus Apps, las cónsolas de videojuegos, minis, eReaders - aquellas computadoras estaban especificamente diseñadas para que los usuarios creasen sus propias aplicaciones en BASIC.  En la década de los 80's, la instrucción en computación que se impartía en las escuelas norteamericanas y europeas estaba orientada a enseñar programación (en lenguaje BASIC).  Es este sentido, es notable el proyecto de alfabetización computacional del gobierno británico, el cual era operado por la BBC y era basado en la BBC micro (Fig. 3.a. y 3.b.), una computadora basada en el microprocesador 6052 al igual que la Apple II. Desde su debut en 1981 en Gran Bretaña, la acogida de la BBC micro en las escuelas británicas como la "computadora educativa" fué total.  Inclusive se produjo una serie televisiva llamada "The Computer Programme" transmitida por la BBC que abarcaba topicos como programación, gráficos, sónido, teletexto, control de dispositivos de hardware externos e inteligencia artificial.


Fig 3.a. La BBC Micro


Fig 3.b. Pantalla de inicio de la BBC Micro: El intérprete BBC BASIC.

La historia de los primeros computadores personales la vivencié yo en los Estados Unidos, donde viví parte de mi infancia y mi adolescencia en la epoca de los 80.  Mi primera exposición al mundo de la programación fué a través de un cartucho para la consola de videojuegos Odyssey 2 llamado Computer Intro.  La lectura del manual que acompañaba este cartucho fué como una revelación para mi: hablaba de de una computadora hecha de engranajes diseñada por un tal Charles Babbage en el siglo XIX y la ENIAC, que ocupaba toda una sala con cables y tubos al vacio.  Contaba que los adelantos de la tecnología electrónica habían hecho posible que las computadoras estén en todas partes, cómo la cónsola Odyssey que tenía en mi sala.  Pero lo que más me llamó la atención fué cuando leí que las computadoras "hablaban" un lenguaje y que al aprenderlo, sería capáz de darle instrucciones a la máquina para que hiciera lo que yo quisiese.  ¡Imagínense! Esto era como el cuento de Aladino y el genio de la lámpara hecho realidad.  Inocentemente, yo me preguntaba si ese lenguaje que "hablaban" las computadoras sería como el inglés o el castellano...

Poco después, en el verano de ese mismo año (1983), me inscribí en un curso de vacaciones en mi escuela en donde aprendería a programar en un lenguaje llamado BASIC.  Cada niño tenía un computador de trabajo donde prácticabamos los comandos nuevos de BASIC que nos enseñaban diariamente.  Mis compañeritos y yo haciamos competencias para ver quien hacía el programa más impresionante: un cohete que despegaba y explotaba al otro lado de la pantalla, un juego de esquivar carros, etc. Sin saberlo, estaba aprendiendo sobre variables, funciones, coordenadas en el plano cartesiano, algoritmos, cómo resolver problemas descomponiendolos en sub-problemas más sencillos- en fín, todo lo que ahora denomiraría como "pensamiento computacional".  Sin duda, esto repercutió positivamente en otras áreas de mi formación intelectual, pero para mi en ese momento era sólo algo extremadamente divertido.  Era como un juego. Un hobby en el cual me "enganché" para siempre.

La programación era un hobby en el cual uno hacia las cosas uno mismo.  Se te ocurria una idea para un video juego o un programa que necesitabas para "automatizar" alguna tarea fastidiosa en la escuela (como por ejemplo para aprenderse de memoria nuevos vocablos en clase de Lenguaje) y lo hacias.  El único límite era tu propia creatividad.  Reflexionando en retrospectiva en torno a estas anecdotas, quisiera resaltar que: 1) Un niño podía aprender a programar y con ello desarrollar habilidades cognitivas asociadas al pensamiento computacional y matemático, como mi propia experiencia y la de centenares de miles de niños en esa epoca lo atestiguan, 2) programar era algo extremadamente divertido porque permitía desplegar la creatividad en proyectos significativos para quien aprendía (aprendizaje significativo), 3) a partir de un pequeño contenido impartido por un facilitador adulto, uno continuaba aprendiendo por su cuenta, altamente motivado por el deseo de llevar a cabo algún proyecto, como por ejemplo un video juego.  Esto es la esencia del aprendizaje constructivista, en el cual el deseo de "construir" algo motiva al estudiante a instruirse sobre el uso de las herramientas de construcción.  La computadora personal, a través del entorno de programación, es el material y la herramienta de construcción.

Existía en aquella época de los primeros computadores personales una cultura que favorecía el surgimiento de generaciones de niños programadores, a través de cursos de programación en las escuelas y revistas de computación con listados de programas que uno podía modificar a su antojo.  Sin embargo, esta era una cultura "underground", un movimiento cultural por y para jovenes programadores- "whiz-kids", "geeks" o "nerds", como les decian. En el afán de hacer estos aparatos cada vez más fáciles de usar y asequibles a la población en general, se desarrollaron sistemas operativos y aplicaciones con interfáces más amigables y gráficas.  Así surgieron las computadoras Macintosh y el sistema operativo Windows (que es una mala copia del MacOS).

Con este tipo de interfáz, el computador se hizo más fácil de utilizar para el usuario común.  Supongo que la idea era hacer el computador asequible para la abuelita, que sólo le interesaba usar el procesador de palabras sin tener que aprender esos "códigos complicados" de la programación.  En todo caso, las computadoras se hicieron más ubicuas pero a la vez, menos "personales".  Por una parte, para poder brindarle al usuario final todas esas ventanitas, todos esos íconos y los fastidiosos asistentes que aparecian cuando uno no los quería, los sistemas operativos se hicieron más complejos a la par del hardware, a tal punto que ya no era tan fácil para un niño desarrollar aplicaciones para ellos.  Por otro lado, ¿para qué se iba uno a tomar la molestia de aprender a programar si ya la gente de Microsoft y los de la Apple habían desarrollado aplicaciones con todas las funcionalidades que cualquier persona podría necesitar? Como resultado, cambió el enfoque en torno a la educación en tecnologías de información. Ya en las escuelas no se enseñaba programación, ahora se enseñaba como usar Microsoft Word, Excel, PowerPoint, Paint, ...

Se impuso una creencia según la cual programar es una actividad profesional para especialistas. Esta creencia ha permeado en varios ámbitos, en particular en el ámbito laboral.  En toda empresa o institución, existe un departamento de IT que se encarga de proveer y mantener las herramientas computacionales que requieran los demás departamentos.  En esta cultura de la especialización, no se espera que todo trabajador sea capáz de programar pero si se espera que el trabajador tenga ciertos conocimientos mínimos sobre el uso del computador.  Bajo este enfoque, los conocimientos sobre programación no son necesarios para poder usar el computador, de la misma manera que una persona puede aprender a manejar sin saber sobre mecánica automotriz, pero esta analogía es engañosa porque con un carro no realizamos nuestras comunicaciones, no manejamos nuestras cuentas bancarias, tramites gubernamentales y compras electrónicas.  Los carros no median nuestras relaciones sociales (Facebook, Twitter) ni cuentan los votos en un país (Smartmatic).  Un carro es solo una herramienta para desplazarse del punto A al punto B. Un computador es algo más.  El computador está intimamente ligado al proceso de la producción de ideas y de nuevos paradigmas sociales. El computador es una tecnología para producir tecnologías- es una tecnología madre por así decirlo.

Cási todas las herramientas tecnológicas que nosotros recibimos pasivamente ya vienen hechas, listas para ser usadas. El cuchillo con el que cortamos, el carro, la televisión- todos estos aparatos se pueden usar sin tener que hacerles modificaciones. Estos aparatos son interfaces que utilizamos para modificar nuestro entorno y puesto que ya vienen pre-determinados y no son modificables, se nos niega la posibilidad de desplegar nuestra creatividad para mejorar la forma en que operamos sobre nuestro entorno, según nuestros deseos y necesidades. Estamos tan acostumbrado a pensar así sobre los artefactos que usamos que nunca reparamos en el hecho que el computador es un artefacto de una naturaleza distinta: puede modificarse porque es programable.  Nunca reparamos en esto porque la cultura de las ventanitas (Windows) nos ha hecho ciegos a esta posibilidad. Hoy en día tenemos la web 2.0, en Facebook podemos comentar en el muro de un amigo, pero básicamente, estamos utilizando una interfáz creada por otros y son personas como Bill Gates, Steve Jobs y Mark Zuckerberg quienes en último termino deciden como debemos interactuar con nuestro mundo.

Esta visión Orwelliana del mundo dista mucho del futuro que como chamo me imaginaba que traería la revolución de las computadoras personales. Afortunadamente, existe una creciente cultura computista basada en el "hazlo tu mismo" como premisa fundamental.  Se llama Software Libre. La cara más visible de este movimiento de software libre es el sistema operativo Linux, en sus distintas versiones o distribuciones como se les denomina.  Incluido en toda versión de Linux hay un interprete de Python. Con el lenguaje Python se rescata la posibilidad de tener una plataforma sobre la cual crear nuestros propios programas o interfaces y volver a hacer de la computación una experiencia "personal" (o personalizable), como lo era antiguamente.

¿Es difícil aprender Python? Voy a responder esta pregunta de forma indirecta.  En el ambito de la programación, muy frecuentemente se hace referencia a los programas "Hola mundo".  Un programa "Hola Mundo" simplemente visualiza un mensaje de "Hola mundo!" en la pantalla.  Es algo así como el primer programa que hace uno cuando aprende a programar.  Para efectos de comparación, veamos un programa "hola mundo" en lenguaje ensamblador x86:

.model tiny
.code
org 100h

main  proc
      mov    ah,9                  
      mov    dx,offset mensaje_hola
      int    21h                   
      retn                         

mensaje_hola db 'Hola Mundo!$'

main  endp
end   main

A continuación el mismo programa pero en lenguaje C++:


#include <iostream>

int main()
{
    std::cout << "Hola Mundo!\n";
}

Y finalmente en Python (versión 2.x):

print "Hola mundo"

El lenguaje ensamblador es un lenguaje de muy bajo nivel (en el que la implementación de un programa está intimamente ligada a la arquitectura y el sistema operativo en el cual se va a ejecutar). Para empezar a explicar como funciona aquel programa "hola mundo" tendría que hablar sobre como en una máquina Von Neumann las celdas de memoria contienen datos y código, sobre como las instrucciones en el lenguaje ensamblador se corresponden a las instrucciones en lenguaje máquina mediante códigos hexadecimales, sobre los registros de un CPU, sobre la pila, el puntero de instrucción, las interrupciones...  Todo este conocimiento completamente inecesario para un usuario no especializado que quiere simplemente practicar el "hazlo tu mismo" en su computador.

El lenguaje C (y su variante C++) es un lenguaje de nivel intermedio (no tan ligado al hardware como el lenguaje ensamblador). De hecho, el lenguaje C es el lenguaje que se enseña en cási todas las universidades venezolanas. Esto a mi parecer es una política errada- yo personalmente no sabría justificar la enseñanza del lenguaje C a aquellos que nunca han programado.  Imagínense que en el primer día de clase el instructor coloca como ejemplo este programa "hola mundo".  Cualquier estudiante medianamente curioso preguntaría que hace la línea con el "#include" al principio.  Uno tendría que explicar que <iostream> es una librería de funciones encargadas de manejar la entrada/salida de la cónsola, que al ser incluidas junto al programa al momento de la compilación... Un docente responsable tendría que primero explicar que es un compilador y que significa eso de "código compilado".

Python es un lenguaje de muy alto nivel, porque el código en Python se parece más a las sentencias en lenguaje natural.  Una de las características más importantes de Python es que es dieñado para crear programas legibles por humanos.  Al ver un programa en Python, es fácil darse cuenta que es lo que hace.  Por ejemplo, el programa de "hola mundo" en Python simplemente imprime "Hola mundo!" en la pantalla (print significa imprimir en inglés).  Es algo muy intuitivo y fácil de entender para cualquier persona.  Por ser Python un lenguaje de muy alto nivel, es fácil crear aplicaciones rapidamente, aún cuando los programas no se ejecuten tán rápido como si fuesen hechos en lenguaje ensamblador.  Cómo los procesadores se han hecho tan rapidos y sin embargo el tiempo de un programador se ha hecho tan valioso (porque los programadores son un recurso cada vez más escaso), es fácil entender porqué el lenguaje Python forma parte de cualquier proyecto de Google.

Con Python es fácil crear aplicaciones para resolver problemas en el trabajo de manera ad hoc donde las herramientas comúnes de la ofimática no bastan.  Voy a ilustrar esto mediante un ejemplo de mi propia experiencia como docente de matemáticas en la Universidad Nacional Abierta.  En la UNA, existe un departamento en Nivel Central denominado SIUNA, que en conjunto con la Secretaría, mantiene todos los datos de control y registro de los estudiantes inscritos semestre tras semestre.  A mi como profesor me interesa tener un listado de los alumnos que yo asesoro en cada materia en las distintas sedes de la Universidad en el Centro Local de Anzoátegui, pero desafortunadamente, la aplicación del SIUNA no genera tal listado.  Lo que el sistema SIUNA si genera es un listado completo de todos los alumnos inscritos en el Centro Local de Anzoátegui con información sobre sus datos personales, la sede en donde están inscritos, y las materias que inscribió.  Es un listado largo de más de 30 páginas en formato PDF. A mi me interesaría extraer a partir de ese documento varias hojas de calculo, cada una con el listado de los alumnos que yo asesoro en mis materias y de las sedes que me corresponden.  ¿Cómo harían eso ustedes en Word, Excel, o Acrobat Reader?

Yo opte por escribir un pequeño script en Python que toma el archivo PDF y lo convierte a un archivo de texto plano, que a su vez es procesado varias veces para generar las hojas de cálculo con las nominas de alumnos que me toca asesorar en cada una de mis materias.  Con un poquito más de sofisticación, se que podría generar un solo libro Excel (Openoffice Calc, perdón) con varias hojas, una por materia y los formatos listos para vaciar los resultados de las evaluaciones académicas de cada estudiante.  De hecho, Python tiene montones de módulos, o librerias, que me permiten ampliar la funcionalidad del lenguaje para generar archivos de Excel, por ejemplo.  Piensen un poco sobre el trabajo tedioso que me ahorro cada semestre, si tuviese que generar esos listados a mano.  No solo ahorro mi tiempo, sino también el de mis colegas profesores de la sede a quienes, modificando mi script un poco, también les genero sus listados con solo apretar un botón.  La moraleja de esto es que eventualmente se presentará alguna ocasión en el trabajo para la cual las herramientas de computación son inadecuadas, debido a que los desarrolladores de esas herramientas no han podido preveer todos los requerimientos particulares de cada usuario.  Para estos casos, definitivamente es una ventaja saber programar en Python.  Y lo mejor es que uno puede "hacerlo uno mismo", sin tener que esperar a los especialistas de SIUNA (o del departamento IT de la empresa donde Ud. labora).

Es de pensar: ¿porqué las empresas no invierten en entrenar a su personal para que este pueda satisfacer sus requerimientos de informática en vez de desplegar un departamento de IT que de todas formas nunca tiene tiempo para satisfacer los requerimientos de los demás departamentos? Pero pensemos un poco más atrás en la cadena: ¿porqué no se hace esto desde las universidades? Y aún más atrás en la cadena: ¿porqué no comenzamos a hacer esto desde la educación primaria? 

En algunos paises desarrollados, hay quienes piensan que el los curricula de Tecnologías de Información necesitan revisión.  Un efecto visible de esto es que paradójicamente, cada vez hay menos egresados de la secundaria que prosiguen estudios de computación en la universidad y este problema de reclutamiento obviamente está comenzando a afectar a la industria. El gobierno británico ha tomado pasos orientados a "volver al futuro"- impartir nuevamente la enseñanza de las "ciencias de la computación" en la escuela primaria, lo cual sería una especie de relanzamiento del antiguo programa de las BBC micros.  Excepto que ahora la BBC micro sería este aparato, denominado "Raspberry Pi":


Fig. 4. Raspberry Pi.

La Raspberry Pi, con un costo de 35$, es un computador minimalista del tamaño de una tarjeta de crédito.  Incluye un procesador ARM, 2 puertos USB, un puerto ethernet, 256 MB de memoria RAM y por dispositivo de almacenamiento secundario utiliza una tarjeta micro SD con el sistema operativo ya grabado, que en este caso es el Debian squeeze (una distribución de Linux). Por cierto, no se les puede instalar Windows porque no hay ninguna versión compilada para el procesador ARM que usa la máquina. Adicionalmente, viene lista para trabajar en clase con el interprete de Python.  Python viene a ser para las nuevas generaciones de niños programadores lo que era el lenguaje BASIC de las viejas BBC micros.

La Raspberry Pi británica invita a una comparación con las Canaimitas que se le dan a los alumnos de primaria en Venezuela. Más que comparar las características de cada equipo de computación, lo cual sería completamente irrelevante para el tema de este artículo, lo que se pretende es comparar los proyectos educativos de los respectivos paises en materia de Tecnologías de Información. A partir del año 2011, ha comenzado en el seno del gobierno y la sociedad británica un intenso debate sobre la reforma del curriculum escolar en materia de las Tecnologías de Información.  Hasta ahora, dicho curriculum estaba orientado a lograr la "alfabetización digital", es decir, la habilidad para usar procesadores de palabras, hojas de cálculo y el internet de manera segura y efectiva.  Este enfoque orientado hacia entrenar usuarios/operadores de computadoras ha tenido como resultado la perdida de competitividad de Gran Bretaña como país productor de Tecnologías de Información.  En palabras de Eric Schmidt, presidente de Google, en una charla en la Universidad de Cambridge (2011):

"Me he quedado pasmado al enterarme que hoy en día, las ciencias computacionales no forman parte de los contenidos impartidos en las escuelas británicas.  Vuestro curriculum de TIC se enfoca en enseñar cómo usar software, pero no en cómo producirlo."

Hoy en día, la opinión según la cual las ciencias computacionales deben enseñarse como cualquier otra disciplina académica (matemáticas, lenguaje, historia, biología, etc.) está ganando terreno en Gran Bretaña. Entre otras cosas, las ciencias computacionales engloban la lógica, resolución de problemas y la capacidad de análisis y desarrollo del pensamiento riguroso y crítico, lo cual justifica su valor educativo y su inserción como parte del curriculum.  Aunque la tecnología de la computación cambia constantemente, los principios sobre los cuales se fundamenta permanecen invariables, por lo cual las ciencias computacionales son realmente una disciplina.  Por otro lado, es una disciplina de enorme importancia económica que repercute profundamente en todos los aspectos de la sociedad. Esta disciplina ha incursionado en otras, como la biología.  Por ejemplo, algunos biologos consideran las celulas como automotas programados por DNA, mientras otros utilizan modelos computacionales para entender la biodiversidad y la dinámica de las poblaciones de seres vivos.  Desde un enfoque basado en las ciencias computacionales se puede comprender mejor ciertos asuntos sociales como los sistemas modernos de comercio financiero y los sistemas de votación electrónicos.

El proyecto educativo Canaima por otra parte "tiene por objetivo general, promover la formación integral de los niños y niñas venezolanos(as) mediante el aprendizaje liberador y emancipador apoyado en las Tecnologías de Información Libres". Entre sus objetivos especificos resaltan los siguientes:

• Transformar la praxis docente con el uso humanista, crítico y creativo de las Tecnologías de Información Libres.

• Desarrollo de potencialidades en Tecnologías de Información Libres para el apoyo a los procesos educativos en pro de la soberanía y la independencia tecnológica.

El apoyo a los procesos educativos se operacionaliza mediante el desarrollo de contenidos multimedia ofrecidos como paquetes, según el grado escolar, a ser instalado en las Canaimitas, unas computadoras tipo mini con el Linux Canaima pre-instalado. Los contenidos multimedia versan sobre las distintas áreas del curriculum de la primaria en venezuela, a saber: lenguaje y comunicación, ciencias naturales, ciencias sociales e historia, cultura, actividad física, deporte y recreación.

El proyecto Educativo Canaima no contempla la enseñanza de las Ciencias Computacionales ni de las destrezas propias de esta disciplina. El rol de las Canaimitas es de servir de apoyo a la enseñanza, es decir, como un medio instruccional alternativo, no para apoderar a los estudiantes en la producción de su propia tecnología, con lo cual se está perdiendo un potencial interesante para lograr una verdadera soberanía e independencia tecnológica.  Se está perdiendo una oportunidad de enseñar a los niños venezolanos a "hacer las cosas uno mismo", que es la esencia de la filosofía del Software Libre. Es una verdadera pena, considerando que como todo sistema Linux, las Canaimitas también proveen un interprete Python.  Finalmente, quisiera cerrar estas notas con una cita de Simón Rodriguez, para que cada quien lea entre líneas:

            “Enseñen y tendrán quien sepa, eduquen y tendrán quien haga”.




Bibliografía

Attwood, J. (2012). "Please don't learn to code". Entrada de Blog "Coding Horror" de 15/05/2012. http://www.codinghorror.com/blog/2012/05/please-dont-learn-to-code.html.

Computing at School Working Group. (2012). "Computer Science as a school subject - Seizing the opportunity". [Documento en línea disponible en: http://www.computingatschool.org.uk].

Gobierno de la República Bolivariana de Venezuela. (2009). "Orientaciones Educativas- Canaima Educativo". [Documento en línea disponible en: http://www.slideshare.net/latingirl/orientaciones-canaimaeducativo].

Haggard, D. (2011). "Why Everyone Should Learn to Program". Reviews in Depth. [Documento en línea disponible en: http://reviewsindepth.com/2011/04/why-everyone-should-learn-to-program/].

Kirschenbaum, M. (2009). "Hello Worlds (why humanities students should learn to program)". Articulo en Chronicle Review, 23/01/2009. Disponible en http://chronicle.com/article/Hello-Worlds/5476.

Naughton, J. (2012). "Why all our kids should be taught how to code".  Guardian Weekly. [Documento en línea disponible en: http://www.guardian.co.uk/education/2012/mar/31/why-kids-should-be-taught-code].