Una de raíces cuadradas

9 mayo, 2012

En esa que hace poco hago una entrevista técnica por teléfono para una compañía internacional y me preguntaron 3 cosas en el tiempo que duró, pero solo fui capaz de responder a 1 satisfactoriamente. De las otras dos, la primera fue: En una hipotética plataforma móvil con poca memoria y donde solo se dispone de enteros, nos encontramos con que no disponemos de una librería matemática, ¿sabría usted realizar un algoritmo para calcular raíces cuadradas?

Mi estupefacción en ese momento fue considerable y le dije que internet estaría lleno de esa clase de algoritmos. Obviamente me dijo que en esta hipotética situación, no se podía acceder a internet. Así que me sinceré y le dije que posiblemente llevaba sin calcular una raíz cuadrada desde los 12 años. Oh tonto de mí, que varias horas después pensé en un primer método muy sencillo por fuerza bruta, y varios minutos después en uno un poco menos bruto.

El método más bruto es empezar desde el cero, calcular el cuadrado de la victima actual, comprobar si es mayor o igual el resultado al número que deseamos calcular, si es menor pasamos a la siguiente víctima, sino miramos a ver si el resultado es igual, en ese caso se devuelve la victima actual, sino la anterior. Esta forma sencilla se le puede ocurrir a cualquier persona, pero supongo que los nervios siempre juegan una mala pasada. La otra solución es:

#include <iostream>
#include <vector>

unsigned Square(unsigned x) { return x * x; }

void FindSquareRootRange(
    unsigned victim, unsigned baseResult,
    unsigned & nextLower, unsigned & nextUpper
) {
    unsigned prevOffset = 0, nextOffset = 1;
    while(Square(nextOffset + baseResult) < victim) {
        prevOffset = nextOffset;
        nextOffset <<= 1;
    }
    nextLower = baseResult + prevOffset;
    nextUpper = baseResult + nextOffset;
}

unsigned SquareRoot(unsigned victim) {
    if(victim < 2) {
        return victim;
    } else {
        unsigned lower = 0, upper = victim;
        do {
            FindSquareRootRange(victim, lower, lower, upper);
        } while(upper - lower > 1);
        return Square(upper) == victim ? upper : lower;
    }
}

int main(int agrc, char ** argv) {
    const unsigned MAX_VICTIM = 1000000;
    const unsigned MAX_RESULTS = 1000;
    std::vector<unsigned> results[MAX_RESULTS];

    for(unsigned i = 0; i < MAX_VICTIM; ++i) {
        unsigned currentResult = SquareRoot(i);
        results[currentResult].push_back(i);
    }

    for(unsigned i = 0; i < MAX_RESULTS; ++i) {
        if(!results[i].empty()) {
            std::cout << "Sqrt(" << results[i][0] << ".."
                      << results[i][results[i].size() - 1]
                      << ") = " << i << "\t\t"
                      << ((Square(i) == results[i][0]) ?
                          "true" : "false")
                      << std::endl;
        }
    }

    return 0;
}

La idea sigue siendo similar a la primera de fuerza bruta, solo que la forma de seleccionar nuestra próxima víctima cambia. En vez de ir de uno en uno, vamos usando las potencias de 2, para obtener un rango de valores donde podría estar el resultado, hasta que este rango se componga de como mucho 2 valores. Entonces cogemos y tomamos de esos dos valores el que más cerca esté sin pasarse.

Horas después de encontrar la solución de este problema, encontré una idea para afrontar el segundo que no pude responder, pero ya escribiré sobre eso otro día. Que a ver si le doy un poco más de vidilla al blog de vez en cuando, jej… ^_^U


Defenders of mankind

28 marzo, 2012

Bueno, finalmente he rescatado el ejecutable del juego que hice con 3 compañeros en el master de videojuegos del 2011. Fueron 6 meses de trabajo duro que terminaron con este… juego… (o algo parecido a un juego a pesar de todo…) De todos modos, he colgado también el código fuente por si algún temerario quiere echarle un vistazo (para vuestra suerte los comentarios están en castellano). Y también podéis visitar la página web del juego que todavía está disponible.

Descargas:


XML, XNA y el Content

14 marzo, 2012

Una de esas cosas que adoro de C# es lo fácil que resulta serializar y deserializar datos en xml, gracias al inmenso poder de la reflexión (algún día tengo que retomar el tema y explicar algunas cosas que se me pasaron la última vez). Comparado con otros lenguajes, la experiencia resulta como alcanzar el nirvana, ya que durante el master por ejemplo tuve que escribir el cargador del xml de escenas para ogre… y no fue algo rápido (no es que sean algoritmos complicados, pero estas cosas se vuelven repetitivas y resulta pesado tener que escribir una y otra vez código similar para cada objeto).

