4 de Febrero, 2014

»Garbage collection · Una de las cosas que no me terminaron de convencer en mi lenguaje de programación es que no podía controlar que toda la memoria reservada se liberara correctamente, especialmente por cómo funciona el runtime. La solución era muy complicada por el diseño del invento, o quizás no tanto... usando el Boehm-Demers-Weiser garbage collector, que básicamente se encarga de gestionar la memoria por nosotros, contando referencias (imagino) y convirtiendo a C en algo más manejable con un recolector de basura ;). Este probablemente es el último cambio a mi lenguaje de juguete, que ya puede hacer más de lo que tenía planeado ;).

Hay 0 comentarios, anotación clasificada en: jtc, programming.

2 de Febrero, 2014

Flax

Hoy he acabado Flax, un juego que he programado durante el mes de Enero dentro del reto one game a month, lo que quiere decir que por ahora lo he conseguido (fácil siendo el primer mes, claro :P).

Se trata de un shoot'em up bastante sencillo que recuerda mucho a Dodgin' Diamond 2 (mismo autor, qué le vamos a hacer) y que no va a sacudir los cimientos del género ni mucho menos (aunque es jugable, ojo). Está programado en Javascript con canvas 2D, y he comprobado que funciona bien tanto en Chrome como en Firefox.

Lo he utilizado como excusa para aprender a fondo a usar canvas y valorar si se puede utilizar para hacer juegos algo complejos, y más o menos estoy satisfecho con el resultado, aunque no ha sido nada fácil.

No he usado ningún framework o librería (salvo para el sonido, que he trabajado con SoundJS), porque quería saber realmente cómo funcionan las cosas sin distracciones de más alto nivel. Lo que me he encontrado es por una parte lo que ya comentaba sobre los problemas con la aceleración, a lo que hay que sumar lo complicado que es trabajar con requestAnimationFrame y conseguir animaciones fluídas (de esto ya hablaré con detenimiendo más adelante), y por otra un API sencillo y fácil de usar que permite ponerse en marcha tras apenas ojear un poco la documentación.

Ya estuve cacharreando con three.js, así que creo que ya puedo incluir web en mi arsenal para hacer juegos. Lo malo va a ser luego decidir qué herramienta es la mejor para cada proyecto (¡y tengo que ponerme con el juego de Febrero! :D).

Hay 3 comentarios, anotación clasificada en: javascript, programming, 1gam.

23 de Enero, 2014

»Aceleración hardware en Linux · Una de las cosas que menos me están gustando de desarrollar un juego para web es que el soporte para aceleración por hadware en Linux está realmente mal. Puedes ojear chrome://gpu en Chromium (Chrome) o about:support en Firefox para ver si tu navegador va a usar toda la capacidad de tu tarjeta grafica; y puede que te lleves una sorpresa como me ha pasado a mi al ver que tengo aceleración con WebGL, pero en canvas todo va por software :(. ¿El motivo? Según los desarrolladores los drivers de las tarjetas gráficas en Linux tienen la culpa: incompletos o repletos de fallos. Vamos, casi como estaban las cosas hace más o menos un año.

Actualización: información sobre drivers gráficos y X11 en Firefox.

Hay 0 comentarios, anotación clasificada en: internet.

19 de Enero, 2014

Programación orientada a objetos en Javascript

Estoy intentando hacer un juego en Javascript usando canvas como parte de mi reto One Game a Month (ya hablaré de esto más adelante si consigo entregar algo :D).

El juego que estoy programando es mucho más sencillo de implementar usando un diseño orientado a objetos, así que he tenido que investigar un poco cómo funciona el tema en Javascript, y finalmente me he decidido por un enfoque funcional (con funciones) en lugar de usar prototipos como es más habitual (por ejemplo Introduction to Object-Oriented JavaScript), pero que no soporta propiedades privadas.

El tema es más o menos seguir una convención en todo tu proyecto, y para mi usar funciones ha resultado a la vez potente y sencillo.

La POO funcional en Javascript se puede resumir como:

var Clase = function(params) {
    // contenido publico
    var self = {
        nombre : "Clase",
        params : params,

        metodo_publico : function() {
            return true;
        }
    };

    // propiedades privadas
    var privado = 0;

    // propiedades progegidas
    self.protegido = "foo";
    self.metodo_protegido = function() {
        return false;
    };

    // como devolvemos 'self' que es un objeto creado con {}
    // no será necesario usar new
    return self;
};

Esa sería más o menos la estructura de una clase. Vamos a ver un ejemplo sencillo:

var Vehiculo = function(nombre, nruedas) {
    var self = {
        nombre : nombre
    };

    var nruedas = nruedas;

    self.get_nruedas = function() {
        return nruedas;
    };

    return self;
};

