@ agnasg

agnasg


Creo que lo logré

13-10-2011 4:42 PM

Hay veces que nos encontramos con piezas de código inexplicables. Difíciles de entender. Complicados de comprender. Requieren de una segunda o tercera reflexión para dilucidar su génesis, su orígen, qué tipo de estado mental tenía su creador para “crear” algo así.

Hace muchos años alguien me mostró el siguiente segmento de programa. No hace realmente nada pero forma parte de la familia de códigos descritos en el párrafo anterior. (Este post es en realidad para mayores de 18 años. Sí Ud. es menor de 18 años años por favor abandone  esta página de inmediato)
[cce lang=”c” width=”480″]
for (int i = 1; i < 4; i++) {
switch (i) {
case 1:
ejecutar_cosas_relacionadas_a_1 (); break;
case 2:
ejecutar_cosas_relacionadas_a_2 (); break;
case 3:
ejecutar_cosas_relacionadas_a_3 (); break;
case 4:
ejecutar_cosas_relacionadas_a_4 (); break;
}
}
[/cce]
Este código tiene un bug y un problema de implementación.El bug no lo voy a explicar porque es obvio, pero el problema de implementación es demasiado descarado para dejarlo pasar. ¿Qué es lo que esto está haciendo? ¿Para qué es el “switch“? ¿Para qué es el “for”? ¿Para qué es todo este código? El código equivalente es el siguiente:
[cce lang=”c” width=”480″]
ejecutar_cosas_relacionadas_a_1 ();
ejecutar_cosas_relacionadas_a_2 ();
ejecutar_cosas_relacionadas_a_3 ();
ejecutar_cosas_relacionadas_a_4 ();
[/cce]
Yo nunca logré explicarme esto. Mi conclusión fue como la de aquél Cura en La Mala Hora: “Fue un momento de ofuscación”. Pero este tipo de accidentes de la prisa sobre la exactitud, no son tan inusuales como podríamos creer. Por ello debemos estar alerta. Debemos estar alerta todo el tiempo. Como he dicho antes, he estado trabajando un juego en javascript. En ciertas partes parece pacman. De hecho, el movimiento del personaje central es igual que el de pacman. En realidad yo nunca había implementado este tipo de movimiento en un espacio-tiempo de tiles (mosaicos o piedras cuadradas o baldosas). Este espacio muy simple simple obedece reglas matemáticas tan complicadas como las del espacio 2.5 o el espacio 3D. Es un espacio de juego, y como tal, es complicado. No podemos tomarlo a la ligera, no podemos aproximarnos a él descuidadamente. Debemos estar alertas.

En este particular espacio 2d, hay 4 movimientos posibles: arriba, abajo, derecha o izquierda. A continuación el código que controla el movimiento hacia la izquierda del jugador. Esta no es necesariamente la primera versión (ni es la definitiva).
[cce lang=”c” width=”480″]
function move_right()
{
room.last_move_direction = 6; // indica cuál dirección llevamos

if (moving)
return;

x = thile[thile_number].x;
y = thile[thile_number].y;
var min_width = bg_width – x – thile_width;
[/cce]
Guardamos en alguna parte que el último movimiento que hizo el jugador es derecha (identificado por 6), guardamos en x,y la posición del jugador (almacenado en thile). Luego inicializamos el mínimo width de del movimiento que en este caso sería lo que queda de tablero menos la posición actual.
[cce lang=”c” width=”480″]
for (i = 1; i < room.tiles_in_level.length ;i++) {
if (i == thile_number)
continue;
xo = parseInt (str_replace(“px”, “”, $(‘#thile’+room.tiles_in_level.charAt(i)).css(“marginLeft”)));
if (!xo)
continue;
if (x > xo) // it can´t be to the right of k.
continue;

yo = parseInt (str_replace(“px”, “”, $(‘#thile’+room.tiles_in_level.charAt(i)).css(“marginTop”)));

if (y > yo && y < yo + thile_height ||
(y < yo && y > yo + thile_height) ||
(yo < y && yo > y + thile_height) ||
y == yo ||
y + thile_height > yo && y + thile_height < yo + thile_height) {

var this_width = Number (xo) – Number (x) – Number (thile_width);
if (this_width < min_width) {
min_width = this_width;
room.cd_id = room.tiles_in_level.charAt(i);
}
}
}
[/cce]
Esto es bien pesado. Aquí estamos recorriendo todos los tiles cuál es el más cercano que está en nuestro camino. Lo voy a decir de nuevo: estamos revisando TODOS los tiles del tablero.
Calculamos la velocidad necesaria para recorrer la distancia obtenida en un segundo.
[cce lang=”c” width=”480″]
moving = true;
var speed_base = 1000.0;
var speed = (min_width / bg_width) * speed_base;

thile[thile_number].x = Number (thile[thile_number].x) + Number(min_width);
[/cce]

Finalmente esta última parte envía el tile la distancia determinada utilizando el procedimiento estándard de un jquery.
[cce lang=”c” width=”480″]

x = thile[thile_number].x;

$(thile[thile_number].tag).animate({
marginLeft: x + “px”
}, speed, function() {
// Animation complete.
moving = false;
start_level ();

});
}[/cce]
Yo no trataría de entender este código, de la misma forma como no trataré de explicarlo (más alla de lo dicho hasta ahora). Lo que quiero es compararlo con la versión final:
[cce lang=”c” width=”480″]
j = parseInt (Math.floor(y – bg_offset_y) / 64);
i = parseInt (x / 64);
do {
i++;
room.set (j, i);
} while (i < ncol && room.available_pos (i, j)); i--; [/cce] Es decir, todo el código de comparación de las posiciones de todos los tiles del tablero lo hemos cambiado por un loop donde validamos si el espacio está o no disponible, basado en un mapa. Las dos primeras instrucciones cambian las coordenadas de la pantalla a las coordenadas del mapa. Yo no sé que proceso mental me llevó a escribir la versión donde comparaba el posicionamiento individual de todos los tiles, pero debe haber sido un proceso mental bien complicado, al igual que su resultado (al cual dediqué días). Sirva como excusa que a medida que escribía código estaba diseñando el juego, y todavía no había decidido cómo sería el mapa. La lección aprendida es la misma: no dudes en eliminar código, cambiarlo, cuestionarlo, desecharlo. Si en un día no has desechado o cambiado código, algo malo está pasando.