Cada nodo, proviene de un solo padre, y puede tener 1 o 2 hijos. El orden elegido es el de inorden. Es una numeración recursiva, y se basa en los siguientes pasos:
- Numeramos la raíz.
- Numeramos el subárbol que cuelga de uno de sus hijos.
- Numeramos el subárbol que cuelga de su otro hijo (si es que tiene).
Esta numeración nos conviene a la hora de confeccionar el algoritmo, ya que si lo analizamos, nos damos cuenta de que los descendientes de cada nodo, son una sucesión de números comprendidos entre dos límites. Es decir, si el nodo que buscamos esta entre esos dos limites, significa que está en esa rama, y continuaremos avanzando por ella. Para entender mejor esto, vemos un ejemplo: Imaginemos que estamos en el nodo 13, y queremos ir al 19. El nodo 13 tiene un solo hijo, y todos sus descendientes están comprendidos entre el 14 y el 17. Como nuestro destino (19) no está comprendido entre esos limites, significa que tenemos que avanzar hacia el padre.
Ahora estamos en el nodo 12, y el proceso es similar, el 19 no está entre el 13 y el 17, así que continuamos hacia arriba.
Llegamos al 11, este nodo es un poco mas complejo, ya que tiene dos hijos. Primero comprobamos uno de ellos, cuyos descendientes están entre el 12 y el 17, intervalo en el cual no está nuestro destino, sin embargo, si está en el subárbol que cuelga de su otro hijo, que comprende el intervalo entre el 18 y el 36. Así que avanzamos por esa rama.
Estamos en el nodo 18, también con dos hijos, miramos los intervalos como hasta ahora y avanzamos hasta el 19. Ya estamos en nuestro destino. Como podemos comprobar, hemos avanzado a través de nodos con un solo hijo, y con dos hijos, subiendo niveles hacia arriba, a través de los padres, y hacia abajo, a través de sus hijos.
También hemos trazado el camino más corto entre los dos puntos. He aquí el potencial de esta numeración. Los números que hemos especificado, no son los definitivos, pero si lo es el orden relativo. En un futuro, cada número corresponderá a una dirección de memoria, en la cual tendremos información sobre ese nodo, (Dirección del padre, de los hijos... orientaciones, etc).
REPRESENTACION DE LA ORIENTACION
Para representar la orientación en 2 bits, utilizamos en siguiente esquema. Así, comparando los números, 00, 01, 10, 11, podemos determinar si necesitamos girar a la izquierda o a la derecha una o varias veces, para hacer coincidir la orientación de nuestro robot con la orientación deseada.
FORMATO DE LA INFORMACION DE CADA NODO
Cada nodo con un solo hijo, dispondrá de la siguiente información, compuesta por 4 bytes. Imaginemos que es el primer nodo. Su información comienza en la dirección 0 de la memoria eeprom. El primer byte, solo tiene 2 bits útiles, el B7 indica si es un nodo con 1 hijo (0) o si es un nodo con dos hijos (1).
El B0, nos indica si la salida más cercana a ese nodo es la 4 (según la numeración que hemos indicado antes) representado por un 0 o la 33, representada mediante un 1. El siguiente byte, tiene 6 bits para indicar la dirección del nodo que representaría el limite inferior del
intervalo que hemos explicado antes (LIM1A) y OR1, de dos bits, contiene la orientación de la rama correspondiente a ese intervalo.
El siguiente bytes (LIM1B), contiene el limite superior del intervalo y la misma orientación. El último byte, nos dice la dirección del nodo padre, y su orientación.
 |
Esta es la forma en la que se almacenan los datos de un nodo con 2 hijos. La única diferencia, es que ocupamos 8 bytes en lugar de 4, estando los dos últimos totalmente inutilizados. Esto es debido a que de esta manera, las direcciones son múltiplos de 4, y al poner los limites de los intervalos en cada byte, escribiremos los 6 bits de mayor peso, quedando SIEMPRE los 2 bits de menos peso a 0 (son direcciones múltiplos de 4). Aprovechamos estos dos bits para poner la orientación.
Si queremos extraer solo la dirección, copiamos la información y ponemos a 0 los dos bits de orientación.
Esta forma de desperdiciar un poco de memoria, nos garantiza una facilidad tremenda a la hora de escribir el algoritmo, por lo tanto, no se considera algo negativo, sino todo lo contrario.
Después tenemos que codificar la información de cada nodo, bit a bit, tarea que hay que realizar con sumo cuidado, ya que un error de un solo bit puede afectar el funcionamiento del robot.
Vamos situando la información en memoria, en el orden en que hemos configurado el árbol, y teniendo cuenta el numero de bytes que se reservan para cada tipo de nodo.
De esta forma, el nodo 1 quedaría en la dirección 0, y a partir de ahora, su número será ese, el de su dirección. El siguiente estará en la dirección 4, después en la 8, en la 10, y así sucesivamente (tened en cuenta que usamos numeración hexadecimal). Los nodos pasarán a llamarse según la dirección de memoria en la que comienzan sus datos.
El mapa del laberinto, si cambiamos los números de nodo, y volvemos a dotar al árbol con su forma original, queda de la siguiente manera:
|