En XNA podemos también cargar y salvar XMLs en PC al menos (porque en la xbox no he podido probarlo todavía), dentro del StorageContainer que tengamos seleccionado. Pero también tenemos una forma de cargar XML a través del Content de nuestro proyecto. Las ventajas de usar el Content son principalmente mayor rapidez a la hora de cargar los recursos, al haber sido reconvertidos para mejorar este proceso. Sin embargo, no todo iba a ser felicidad pura, ya que por ejemplo no tenemos acceso a los atributos de una etiqueta, por ejemplo. Digamos que tenemos en nuestro namespace DataTypes lo siguiente:

public class Hamperdine {
  [ContentSerializerIgnore()]
  public string ForeverAlone = "Forever alone!!!";

  [ContentSerializer(ElementName = "Size")]
  public int SignedNumber = 101;

  [ContentSerializer(ElementName = "Answer",
     Optional = true)]
  public uint UnsignedNumber = 42;

  [ContentSerializer(ElementName = "UnrealNumber")]
  public float RealNumber;

  [ContentSerializer(ElementName = "DeadSpace")]
  public Rectangle IntRectangle;

  [ContentSerializer(ElementName = "VectorTwo")]
  public Vector2 FloatPoint;

  [ContentSerializer(ElementName = "Ormagöden")]
  public BrütalLegend AwesomeGame;
}

public class BrütalLegend {
  [ContentSerializer(ElementName = "Ozzy")]
  public string GuardianOfMetal;

  [ContentSerializer(ElementName = "Lemmy",
     CollectionItemName = "AceOfSpades")]
  public string[] KillMaster;

  [ContentSerializer(ElementName = "Halford",
     CollectionItemName = "Painkiller")]
  public List<string> TheBaron;
}

De aquí podemos sacar que una propiedad o campo en la clase puede tener los siguientes atributos:

  • ContentSerializerIgnore: Ignora al miembro etiquetado con este atributo a la hora de cargar el fichero.
  • ContentSerializer: Indica que el miembro etiquetado debe ser serializado. Podemos indicar las siguientes opciones, entre otras:
    • ElementName: El nombre de la etiqueta dentro del fichero XML. Si no se indicara un nombre para la etiqueta, por defecto tomará el nombre del miembro etiquetado en la clase.
    • Optional: Flag para indicar si el elemento es opcional o no. Por defecto, en caso de no indicarse vale false.
    • CollectionItemName: El nombre de las etiquetas de cada ítem dentro de una lista (se puede usar un array o una lista genérica para almacenar los datos cargados). Por defecto, en caso de no indicarse vale “Item”.

Entonces nos quedaría un XML tal que:

<?xml version="1.0" encoding="utf-8" ?>
<XnaContent>
  <Asset Type="DataTypes.Hamperdine">
    <Size>108</Size>
    <UnrealNumber>3.14</UnrealNumber>
    <DeadSpace>4 8 15 16</DeadSpace>
    <VectorTwo>23 42</VectorTwo>
    <Ormagöden>
      <Ozzy>Crazy!!!</Ozzy>
      <Lemmy>
        <AceOfSpades>You know I'm born to loose...</AceOfSpades>
        <AceOfSpades>and glambling's for fools...</AceOfSpades>
      </Lemmy>
      <Halford>
        <Painkiller>This is...</Painkiller>
        <Painkiller>the painkiller!!!</Painkiller>
      </Halford>
    </Ormagöden>
  </Asset>
</XnaContent>

Hay que tener en cuenta, que los nodos tienen que estar ordenados del mismo modo que lo están los miembros de la clase, o sino el proyecto no compila (una pequeña restricción que tampoco es muy terrible). ¿Y cómo podemos cargar entonces el fichero? Seguro que de una forma retorcida y complicada, ¿no?

Hamperdine hamperdine = Content.Load<Hamperdine>("hamperdine");

¿Cómo? ¿Me tomas el pelo? Pues la verdad es que no, así de fácil es cargar este tipo de recursos en XNA. Por lo que con esto podéis hacer herramientas que guarden los datos en estos XML limitados y cargarlos a objetos en el juego de forma sencilla.

Por último voy a mostrar, en caso de no querer poner tantas etiquetas de atributos, otra opción que podríamos tomar para definir la clase:

public class Hamperdine {
  [ContentSerializerIgnore()]
  public string ForeverAlone = "Forever alone!!!";

  public int SignedNumber = 101;

  [ContentSerializer(Optional = true)]
  public uint UnsignedNumber = 42;

  public float RealNumber;

  public Rectangle IntRectangle;

