@ agnasg

agnasg


Es irrelevante

26-09-2015 4:50 PM

Estoy tratando de entender por qué podría ser irrelevante saber por qué ciertas cosas son de una cierta forma y no de otra. Claro, es irrelevante la pregunta en sí. Entiendo. Yo entiendo que es irrelevante entender porqué nuestro desayuno quedó mal. O por qué una reunión con nuestros colegas llegó a resultados inesperados. O nuestra vida no resultó exactamente como esperábamos. Es irrelevante. Pero estoy aquí tratando de entender por qué es irrelevante que nuestros creadores, los ingenieros, en términos de la película Prometeo, la continuación, la explicación, la segunda parte de Alien, por qué ellos cambiaron de opinión, y ya no nos quieren en la galaxia. ¿Es que acaso no es esa nuestra pesadilla? Resultamos irrelevantes. No es la razón en sí, no es el hecho en sí, es que “nosotros” somos irrelevantes. O nos volvimos irrelevantes. Recuerdo, hablando de películas, la pregunta del profesor Eugene Simonet a Trevor McKinney en la película Cadena de favores: ¿Qué espera la humanidad de tí? Su respuesta fue tajante, genuina, fulminante: Nada.

Es decir, la respuesta en realidad, porque sí. Shaw en la película Prometeo responde “quizás sea porque yo soy humana y tú eres un robot“. ¿Sí? Sí, Shaw, es esa quizás la verdadera razón, ¿o es que la respuesta es que en el fondo nuestros esfuerzos vanos por lograr nuestra última satisfacción, la genuina satisfacción, la deseada satisfacción, en sí son irrelevantes, porque queremos la satisfacción, buscamos esa satisfacción, ¿necesitamos esa satisfacción? Satisfacción que solo una respuesta nos provee. Algo que un robot por supuesto encuentra irrelevante.
EDITADO: este post requirió una semana de digestión, pero fue escrito en su forma actual en algo menos de 15 minutos.

Enlaces relevantes

  • Me estoy cansando de leer estos artículos sobre “por qué mi juego falló”.  Mercadeo, juego que nadie quiere jugar, pésima calidad. Hay una receta para hacer dinero si eres programador: hacer un juego. La verdad es que la programación de juegos no es tan fácil ni divertida como uno podría pensar al comienzo, y la recompensa no necesariamente está garantizada. Pero la gente piensa que la receta funciona porque hay tantos ejemplos de éxito. No, no funciona, los ejemplos de éxito son más bien una rareza: se publican 250 juegos (de calidad con un alto presupuesto en dinero y tiempo)  todos los meses  y apenas 1-2 llegan a tener alguna notoriedad.
  • Ya antes he mencionado el manuscrito Voynich (de pasada sin explicar nada: Cita con Rama escrito en el lenguaje del manuscrito Voynich) El artículo de Wikipedia es tan intrigante como el mismo manuscrito (El manuscrito Voynich es un libro ilustrado, de contenidos desconocidos, escrito hace unos 500 años por un autor anónimo en un alfabeto no identificado y un idioma incomprensible, el denominado voynichés). Quizás la mejor descripción de todos los hechos que rodean este enigma aparece en este documento. Más sobre esto pronto.

 

El bug que no lo es

30-08-2015 5:18 AM

En mi tarjeta de presentación soy un presidente corporativo.
En mi mente soy un desarrollador de juegos,
Pero en mi corazón soy un jugador de videojuegos.
Satoru Iwata 1995-2015

Este es un bug producido por desconocer (u olvidar) cómo es o cómo está estructurada la data. En realidad es un bug mental, no hay bug sino la apariencia de un bug que no lo es. Pero puede ser catalogado como bug porque huele a bug, luce como bug, sabe a bug. El detalle es que resulta ser otra cosa. Este tipo de bug quita tanto tiempo como los bugs reales, cuidado si no más tiempo. Me había pasado antes con clientes, y mi trabajo era convencerlos que el supuesto bug estaba solo en su cabeza. Estos son los bugs difíciles de explicar y los clientes adquieren un temor irracional hacia ellos, por lo que cada vez que aparece algo sospechosos gritan desaforados ¡bug! ¡bug! ¡bug! Inclusive llaman bug a cosas no implementadas. Un bug es algo que no funciona correctamente en algo implementado. Algo que no ha sido implementado no es un bug, es una omisión u olvido.