Con esto definimos un vehículo que tendrá dos propidades: nombre (público, podemos cambiarlo) y nruedas (número de ruedas, que es privado y no va a cambiar). Vamos a hacer alguna preba:

> v = Vehiculo("bicicleta", 2);
  Object {nombre: "bicicleta", get_nruedas: function}
> v.nombre; 
  "bicicleta"
> v.nruedas; 
  undefined
> v.get_nruedas();
  2

Esto es bastante básico. Ahora vamos a implementar herencia, que es lo que realmente necesito para mi juego. Definamos una subclase Coche que añade funcionalidad a un vehículo:

var Coche = function(fabricante, modelo, npuertas) {
    var self = Vehiculo("coche", 4);

    var npuertas = npuertas;

    self.get_npuertas = function() {
        return npuertas;
    };

    self.fabricante = fabricante;
    self.modelo = modelo;
    self.nombre += " (" + fabricante +" " + modelo +")";

    return self;
};

Bueno, es un ejemplo algo tonto, pero nos pemite ver cómo hemos modificado una propiedad pública y hemos añadido funcionalidad a lo que ya teníamos en la clase base:

> c = Coche("Opel", "Corsa", 3);
  Object {nombre: "coche (Opel, Corsa)", get_nruedas: function, get_npuertas: function, fabricante: "Opel", modelo: "Corsa"…}
> c.get_nruedas();
  2
> c.nombre;
  "coche (Opel Corsa)"
> v.nruedas; 
  undefined
> v.npuertas; 
  undefined

Esto es lo que estoy usando, y para mi es suficiente. Es importante destacar que esta estrategia nos permite reemplazar un método de la clase base en la clase derivada, pero no hay forma de llamar al método base para aumentar su fucionalidad (en el ejemplo he modificado una propidad pública premeditadamente, porque eso sí se puede hacer :P).

Douglas Crockford propone añadir el siguiente método a tipo Object:

Object.prototype.super = function(name) {
    var self = this, method = self[name];
    return function() {
        return method.apply(self, arguments);
    };
};

De forma que podríamos hacer algo como:

var Motocicleta = function(sidecar) {
    var self = Vehiculo("motocicleta", 2);

    self.sidecar = sidecar;

    var super_get_nruedas = self.super('get_nruedas');
    self.get_nruedas = function() {
        var ruedas = super_get_nruedas();
        if(self.sidecar) {
            ruedas += 2;
        }
        return ruedas;
    };

    return self;
};

Con lo que si nuestra motocicleta lleva sidecar, añadimos dos ruedas (menudo ejemplo):

> m = Motocicleta(false);
  Object {nombre: "motocicleta", get_nruedas: function, sidecar: false, super: function}
> m.get_nruedas();
  2
> m = Motocicleta(true);
  Object {nombre: "motocicleta", get_nruedas: function, sidecar: true, super: function}
> m.get_nruedas();
  4

Imagino que hay mejores formas de explicar todo esto, y yo no soy un experto en Javascript, pero escribir esta anotación me ha ayudado a aclarar mis ideas y me servirá para tener algunas notas cuando pase el tiempo y no me acuerde en qué estaba pensando cuando escribí el código ;).

Hay 4 comentarios, anotación clasificada en: programming, javascript.

8 de Enero, 2014

CentOS une fuerzas con Red Hat

Gran noticia: CentOS une fuerzas con Red Hat.

Está todo explicado en el anuncio, pero básicamente parte del equipo de CentOS (nueva web, por cierto) pasa a trabajar para Red Hat (pero no en su Enterprise Linux), manteniendo su independencia en lo que respecta a CentOS y trabajando con Red Hat en algunos puntos que creo que van a beneficiar a los usuarios de CentOS.

Veremos como se desarrollan las cosas, pero creo que tiene mucho sentido que Red Hat se beneficie del conocimiento acumulado durante los años por la gente trabajando en CentOS y no se trata necesariamente de una maniobra para controlar a un posible competidor.

Red Hat tiene una impecable trayectoria en el mundo del Open Source, y no hay una empresa que entienda mejor cómo contribuir. En resumen: ¡buenas noticias!

Hay 0 comentarios, anotación clasificada en: centos, software libre.

7 de Enero, 2014

»¡Diccionarios! · He añadido diccionarios a mi lenguaje de programación. No es que ahora sea útil de repente, pero al menos se pueden hacer algunas cosas más interesantes; y desde luego implementar este tipo de datos no ha sido tarea fácil :P. Me parece curioso como he tomado algunas decisiones de diseño sobre la marcha que me han recordado posteriormente a Perl, me he sentido un poco Larry Wall por unas horas :D.

