Ejecución y costos
Cuándo corre el ADN dentro del ciclo, en qué orden, qué ve de los sentidos y cuánta energía cobra cada instrucción.
El ADN de un bot no es un programa que arranca una vez y queda corriendo: es una receta que el mundo vuelve a leer entera, de arriba abajo, en cada ciclo. Esta página cuenta en qué momento del ciclo pasa eso, qué ve el bot cuando lee sus sentidos, en qué orden corren los genes y cuánta energía le cuesta cada instrucción.
El ADN corre al principio del ciclo
Cada ciclo de la simulación (lo ves completo en El ciclo y el orden de las acciones) empieza, después de unas cuentas generales, con la fase de ADN: el motor recorre los bots vivos uno por uno y ejecuta el ADN de cada uno. Recién cuando terminaron todos se mueven los disparos, se aplican las fuerzas, se integran las posiciones, miran los ojos y se resuelven las acciones (disparar, reproducirse, fabricar escudo…).
Eso tiene dos consecuencias que conviene tener siempre en la cabeza:
- Lo que leés viene del ciclo anterior. Los ojos, el contacto, la velocidad, la energía y demás sentidos se escriben durante la parte física del ciclo N−1; el ADN del ciclo N lee esos valores.
- Lo que escribís se aplica después. Un
10 .up storedeja el 10 en memoria en el acto, pero el empuje se aplica más tarde, en la parte física del mismo ciclo. Su efecto en los sentidos lo vas a ver recién en el ciclo siguiente.
Los cadáveres no ejecutan ADN. Un bot que nace durante el ciclo N corre su ADN por primera vez en el ciclo N+1.
Un ciclo de retraso, comprobado
Este bot empuja hacia adelante con .up y, antes, anota en la posición 52 la velocidad que lee en .vel:
' Empuja hacia adelante y anota la velocidad que lee
cond
start
*.vel 52 store
10 .up store
stop
endCorriéndolo, la posición 52 va siempre un paso atrás de la velocidad real:
| Ciclo | .vel al terminar el ciclo | Lo que el ADN anotó en 52 |
|---|---|---|
| 1 | 7 | 0 |
| 2 | 13 | 7 |
| 3 | 20 | 13 |
| 4 | 26 | 20 |
En el ciclo 1 el bot ya empujó, pero cuando su ADN leyó .vel el empuje todavía no se había aplicado. Pasa lo mismo con .nrg: el bot ve la energía con la que terminó el ciclo anterior, no la que le queda mientras su propio ADN la va gastando. Un bot recién sembrado en el mundo lee además los sentidos en 0 durante su primer ciclo, porque todavía no pasó por ninguna parte física.
Todo el ADN, cada ciclo, en orden
En cada ciclo el intérprete arranca en la primera instrucción y avanza hasta el end final (o hasta el final del archivo). No hay saltos ni bucles: los genes no se llaman entre sí y nada vuelve atrás. Cada instrucción se mira a lo sumo una vez por ciclo, y los genes se recorren en el orden en que están escritos.
Un gen cuya condición es falsa no se salta de un golpe: el intérprete sigue pasando por sus instrucciones, pero las ignora una por una hasta el próximo marcador (cond, start, else o stop). Los detalles de esos marcadores están en Genes: cond, start, else y stop.
Las pilas (La pila entera y la booleana) se vacían al empezar el ADN de cada bot: nada queda en ellas de un ciclo a otro ni pasa de un bot a otro. Lo que sí persiste es la memoria, y los stores escriben en ella en el momento (Escribir en la memoria). Por eso un gen ve lo que escribió un gen anterior en el mismo ciclo, pero no lo que va a escribir uno posterior:
' El gen 1 cuenta; el gen 2 copia el contador
cond
start
*50 1 add 50 store
stop
cond
start
*50 51 store
stop
endCon este orden, al final de cada ciclo 50 y 51 valen lo mismo (1 y 1, 2 y 2, 3 y 3…). Si invertís los dos genes, la copia lee el valor viejo y 51 queda siempre uno por detrás de 50 (1 y 0, 2 y 1, 3 y 2…).
El ADN de un bot solo toca su propia memoria y su energía; no lee ni escribe nada de otros bots durante esta fase. Por eso el orden entre bots no cambia lo que calcula cada ADN. (Lo único compartido es el generador de números aleatorios: si usás rnd, el número que te toca depende de cuántos bots lo usaron antes que vos.)
Cuánto cuesta cada instrucción
Cada instrucción ejecutada descuenta energía del bot en el momento, según su clase. Los precios son parámetros del escenario (página Parámetros: Costos) y todos se multiplican por el Multiplicador de costos:
| Clase | Ejemplos | Parámetro |
|---|---|---|
| Número | 10, .up (como dirección) | Número |
| Lectura de memoria | *.eye5, *50 | Lectura *.número |
| Operador básico | add, dup, rnd | Comando básico |
| Operador avanzado | angle, dist, sqr | Comando avanzado |
| Operador de bits | &, << | Comando de bits |
| Condición | >, =, %= | Condición |
| Lógico | and, not, dropbool | Lógica |
| Store | store, inc… | Store (ver abajo) |
| Marcador de gen | cond, start, else, stop | Control de flujo |
Algunas reglas finas:
- Lo que se ignora no se cobra. Dentro de un gen apagado, números, lecturas, operadores y stores no cuestan nada. Lo que sí se cobra siempre es la parte de condiciones (que hay que evaluar para saber si el gen corre) y los marcadores
cond,start,elseystop, que se ejecutan aunque el gen esté apagado. - Un store que no escribe no cuesta. Si una condición en línea dejó falso arriba de la pila booleana (Condiciones en línea), el store no corre y no se cobra. Un store a la dirección 0 tampoco hace nada ni cuesta.
- No todos los stores cuestan lo mismo.
storepaga el precio entero;incydec, la décima parte;addstore,substore,multstore,divstore,ceilstoreyfloorstore, la quinta;rndstore,sgnstoreysqrstore, la séptima;absstoreynegstore, la octava. - Gratis:
debugintydebugbool, que solo sirven para mirar. - Sin piso. El intérprete resta sin mirar el saldo: la energía puede quedar negativa durante la fase de ADN. La muerte por falta de energía se decide más adelante en el ciclo (Muerte y cadáveres).
Un ejemplo con números
' Un gen cuya condición es falsa
cond
0 1 =
start
1 50 store
2 51 store
stop
endCon número, condición, store y marcadores a 1 cada uno, este bot pierde 6 de energía por ciclo: 2 números y una condición en la parte de cond, más los tres marcadores. El cuerpo no se cobra. Si cambiás 0 1 = por 1 1 =, el cuerpo corre y el gasto sube a 12: se suman 4 números y 2 stores.
El ADN largo cuesta aunque no corra
Además de lo que cobra cada instrucción ejecutada, el mantenimiento de cada ciclo cobra por el largo del ADN, se ejecute o no. El precio es el parámetro ADN por ciclo, y se paga una vez por cada instrucción del genoma sin contar el end final. Un bot como cond start 1 50 store 2 51 store stop end tiene 9 instrucciones más el end: con ese costo en 1 pierde 9 por ciclo, y los perdería igual con todos sus genes apagados. Podés consultar el largo de tu propio ADN en .dnalen, que cuenta también el end (para ese bot vale 10).
El largo vuelve a pesar al reproducirse: el padre paga el costo de Copia del ADN una vez por cada instrucción del genoma (esta vez contando el end) al copiarlo para el hijo (Reproducción). Con estos dos costos encendidos, cada instrucción que sobra es energía que el bot no usa para otra cosa.
¿Hay un límite de instrucciones?
No hay un tope de energía ni de tiempo: un bot ejecuta todo su ADN cada ciclo aunque se quede sin energía en el camino. El único límite es de posición: el intérprete mira como mucho las primeras 32000 instrucciones del genoma, y lo que esté más allá nunca corre. Como no hay bucles, ningún ADN puede trabar la simulación.
Qué valores se usan
Los costos dependen del escenario. Las reglas F1, las de las competencias (en Experimentar las aplicás con «Ajustes F1»), cobran 0,04 por store y 0,004 por condición y dejan en 0 los demás costos del ADN, incluido el del largo. Con esas reglas, diez stores por ciclo le cuestan a un bot 0,4 de energía por ciclo; el largo del genoma, nada.
El Multiplicador de costos puede moverse solo si activás el Ajuste dinámico de costos (Parámetros: Costos dinámicos): el motor lo sube o lo baja para llevar la población a un objetivo, y todos los precios de esta página cambian con él. Cómo encaja todo esto con el resto de los gastos del bot está en Energía, cuerpo y desechos.