Pero el caso es que este bug aparente me pasó a mi. Un bug mental. Como ya he dicho estoy programando un parser para los dialogos de los npcs en psyblast. Yo tengo todo un tema con esto de los parsers y siempre prometo que no voy a hacer más nunca en mi vida uno más, pero al final termino enredado en uno nuevo. Volviendo al bug, el parser finalmente procesó y almacenó los dialogos correctamente en la base de datos del juego (sqlite por ahora) pero al final estaban apareciendo 7 registros (o rows en la base de datos) con el valor “Al terminar el hechizo…”, “Al terminar el hechizo…”, “Al terminar el hechizo…”. Por alguna razón el parser no estaba detectando el final del archivo de entrada. Dediqué 3 horas buscando, debugueando, sin ningún éxito. Al final se me ocurrió ver con detalle la base de datos. Estoy usando Sqlitebrowser, que es similar MySQL browser, y como los registros tienen varios campos y ocupan más del tamaño de la ventana, el campo relativo al “valor” queda truncado así que solamente se ve “Al terminar el hechizo…”… claro, al extender la ventana y ver el contenido del campo pude descubrir que el parser estaba funcionando, lo que pasaba es que casualmente los últimos registros corresponden a un npc que enseña hechizos y todos comienzan con la misma descripción “Al terminar el hechizo…”. Así pues, este era un bug que no es un bug. El parser estaba funcionando correctamente, el problema es que yo no recordaba los diálogos de este npc (los cuales escribí hace meses).

Enlaces que sí son enlaces

Parsers 2015

20-08-2015 3:33 AM

Estoy una vez más programando un parser de un archivo de dialogos de npcs intencionalmente simple, pero que ha resultado ser inadvertidamente complicado. Ya he dicho varias veces (1, 2, para la definición de parser ver aquí) que he tenido que hacer varios parsers en mi vida de programador de juegos inéditos. Si leemos aqui, veremos que mi opinión es que usar los viejos atlantes de la programación de compiladores (lex y yacc) es un trabajo de meses. Esa es una exageración, pero las cosas resultan algo como eso (esta librería de facebook usa bison y yacc para parsing de GraphQL, un lenguaje para describir requerimientos de datos). Pero ¿qué tal hacerlo a mano? Depende del lenguaje. Hace años hice un intérprete de un lenguaje similar a C y si mal no recuerdo no resultó complicado. Pero esta vez la complicación provino de la recursividad. Mi “simple” formato incluye un nombre de npc, que puede tener una o más palabras claves, que tienen asociado uno o más párrafos. Todo salpicado con formatos del tipo {[1]}, {[2d6]}, etc. que indican cuántas veces se debe decir el texto. Finalmente se pueden insertar %%comentarios%%, que abarcan una o más líneas. Simple ¿verdad?

No.