Vamos a hacer un ejemplo, de como se codificaría la información de un nodo, y como quedaría representado en memoria. Vamos a tomar el nodo 20. Esto quiere decir que comenzaríamos a escribir estos bytes a partir de la posición 20.
Sabemos que está más cerca de la salida 10, que de la 9C, luego el bit de menos peso, será 0.
También tenemos en cuenta que solo tiene un hijo, así que el bit de más peso será 0. El resto están
inutilizados.
Primer byte: 00000000 => 0x00
El segundo y tercer byte: Sus hijos están comprendidos entre el 24 (00100100)y el AC(10101100), y para ir por esa rama, tendremos que ir por el oeste (11). Segundo byte: 00100111 => 0x27 Tercer byte: 10101111 => 0xAF
El padre es el nodo 1C(00011100), y está situado al este, luego la orientación será 01.
Cuarto byte: 00011101 => 0x1D
Ahora tenemos que repetir esta operación con los 36 nodos.
El mapa de memoria queda representado de la siguiente forma (ya escrito en PBASIC, en forma de directivas para almacenar en memoria los datos en tiempo de grabación).
En el código del programa, como norma general, utilizaré notación hexadecimal. Cada linea representa una casilla o nodo, algunas con 4 bytes, y otras con 6. En cada linea especifico la dirección en la que comienza a copiarse la siguiente información.
DATA @$00, $00, $04, $AC, $00 DATA @$04, $00, $09, $AD, $02 DATA @$08, $80, $16, $AE, $10, $10, $07 DATA @$10, $00, $FF, $FF, $0A
DATA @$14, $00, $1A, $AE, $08
DATA @$18, $00, $1F, $AF, $14
DATA @$1C, $00, $23, $AF, $19
DATA @$20, $00, $27, $AF, $1D
DATA @$24, $00, $2A, $AE, $21
DATA @$28, $00, $2E, $AE, $24
DATA @$2C, $81, $35, $49, $53, $AF, $28
DATA @$34, $01, $38, $4C, $2F
DATA @$38, $01, $3D, $4D, $36
DATA @$3C, $81, $45, $45, $4A, $4E, $3B
DATA @$44, $01, $FF, $FF, $3F
DATA @$48, $01, $4D, $4D, $3C
DATA @$4C, $01, $FF, $FF, $4B
DATA @$50, $81, $60, $AC, $5B, $5F, $2D
DATA @$58, $01, $5C, $5C, $51
DATA @$5C, $01, $FF, $FF, $5A
DATA @$60, $01, $64, $AC, $52
DATA @$64, $81, $70, $AC, $6F, $6F, $62
DATA @$6C, $01, $FF, $FF, $65
DATA @$70, $81, $88, $AC, $79, $85, $66
DATA @$78, $01, $7D, $85, $73
DATA @$7C, $01, $80, $84, $7B
DATA @$80, $01, $87, $87, $7E
DATA @$84, $01, $FF, $FF, $81
DATA @$88, $81, $90, $9C, $A3, $AF, $72
DATA @$90, $01, $95, $9D, $8A
DATA @$94, $01, $99, $9D, $93
DATA @$98, $01, $9D, $9D, $97
DATA @$9C, $01, $FF, $FF, $9B
DATA @$A0, $81, $A8, $A8, $AE, $AE, $89
DATA @$A8, $01, $FF, $FF, $A2
DATA @$AC, $01, $FF, $FF, $A0
NUESTRO ALGORITMO Ya tenemos lo necesario para desarrollar el algoritmo. Nuestro robot en todo momento sabrá en que orientación se encuentra. Se la especificaremos inicialmente, y con cada movimiento la actualizaremos. También en todo momento conocemos en nodo en el que estamos, actualizando este dato cuando avanzamos hacia otro nodo, así como el destino al que vamos, que será en la primera fase el objeto, y en la segunda fase la salida más cercana. Además, tenemos que tener en cuenta que el objeto puede bloquear la salida, y que no podemos atravesarlo, por lo que al llegar a él, nos quedaremos en el nodo anterior, y giraremos si es necesario para encararlo, decidiendo después a que salida nos vamos a dirigir, y volviendo a repetir todo el proceso de la primera fase, para encontrar la salida.
|