  public Vector2 FloatPoint;

  public BrütalLegend AwesomeGame;
}

public class BrütalLegend {
  public string GuardianOfMetal;
  public string[] KillMaster;
  public List<string> TheBaron;
}

Entonces el XML tendría que ser de la siguiente forma:

<?xml version="1.0" encoding="utf-8" ?>
<XnaContent>
  <Asset Type="DataTypes.Hamperdine">
    <SignedNumber>108</SignedNumber>
    <RealNumber>3.14</RealNumber>
    <IntRectangle>4 8 15 16</IntRectangle>
    <FloatPoint>23 42</FloatPoint>
    <AwesomeGame>
      <GuardianOfMetal>Crazy!!!</GuardianOfMetal>
      <KillMaster>
        <Item>You know I'm born to loose...</Item>
        <Item>and glambling's for fools...</Item>
      </KillMaster>
      <TheBaron>
        <Item>This is...</Item>
        <Item>the painkiller!!!</Item>
      </TheBaron>
    </AwesomeGame>
  </Asset>
</XnaContent>

Y esto es todo por ahora, espero que os pueda resultar útil. Un saludo.


Iniciando el remake de una década

2 marzo, 2012

Pues ya llevo como unas dos semanas que he retomado la programación de buena gana, aunque de vez en cuando juego un rato al WoW para no perder las malas costumbres y tal, jej… xD En fin, el caso es que empecé primero planteándome la versión en C++, por lo que me puse a iniciar una especie de port de XNA a C++, pero eso implica muchas clases y aunque mi intención es intentar cubrir con ese port la mayor parte de la librería, mi prioridad es el remake más que la librería. Por ello me puse con la versión de C#, así puedo ver qué necesito realmente para una primera versión alfa del port, hacerlo y lanzar el remake al mundo, y después centrarme en la librería con menos preocupaciones.

Mientras investigaba en la primera semana para portar XNA a C++, pude observar una curiosidad, que después de leer la documentación en la MSDN sobre DirectInput cobra cierto sentido. XNA para aquellos que no lo sepan, es una librería montada encima de DirectX 9. La gestión de dispositivos de entrada a grandes rasgos consiste en el teclado, el ratón, los mandos y dispositivos táctiles para el Windows Phone. Para los mandos se utiliza XInput, ya que si algún valiente ha intentado usar un mando de la X360 desde DirectInput, se habrá percatado de que los triggers laterales son tomados como el eje Z (me imagino que es así por el hecho de que estos “botones” tienen un intervalo de valores desde pulsado del todo a no pulsado). Y para el teclado y ratón me imaginé que usaría DirectInput.

DirectInput no ha cambiado desde la versión 8 y desde la página de la MSDN se recomienda usar el sistema de mensajes para el teclado y el ratón (no sé muy bien cuál es la razón para ello). Así que planteando como portar el Input de XNA a C++ me di cuenta que las constantes para las teclas del teclado no coincidían en una serie considerable de valores. Peor aún, cuando inspeccioné en una prueba el valor que XNA daba a los valores del enumerado, pude comprobar que para nada se correspondía con el que DirectInput tenía. Tras dar vueltas y perder un par de días encontré por casualidad una página en la MSDN con las virtual keys de la API de Windows… y tras ver que los nombres eran calcados, pude comprender que no estaban usando DirectInput precisamente. Por suerte para mí hay una función en la API para convertir un valor de virtual key a scan code y poder hacerme así una tabla de traducción de valores. No es directo del todo, pero es mejor que nada.

Quizás parece estúpido no usar los códigos del teclado y usar en su lugar las virtual keys, pero uno normalmente no se daría cuenta de lo problemático que es hasta que coge otro teclado y puede observar que el código que sirve en el teclado castellano para una tecla, en uno estado unidense cambia. ¿Por qué no usar al sistema operativo para que nos abstraiga del hardware y nos haga la vida más feliz? Eso debieron de pensar en Microsoft y por lo que no recomiendan usar DirectInput para cosas como el teclado. Sin embargo nada nos impide hacer un uso de los códigos de las virtual keys y hacer una traducción a los scan codes del teclado que tengamos enchufado en ese momento en tiempo de ejecución.

Después del asunto del Input estuve creando algunas cuantas clases más y tal, y me pasé a iniciar la versión en C# del remake, sobre XNA 4.0. De paso rescaté código que pensaba usar para un juego experimental de tipo fusión entre un Rogue y un juego de Rol por turnos a lo japonés, que espero algún día continuar y que por supuesto será en ASCII. Ese código es un intento de framework para hacer juegos, usando estados, entidades formadas por componentes y algunas cosillas que XNA no tiene por defecto (sprites animados por ejemplo). Así que ando entretenido meditando con cada clase, porque como dice Andrei Alexandrescu, el problema de programar es que tienes que tomar muchas decisiones, cada paso es una montaña de ellas… y claro, eso te lleva a estar meditando largo y tendido, hasta rozar la locura plena… Pero qué se le va a hacer, si al final esto es lo que nos gusta, jej… xD