[code language=”cpp”]
for (ilineno = 0; ilineno < MAX_LINES;ilineno++) { if (dialog_id && variable_id) { // variable_id not assigned yet to its dialog update_dialog_variable (dialog_id, variable_id); variable_id = 0; dialog_id = 0; } bool found = false; // search a npc while (parser->getline (line)) {
lineno++;

// handle comments
if (handleComments (parser, line)) {
continue;
}

begin = parser->after_pattern(line, CIS_TAG_NPC);

if (begin == std::string::npos) {
continue;
}
std::string s = line.substr (begin);
end = parser->before_pattern(s, CIS_TAG_NPC);
if (end != std::string::npos) {
npcname = s.substr (0, end);
found = true;
break;
}
}
if (!found) {
break; // finished… maybe
}
std::transform(npcname.begin(), npcname.end(), npcname.begin(), ::tolower);
int id = npcs->getId (npcname);
if (id == -1) {
id = npcs->insert (npcname); // create instance
}
(id == -1) && panic ("CIntSystem::load: can’t insert/update a new npc");
// now a loop of ::keywords[,keywords]:: text,text…
while (parser->peekline (line)) { // give me the line but keep it in the input pipeline (so I can do a getline (line) after)
begin = parser->after_pattern(line, CIS_TAG_NPC);
if (begin != std::string::npos) { // we found a npc so we finished
break;
}
dialog_id = insert_dialog (); // create empty dialog
while (parser->getline (line)) {
lineno++;

// handle comments
if (handleComments (parser, line)) {
continue;
}
begin = parser->after_pattern(line, CIS_TAG_KEYW);
if (begin == std::string::npos) {
continue;
}
int i;
for (i = 0; i < MAX_KEYWORDS;i++) { std::string s = line.substr (begin); end = parser->before_pattern(s, CIS_TAG_SEP);
if (end != std::string::npos) {
keyword = s.substr (0, end);
insert_keyword (dialog_id, keyword);
begin = parser->after_pattern (s, CIS_TAG_SEP);
} else {
end = parser->before_pattern(s, CIS_TAG_KEYW);
value = missing + "’" + std::string(CIS_TAG_KEYW) + "’ at line " + itos (lineno);
end == std::string::npos && panic (value);
keyword = s.substr (0, end);
insert_keyword (dialog_id, keyword);
break;
}
}
(i == MAX_KEYWORDS) && panic ("CIntSystem::load: Too much keywords or parsing error");
break;
}
// now dialog’s lines
int index = 0;
while (parser->peekline (line)) { // give me the line but keep it in the input pipeline (so I can do a getline (line) after)
begin = parser->after_pattern(line, CIS_TAG_NPC);
if (begin != std::string::npos) { // we found a npc so we finished
break;
}
begin = parser->after_pattern(line, CIS_TAG_KEYW);
if (begin != std::string::npos) { // we found a another keyword so we finished current keyword
break;
}
while (true) { // comments loop
parser->getline (line); // get the line
begin = parser->before_pattern(line, "::Lugar::");
if (begin != std::string::npos) {
int kk = 0;
kk++;
}
if (lineno == 28) {
int kk = 0;
kk++;
}
// handle comments
if (!handleComments (parser, line)) {
parser->getline (line); // eat the line
break;
}
// verify missing tag
begin = parser->before_pattern(line, CIS_TAG_NPC);
end = parser->before_pattern(line, CIS_TAG_KEYW);
(begin != std::string::npos || end != std::string::npos) && panic ("CIntSystem::load: Wrong comment in line " + line);
}
while (true) { // this loop travel the line until its end… truly amazing
// as the documents is generated using Word, the text is in one line without newline (LF+CR)
// anyway this parser assume is possible to have several lines and each one is taken as a paragraph.
int initial_size = line.size ();
begin = parser->before_pattern(line, CIS_TAG_FMTBEG);
if (begin == std::string::npos) {
if (dialog_id == 0) { // we found a line previously so lets create a new one
dialog_id = insert_dialog (line, 0, index); // create empty dialog
}
// reset all
variable_id = 0;
dialog_id = 0;
trigger_id = 0;
// check next line
break; // exit the loop analizing this line so get a new line.
}
// begin != std::string::npos
// we found some formatting instructions
if (0 != begin) {
value = line.substr (0, begin); // <=:- value is here in case you’re like me update_dialog (dialog_id, value, std::string(), variable_id); variable_id = 0; // this means that variable_id is assigned to his dialog } begin++; // skip CIS_TAG_FMTBEG line = line.substr (begin); begin = line.find_last_not_of(whitespaces); // skip any white spaces
switch (line[begin]) { case CIS_TAG_CNTBEG: // [ // count …
break;
case CIS_TAG_VARBEG: // $

break;
case CIS_TAG_VARACT: // =

break;

case CIS_TAG_VARDIS: // ~

break;
default:


break; // we don’t reach this point.
}

}
}
}
}
:


[/code]

De enlaces

  • Una discusión sobre una patente de ascensor espacial sin que se mencione en lo absoluto a Arthur C. Clarke. Al parecer esta patente gira sobre conceptos que no encajan exactamente con la definición de ascensor espacial, es más bien una torre muy alta con un espaciopuerto en la azotea. Alguien hizo un post en 9gag sobre lo mismo.
  • Leyendo aquí descubrí Carrion Fields, un roleplaying mud, que inclusive está de 6to en topmuds. Raro que no lo vi hace meses cuando huía despavorido de batmud. En esa ocasión visité Aardwolf (suele estar de primero, me gustó hasta dónde llegué), landsofredemption.comabandonedrealms.com y Slothmud.
  • Tú necesitas un plan y un diseño. No. Tú necesitas ponerte a trabajar. Planear lo hacen los aviones 🙂 Hablando en serio me gustaría hacer un inventario de cuántos posts como este he leído en los últimos 20 años. Pero si usted nunca ha leído uno así hágalo, la planificación es en mi opinión inútil pero siempre sirve como divertimento medieval cuando no tenemos nada mejor que hacer. Yo escribo ideas todo el tiempo, así que organizarlas en un plan no molesta en lo absoluto, así que sí, planifique, planifique, eso es bueno.

Oh Oracle

11-08-2015 10:31 AM

Solo enlaces

  • Me gustó este artículo por la forma extraña en que utiliza la expresión “No te repitas a ti mismo”. Esperaba una disertación sobre no caer de nuevo en errores que ya has cometido, pero en realidad se trata sobre no duplicar código. ¡¿No duplicar código?! ¡Como si pudiéramos evitarlo! No me refiero a las tonterías que hacemos cuando solemos ser novatos (somos novatos cada vez que comenzamos a trabajar con un sistema, api, lenguaje o herramienta nueva, lo cual debe suceder al menos una vez al año, es decir somos novatos anualmente), me refiero a las oportunidades en que tenemos que duplicar código. O cuando tenemos que hacer una y otra vez algo. Por ejemplo, he dicho que en mi vida de programador de juegos he tenido que hacer varios parsers, y metalenguajes para manejar el scripting, o los diálogos del juego. Lo hecho al menos 4 veces incluyendo cuando traté de hacer una imitación de Inform (reportado en alguna parte en el caad como un fracaso). Pues bien, aquí lo estoy haciendo otra vez con psyblast. ¿Repitiendome a mi mismo? La historia de mi vida. Y es que vivimos en la dicotomía de Ousterhout, entre un lenguaje formal y el lenguaje para scripting. Y en programación de juegos, esto es una norma obligada.
  • Journey of the light, un juego tan difícil que el desarrollador no se tomó la molestia de incluir los niveles 2-8 porque el 1 ya era lo suficientemente difícil. Evidencias. Steam de hecho decidió ofrecer la devolución total del dinero a quien lo solicite, sin importar el tiempo de juego ya consumido. El desarrollador se disculpó, dijo que fue un error, pero que el daño ya estaba hecho. Ouch.
  • ¿Quieren ver el blog post más arrogante del mes? Lean esto. ¿Oh un 404? Es porque es tan arrogante, es tan mala publicidad, que la gente de mercadeo de Oracle decidió eliminarlo. Pero no importa, aquí hay algunas copias: 1,2,3,4. Basicamente la Jefe de seguridad de Oracle dice que un cliente no puede investigar en busca de fallas (haciendo ingeniería inversa o cualquier otra cosa) porque eso sería violación de la licencia, y que eso es como ser infiel a la esposa/esposo. Y si un cliente descubre una falla tiene que mostrar suficientes evidencias como para que Oracle tome cartas en el asunto. Increíble. Reportado en reddit y Hacker news. Oh Oracle…