09 abril 2011

Juego de la vida (2da parte: implementación)


Hecha la introducción sobre el juego de la vida de Conway en el post anterior, paso a contarles algunos detalles de implementación.
No voy a referirme al algoritmo: es el primero que me salió,  en cambio vamos a ver algunas cosas interesantes para aprender de JavaScript y HTML5.


Doctype 
La primer duda que me surgió a la hora de escribir el HTML5, es ¿Qué DOCTYPE uso?
Quienes recién comienzan con HTML quizás no entiendan esta duda, es una larga historia resumida de forma excelente en "Dive into Html 5": http://diveintohtml5.org/semantics.html#the-doctype .

En pocas palabras, el DOCTYPE que debe usarse en HTML5 es simplemente: <!DOCTYPE html >


Progressive Enhancement
Progressive enhancement es una técnica que consiste comenzar con el contenido, usando los tags de HTML para estructurarlo (títulos, párrafos, listas, etc) y luego ir agregando el diseño y "comportamiento" mediante CSS y JavaScript.

Pueden encontrar una buena introducción en este articulo.

Claro que en la pequeña aplicación JavaScript no hay contenido :), en fin el objetivo era aprender y practicar técnicas útiles para el desarrollo web.


CSS
Los stylesheets son sumamente engorrosos de mantener. Afortunadamente existen lenguajes de macros que permiten generar stylesheets usando constantes y funciones.
Uno de ellos es LESS, que lo elegí por dos razones: pueden usar JavaScript en el cliente para hacer pruebas y para aplicaciones Java cuentan con un servlet.
Otra alternativa para quienes usan Ruby es Sass.


Canvas y gráficos dinámicos
Para los gráficos comence usando un Canvas.
Lamentablemente el API de Canvas es en cierto sentido de "bajo" nivel: provee primitivas para dibujar directamente, pero carece de algunas abstracciones convenientes.
Luego de frustrarme (por alguna razón que no pude encontrar, los gradients en el stylesheet que uso modifican el estilo de dibujo del Canvas... algo muy engorrozo que me paso tanto Chrome como en Firefox) decidí buscar algun framework JavaScript que me facilite las cosas.
Entre los frameworks que estube mirando me encontré a gusto con raphaeljs.
No usa Canvas si no SVG (que al parecer no esta disponible en algunos browsers para smartphones).
Pero el API me pareció simple e ideal para hacer visualizaciones en HTML.


Local storage
Guardar y retornar información local en HTML5 es extremadamente fácil:

localStorage.setItem("key", "hello");
var value = localStorage.getItem("key");

Claro que este "map" es bastante rudimentario, hay otras opciones pero funcionan solo en ciertos browsers.
Aunque no lo use en este ejemplo, también pueden proveerle al browser información de que archivos mantener localmente para que la aplicación funcione offline.


Debugging y profilling
Con la ayuda de Diego Camera, conoci algunas herramientas de debugging y profiling de Google Chrome.
Tanto si usan Chrome o no, cuentan con la extensión FireBug que les agrega un API de consola extremadamente útil para hacer debugging y profiling (en Chrome no necesitan instalar una extensión para acceder a este API).

Para destacar: console.dir(object) les permite inspeccionar rápidamente el objeto pasado como parámetro.

Una cosa que me gusta de trabajar con estas herramientas es que me dio casi la misma sensación que en Smalltalk: uno puede inspeccionar y modificar en "entorno" en cualquier momento. Quizás en algún momento con proyectos como Ace (antes Mozilla Bespin/Skywriter) y  Eclipse Orion se llegue a lo que hacían los entornos de Smalltalk hace más de 20años ;-)

Para terminar....
Este post solo tiene algunas "puntas" a mirar para aprender más sobre JavaScript y HTML5.

Si están interesados en hacer algo para aprender, la implementación del juego de la vida que presente en el post anterior tiene muchas cosas pendientes, y con distintos niveles de complejidad:
  • Cada celda tiene su propio event handler, se podría usar un unico event handler para ahorrar recursos.
  • Las celdas se pintan haciendo click, lo cual es bastante incomodo si quieren pintar más de una celda. Se podrían cambiar los event handlers para permitirlo.
  • La función de "Save/Load" solo permite grabar una instancia, se podria modificar para soportar mas de una.
  • Seria útil poder insertar patrones de celdas predefinidos
  • Se puede cambiar la implementación para usar el tag canvas en lugar de raphaeljs
  • ... y si son unos "grosos" de los algoritmos, podrían simular que el "mundo" es infinito en lugar de hacer la simplificación que hice

05 marzo 2011

Juego de la vida (1ra parte)


Hace poco, conocí a través del libro "El gran diseño" de Stephen Hawking, el "juego de la vida" de Conway.

Este "juego" -entre comillas- me resultaba conocido, ya que en alguna vieja distribución de Linux, había visto algo similar. Pero hasta hace unos días no tenia ni la menor idea de que se trataba.

Pero basta de misterios, les cuento muy brevemente de que trata.

La idea es que uno tiene una gran grilla con celdas. Las celdas tienen una configuración inicial: vivas (activadas) o muertas (desactivadas). A partir de esta configuración inicial se deja correr el tiempo -que son pasos discretos. A cada paso se determina que celdas nacen o mueren según unas reglas muy simples:


  • Si la celda esta viva pero no tiene vecinos: , en la siguiente generación muere:   
  • Si la celda esta viva pero tiene entre 2 o 3 vecinos: , en la siguiente generación permanece viva: 
  • Si la celda esta muerta pero tiene 3 vecinos: , en la siguiente generación se transforma en una celda viva: 
  • Si la celda tiene más de 3 vecinos, muere.

Notar que cuando se evalúa el estado de las celdas, es como si se sacara una foto: las reglas se evalúan en base al estado de esa foto.

Hasta acá nada interesante, ¿Donde esta la gracia de todo esto?
La gracia esta en que dependiendo de la configuración inicial, si uno deja correr el "tiempo" las celdas cobran vida. Hasta el punto que es posible simular una maquina de Turing!

El aprendizaje de todo esto, es que "formas de vida" muy simples pueden dar lugar a comportamientos muy complejos. Algo que menciona Douglas Hofstadter en su libro Gödel-Escher-Bach cuando hace la analogía entre las neuronas y las colonias de hormigas.

Como ven esto es algo muy interesante y simple de implementar a la vez :)
Por eso lo use como excusa para hacer algunos experimentos con JavaScript, experimento que pueden bajar de este link.

Nota:
El link contiene un WAR (Java Web Application Archive) que no es más que un archivo .zip.
Pero no necesitan Java, ni Tomcat o Jetty para probarla.
La razón por la que use un WAR es la siguiente: quisé hacer tambien el experimento de usar LESS (un lenguaje de macros para CSS -altamente recomendable).
LESS incluye una version JavaScript que pueden usar en el cliente... pero desafortunadamente usa un XMLHttpRequest para bajar el CSS, y por razones de seguridad browsers como Chrome lo filtran.
Por eso termine haciendo una aplicación web, que usa un servlet para LESS (tenia otras opciones, pero quería probar LESS y esta opción era más sencilla que instalar Node.js en Windows).
El uso de LESS no es necesario, pueden jugar con el ejemplo sin necesidad de levantar una aplicación web: abran directamente el archivo index.html dentro del war.
En el próximo post les cuento como desarrolle esta pequeña implementación (que usa jQuery, Raphael y local storage).

Mientras tanto les recomiendo jugar con patrones como este (pueden usar la opción de Save/Load para guardar/recuperar el patrón del local storage):