Variables con def
Cómo ponerle nombre a una dirección de memoria o a un número con def, cómo se resuelven esos nombres y qué trampas tiene.
Escribir 50 inc para contar algo funciona, pero a la tercera dirección suelta ya no sabés qué era cada una. La línea def le pone nombre a un número: después, en cualquier parte del bot, escribís .nombre y el cargador lo cambia por ese número.
' Un contador en una variable propia
def pasos 50
cond
start
.pasos inc
stopEste bot suma 1 a la celda 50 en cada ciclo: .pasos inc es exactamente lo mismo que 50 inc. Lo comprobamos corriéndolo: después de cinco ciclos la celda 50 vale 5.
Cómo se escribe
La forma es def nombre número, sola en su línea:
defen minúsculas, al principio de la línea.DefoDEFno cuentan: esa línea se lee como ADN común y sus palabras se vuelven ceros (ver Números y direcciones).- Un espacio (o un tabulador) entre
defy el nombre, y otro entre el nombre y el número. - El número es un entero entre −32768 y 32767. Puede ir un comentario con
'después. - Una línea
defno produce ninguna instrucción: no ocupa lugar en el ADN, no cuesta energía y no cuenta en.dnalen.
Los def se ponen arriba de todo, antes del primer gen, por una razón que sigue.
Cómo se resuelven los nombres
El cargador lee el archivo de arriba hacia abajo y traduce cada palabra en el momento en que la lee. Cuando encuentra .algo:
- Busca una sysvar llamada
algo, sin distinguir mayúsculas:.UP,.Upy.upson la misma. - Después busca entre tus
defya leídos, esta vez distinguiendo mayúsculas:.Pasosno es.pasos. - Si hay coincidencia en los dos lados, gana tu
def. Si hay dosdefcon el mismo nombre, gana el último. - Si no encuentra nada,
.algovale 0. No hay error ni aviso al cargar.
Dos consecuencias prácticas:
- Un
defpuesto más abajo que su uso no sirve. Si un gen usa.pasosy eldef pasos 50aparece después, ese.pasosya se tradujo como 0. - El punto es obligatorio. Sin punto,
pasoses una palabra desconocida y vale 0. Con asterisco y punto,*.pasos, leés lo que hay guardado en la celda (ver*).
Que un nombre «no exista» y valga 0 parece inofensivo, pero no lo es: en un store, la dirección 0 no hace nada, y en una lectura *0 lee la celda 1000. Un error de tipeo en un nombre deja al gen escribiendo en ningún lado (ver Números y direcciones).
Un def es solo un número
El cargador no sabe si tu def es una dirección o una constante: guarda un número y nada más. Eso te deja usar def para las dos cosas. Este bot usa reloj como dirección y giro como constante:
' Gira un cuarto de vuelta cada 20 ciclos
def reloj 60
def giro 314
cond
start
.reloj inc
stop
cond
*.reloj 20 >=
start
0 .reloj store
.giro .aimdx store
stop.reloj inc incrementa la celda 60; *.reloj lee su valor; .giro apila directamente el número 314, que es lo que se guarda en .aimdx. Al correrlo, la celda 60 cuenta de 0 a 19, vuelve a 0, y en ese ciclo el .aim del bot baja 314 (un cuarto de vuelta hacia la derecha, porque la vuelta entera es 1256).
LoveBot F2, de Moonfisher, usa el mismo truco para dejarle una «llave» a sus hijos en la memoria genética:
' Fragmento de LoveBot F2 (Moonfisher, 2008)
def original 971
def origkey 1234
cond
*.robage 2 <
start
.origkey .original store
stoporiginal es una dirección (la 971, que se hereda: ver Memoria libre y epigenética) y origkey es una constante. El gen guarda 1234 en la 971 durante los dos primeros ciclos de vida.
Como es solo un número, el def puede valer cualquier cosa en ±32767. Si lo usás como dirección y cae fuera de 1..1000, se ajusta igual que cualquier dirección (ver Números y direcciones): def x 1050 y def x -50 terminan los dos en la celda 50. El valor tiene que ser un número escrito con cifras: def x .up no copia la dirección de .up, vale 0. El El editor de ADN lo marca.
Un def que pisa una sysvar
Si llamás a tu variable igual que una sysvar, tu def gana en todo el bot. Acá .up deja de ser la orden de avanzar:
def up 50
cond
start
10 .up store
stopEl bot no se mueve: el 10 va a la celda 50, no a la 1 (.up). Y como los def distinguen mayúsculas y las sysvars no, en ese mismo bot .UP sigue siendo la sysvar de verdad. Es una fuente de confusión segura; el lint de la app lo marca como aviso. Elegí nombres que no choquen con la lista de sysvars.
Nombres sin control
El cargador no revisa el nombre. Puntos, cifras o símbolos valen: def a.b 70 o def 5 70 definen variables legales, que se usan como .a.b y .5. Ojo con el último: .5 sin def no es la dirección 5, vale 0 (las direcciones van sin punto).
Más raro todavía: cualquier línea que empiece con las letras def se toma como un def. El cargador descarta los cuatro primeros caracteres y lee lo que queda. Una línea como esta:
defensa 50define una variable llamada nsa con el valor 50. Si alguna vez un bot hace cosas inexplicables, revisá que ninguna línea empiece con «def» por accidente. El editor también te avisa cuando una línea se lee como def.
use: una palabra muerta
Algunos bots viejos del foro traen líneas como use NewMove. En esta versión use no hace nada especial: cada palabra se lee como ADN común y, al no ser comandos ni números, valen 0. Si la línea está antes del primer gen, esos ceros no se ejecutan nunca; si está dentro de un gen, apilan ceros. Podés borrarlas sin miedo.
Límites y errores que impiden cargar
| Caso | Qué pasa |
|---|---|
def x sin número, o def solo | El bot entero no carga. |
Número fuera de −32768…32767 (def x 40000) | El bot entero no carga. |
Más de 1000 def | El bot entero no carga. |
Dos def con el mismo nombre | Carga; gana el último. |
def con un número fuera de 1..1000 | Carga; usado como dirección, se ajusta a 1..1000. |
Rarezas heredadas del 2.48.32
Dos comportamientos curiosos del original, uno conservado y otro corregido:
- Se pierde el primer token (se conserva). Si el bot tiene algún
defy lo primero del ADN no escond,start,elsenistop(por ejemplo, un número suelto antes del primer gen), ese primer token desaparece. Como lo que está antes del primer gen no se ejecuta, en la práctica solo lo notás en que.dnalenda uno menos. Si empezás concond, no pasa nada. Más en La estructura de un bot. - Un bot hecho solo de
def(corregido). En el DarwinBots original, un archivo condefy ningún gen trababa una parte de cada ciclo de la simulación. En esta versión el bot simplemente vive sin hacer nada.
Por último, los nombres existen solo en tu archivo. Cuando la simulación guarda un bot como .txt (ver El formato .txt), el ADN sale ya traducido: cada .pasos aparece como 50, sin los def.