Dejando la pereza y la desidia de lado…

23 febrero, 2012

Pues después de un par de meses reenganchado al WoW, finalmente he logrado moderar mi vicio con el juego y reconducir un poco las cosas. Así que estoy trabajando en crear una versión inglesa de mi página/blog, sin por ello dejar de lado completamente esta versión en castellano, porque creo que es interesante y positivo, si publico artículos, hacerlo en los dos idiomas. Porque siendo serios, cualquier estudiante de programación adulto está obligado a aprender inglés para crecer profesionalmente, pero en el caso de un adolescente el tema del inglés es un poco más peliagudo, por lo que creo que es bueno dar opciones.

Además, aprovechando el próximo lanzamiento de mi web en inglés, estoy realizando un remake de la mayoría de mis juegos amateurs (quitando el del curso de verano y el del máster que ya tuve suficiente con hacerlos una vez, jej). ¿La razón? Pues resulta que a pesar del esfuerzo que supusieron en su momento, la mayoría de ellos están hechos para la plataforma MS-DOS, por lo que para cualquiera que no tenga instalado algo como DosBox en Windows Vista o Windows 7, se encuentra ante un problema para poder ejecutarlos y echarles un vistazo. Por no hablar del infame caso del paxnaman, que no he conseguido ejecutarlo en ningún ordenador que no tuviera el Visual C# Express 2008 instalado con el XNA 3.1… Me imagino que quizás falta algún redistribuible de esos que se instalan 20 o 30 para cada juego en PC, pero lo mejor va a ser coger una selección de todos, y hacer un remake en C++ y C#.

La única “pena” es que el código y los comentarios los voy a poner en inglés esta vez, porque ya es costumbre en mi programar de esa forma y tener dos versiones del código es bastante problemático. Lo que no sé es qué hacer con las versiones antiguas (que no las puedo poner en la futura versión inglesa del blog, porque tienen los comentarios escritos en castellano y/o código también en español.

Otra cosa interesante, aprovechando el nuevo C++11 que es un verdadero aire fresco para el lenguaje C++, es que estoy intentando hacer una versión mínima de port de biblioteca “tipo” XNA a C++. No sé hasta qué punto pueda portarlo todo o parte y qué partes, pero de momento he empezado con el proyecto y está resultando interesante para aprender un poco más del funcionamiento de XNA4. También quiero ver, cuando termine con este mostrenco de proyecto, hacer una versión del IEnumerable de C# 4.0, para implementar la parte que me gusta de LINQ con los contenedores de la librería estándar de C++. Sé que hay algunas personas que han logrado hacer implementaciones de eso, pero sinceramente, todo esto no lo hago con fines de “necesidad”, sino formativos y de experimentación.

En fin, espero poder ser menos dejado e ir comentando mis aventuras con el remake.


Diapositivas de la charla sobre XNA 4.0

15 diciembre, 2011

Bueno, sin duda alguna la pereza es todo un pecado y tal, y estar enganchado al WoW de nuevo puede que sea otro, jej. Aprovechando que hoy di una charla introductoria sobre XNA 4, he subido las diapositivas y el prototipo de snake hecho con este maravilloso framework. Que lo disfruteis, si podeis, jej… xD


Planificando el futuro…

20 octubre, 2011

Bueno, llevo bastante tiempo con el blog abandonado, porque estaba pensando en migrar a un servidor web que había pagado, pero últimamente he estado dudando. De todos modos, he aprovechado hoy para hacer un poco de limpieza, porque de cara a los próximos meses quiero reorganizar el blog y centrarlo en la programación y mis proyectos solamente. Además quiero poner una versión en inglés. Así que poco a poco, durante el próximo año estaré reorganizando el blog y espero que publicando algún artículo de interés sobre programación, así como también noticias sobre mis próximos proyectos.


Small Basic en español

15 julio, 2011

Buenas, he migrado mi subsección sobre Small Basic a un blog externo, para centrar la atención del visitante solo sobre el lenguaje y porque estoy pensando en hacer un curso/tutorial durante los próximos meses para enseñar programación a los niños, para si algún día tengo alguno y se interesa, tener algo preparado para no hacer el panoli más de lo necesario, jej.

Ala, un saludo a todo el mundo.


Seguir

Get every new post delivered to your Inbox.