Hay 0 comentarios, anotación clasificada en: programming, jtc.

5 de Enero, 2014

Mi propio lenguaje de programación

No sé que tienen los sistemas operativos y los lenguajes de programación que son tan interesantes de diseñar e implementar (al menos hasta cierto nivel de complejidad, que es más o menos cuando deja de ser divertido :P), pero a mi me pica el gusanillo de vez en cuando.

Hace años programé un intérprete para un lenguaje inventado (hasta cierto punto, era una especie de C) usando flex y bison, dos herramientas para generar compiladores e intérpretes, y fue muy entretenido y aprendí muchas cosas.

Lamentablemente eran tiempos de DOS (y pre-Internet, al menos para mi), con lo que todo aquello se perdió (no sé si es mejor así :D).

Estas vacaciones he vuelto a las andadas, aunque con un conjunto de herramientas ligeramente distinto: Python y PLY (que es una implementación en Python de Lex y Yacc; o lo que es lo mismo: flex y bison).

Además he cambiado el enfoque creando un compilador en lugar de un intérprete, generando código intermedio en C que puede ser compilado a código binario. Así que no es solo Python, también he tenido que escribir una buena cantidad de código C (especialmente el run-time del lenguaje).

Tomemos como ejemplo el siguiente programa:

# calculate the n-th Fibonacci number
def main() {
    def fib(n) {
        if(n <= 1) {
            return n;
        }
        return fib(n-1) + fib(n-2);
    }
    println(fib(10));
    return 0;
}

Los pasos para compilar el código son los habituales:

  1. Análisis léxico: usando lex se transforma el código en tokens con significado en nuestro lenguaje y que serán procesados por el parser.
  2. Análisis sintáctico: se analizan los tokens y se genera un árbol de sintaxis con yacc que permite evaluar qué es correcto o no en nuestro lenguaje.
  3. Generación de código: en mi caso genero código en C, comprobando algunas cosas como que no se acceda a variables que no existan o el número de argumentos de las funciones, que finalmente se compila con cualquer compilador de C estándar.

En nuestro ejemplo los token serían algo así como:

LexToken(DEF,'def',2,38)
LexToken(ID,'main',2,42)
LexToken(LPAR,'(',2,46)
LexToken(RPAR,')',2,47)
LexToken(LCB,'{',2,49)
LexToken(DEF,'def',4,53)
LexToken(ID,'fib',4,57)
LexToken(LPAR,'(',4,60)
LexToken(ID,'n',4,61)
LexToken(RPAR,')',4,62)
LexToken(LCB,'{',4,64)
...

Que al procesarlos con el parser se transforman en lo siguiente:

(15: func -> sub: [
  (2: params -> sub: [] value: None), (13: block -> sub: [
    (11: func -> sub: [(4: params -> sub: ['n'] value: None), ...

Con esa estructura de datos se genera el siguiente código C, que al compilarlo da un binario que cuando se ejecuta imprime el resultado esperado: 55.

El compilador está disponible en github: Juan's Toy Compiler; y como su propio nombre indica: es un juguete ;) (además ha sido un proceso de descubrimiento para mi y no estoy del todo seguro de hacer las cosas de la forma más adecuada).

En la página del proyecto hay una descripción del lenguaje, cuyas principales características son:

  • Soporta funciones con ámbito local, parámetros por referencia, recursividad y devolución de valores.
  • Tipado dinámico con tres tipos distintos: números enteros, números decimales (coma flotante) y cadenas de texto. No hay tipo booleano, se usan enteros como en C.
  • Operadores aritméticos y lógicos, con algunas conversiones automáticas (sin llegar a la pesadilla de Javascript :P).
  • Control de flujo con condicionales y bucles.
  • Algunas funciones internas como salida por pantalla o identificar el tipo de una variable.

Lo más interesante (e ineficiente, por cierto) es la implementación del tipado dinámico, que hace que el run-time se comporte en realidad como un intérprete (los operadores no saben qué tipo son los operandos hasta que están en tiempo de ejecución), y probablemente usar uthash para almacenar las variables.

Por lo demás es un juguete que no sirve para nada más que para tenerme entretenido un par de tardes, y por la satisfacción de haber creado mi propio lenguaje de programación ;).

Actualización: me acabo de acordar de mi intérprete de Forth, que me parece que es la última vez que me dio por hacer un intérprete :D.

Hay 0 comentarios, anotación clasificada en: programming, jtc.

2 de Enero, 2014

Una historia sobre DRM

A la vuelta de nuestras vacaciones en España el tiempo por aquí era bastante malo, incluso peor de lo que era de esperar: lluvia, viento y frío; así que no apetecía para nada salir a la calle. Bien, estába viendo un par de vídeos en YouTube y me crucé con Monsters University, que no habíamos visto, y resulta que está para ver vía Google Play.

No parecía mala idea: se puede ver desde la web (no como otros servicios que requieren un dispositivo con Android o algún plugin que no funciona en Linux) y el precio es aceptable ($5 en modo alquiler: no suelo ver las películas más de una vez... así que es perfecto.). Pues no salió tan bien como esperaba :(.

Resulta que la reporoducción vía web utiliza Flash, que no es problema porque está disponible en Linux, pero requiere que esté HAL instalado... que es una tecnología abandonada en pro de udev (las distribuciones dejarón HAL atrás en 2011), con lo que no está disponible para Fedora 19.

El caso es que Adobe lo sabe y le da igual, probablemente porque hace tiempo que Linux no entra en sus planes.

Podemos aceptar que a Adobe, le de igual... pero ¿algo pintará Google Play en todo esto? Pues parece que no. Cuando intentas reproducir el vídeo sin HAL... simplemente no funciona, con lo que descubrir donde está el problema es bastante complicado hasta que encontré la lista de requisitos y ese Ubuntu and Linux OS users must install the HAL module -eso en los sistemas que existe el paquete; ¿vuelvo a usar Fedora 15?-.

La verdad es que la situación es algo mejor que en otros servicios en los que, por ahora, la única solución es usar WINE; lo cual es un hack con el que no estoy del todo de acuerdo porque está claro que los señores de Netflix no quieren mi dinero (ni el de otros usuarios de Linux).

Finalmente pude ver la película en mi Chromebook; que efectivamente lleva soporte para el DRM de Flash. A partir de aquí el problema era que, al parecer, YouTube tenía problemas para reproducir el vídeo a 480p (máxima resolución vía web; que no es mucho, ¿verdad?) y nos tuvimos que conformar con 360p :(. Mi conexión es capaz de mucho más que eso, así que sospecho que tendría que ver con la fecha/horas y congestión en la parte de Google.

Por una parte el precio y el servicio no me parecen mal, las condiciones son correctas (tienes 1 mes para ver la película, y una vez vista la puedes ver todas las veces que quieras durante 48 horas); pero el servicio para los usuarios de Linux deja mucho que desear. Luego está el tema de la calidad del vídeo; que en una pantalla grande no hubiera resistido bien esos 360p. Sin duda lo tienen que mejorar.

Al final la mayoría de los problemas que me he encontrado vienen del DRM. Si es relativamente fácil encontrar un torrent con esa película a calidades mucho superiores (1080p!), está claro que hay otros mecanismos para obtener la película y no es vía Google Play; si solo voy a ver la película una vez, ¿por qué no ofrecerla sin DRM de forma que no sea una barrera entre los contenidos y los usuarios? A saber, yo por mi parte no creo que repita la experiencia en estas condiciones.

Hay 0 comentarios

20 de Diciembre, 2013

»Blackwell · Ya comenté hace unos meses lo complicado que es diseñar juegos y que jugar puede ayudar con la inspiración. Mi última PyWeek fue algo así como una aventura gráfica y, aunque he leído algún buen ensayo, también tengo que jugar un poco, ¿no? :).

La gente de Wadjet Eye Games regaló The Blackwell Deception durante el pasado Halloween, así que lo bajamos y al final lo hemos completado (a ratos los domingos, serán ¿unas 10 horas de juego?). Es una aunténtica pasada: una aventura gráfica bastante bien hecha, con buenos puzzles (con su lógica, en general) y una historia excelente; así que nos hemos puesto con The Blackwell Convergence y por ahora nos está gustando mucho.

Recomiendo el Blackwell Bundle en GOG, que por $7.49 puedes bajarte los 4 capítulos para jugar en orden (además sin DRM). Son juegos hechos con AGS, así que van bien en Linux con Wine (mejor que el intérprete nativo de AGS, que estaba algo verde al menos cuando yo lo compilé, porque petaba aleatoriamente :S).

Hay 0 comentarios

8 de Diciembre, 2013

»London Python Code Dojo · Este pasado jueves asistí al London Python Code Dojo, y fue una pasada (en las coloristas oficinas de Mind Candy, creadores de Moshi Monsters). Si no sabes de qué va este code dojo -porque el mismo nombre se usa para varias cosas; modas imagino-, puedes ojear la presentación de Nicholas Tollervey. En esta edición estuvimos jugando a Robot Game, en el que programas robots en Python para que luchen entre ellos (parecido a la Google AI Challenge). Muy divertido e inspirador, y pude aprender algunas cosas nuevas :).

Hay 0 comentarios, anotación clasificada en: programming, python.

Entradas antiguasEntradas nuevas