DarwinBotsManual
Abrir la app EnglishEN

Un bot que reconoce a su especie

La firma del ADN y una contraseña pública, paso a paso, para que tu bot reserve los disparos para los extraños.

En Un bot que busca comida tu bot aprendió a moverse hacia la comida, y en Un bot que dispara, a quitársela a otro a tiros. Este tutorial agrega la pieza que falta para que muchas copias del mismo bot vivan juntas: saber a quién tenés enfrente, y reservar las balas para los extraños.

El disparo no elige

El disparo no distingue especies: le pega a cualquier bot que se cruce. Un bot nunca se pega con su propio disparo, y un recién nacido está protegido de los disparos de su padre durante sus primeros ciclos; de nadie más. El ADN tampoco puede leer el nombre de la especie: para el motor es un nombre que se hereda (ver Especies y linaje), y no hay ninguna sysvar que lo traiga. Lo más parecido es .totalmyspecies, que cuenta cuántos bots vivos llevan tu nombre: sirve para saber cuántos quedan, no quién tenés enfrente.

Sembrá cuatro copias de este cazador sin filtro — el del tutorial anterior, reducido a lo esencial —, en un mundo chico y sin vegetales:

cond
 *.eye5 0 =
start
 314 rnd .aimdx store
stop

cond
 *.eye5 0 >
start
 -1 .shoot store
stop

En la corrida, a los 20 ciclos ya faltaba uno, y a los 30, otro. Uno de los supervivientes cerró con dos muertes de sus propios hermanos en .kills; al otro lo estaban desangrando de a poco (de 3000 a 2441 de energía, mientras el primero subía a 9175). Sin vegetales que repoblar, una especie así se come a sí misma. (Este mismo bache, con su arreglo, está en Errores frecuentes.)

Las dos señales

Todo lo que un bot sabe del que tiene adelante llega por la vista —y por los choques—, y ninguna de esas cosas es un nombre. Cuando el ojo con foco ve algo, las celdas ref* lo describen: dónde está, cómo se mueve, cuánta energía y cuerpo tiene (Visión). Entre esos datos llega una firma de su ADN: los mismos contadores que tenés en las my*, pero del otro.

La firma no sale de lo que el otro hace, sino del texto de su ADN. .refeye, por ejemplo, dice cuántas veces lee sus ojos su ADN; .refshoot, cuántas veces ordena un disparo; .refup, cuántas veces empuja. Como se cuenta el texto, cuenta aunque ese código nunca se ejecute, y no se puede falsear: escribir a mano las propias my* no cambia lo que ven los demás. Dos bots con el mismo ADN tienen exactamente la misma firma. La comparación más usada —viene de Animal Minimalis, de Numsgil, y la llevan cientos de bots del Bestiario— es .refeye contra tu .myeye.

La otra señal funciona al revés: no la deducís del otro, la publica él. Escribís un número en .out1 y queda ahí: el motor no lo borra nunca. Cualquier bot que te tenga en el ojo con foco lo recibe en su .in1, con el atraso de un ciclo que tienen todos los sentidos. Es un canal público: el 555 de Artemis Minimalis, del Bestiario, es el ejemplo clásico.

SeñalFortalezaDebilidad
La firma (ref* contra my*)No se puede copiarDos ADN distintos pueden contar igual
La contraseña (in1 contra out1)No coincide por casualidadCualquiera que te vea la lee

Vamos con las dos, en orden, porque cada una tapa el hueco de la otra.

Paso 1: la firma

El cazador lee *.eye5 dos veces, así que su .myeye vale 2: esa es su firma. Agregale la comparación al gen que dispara:

' Disparar solo si la firma del otro no coincide con la mia
cond
 *.eye5 0 =
start
 314 rnd .aimdx store
stop

cond
 *.eye5 0 >
 *.refeye *.myeye !=
start
 -1 .shoot store
stop

Qué deberías ver:

  1. Contra un clon (la misma especie, dos copias), ni un disparo. En la corrida quedaron pegados frente a frente —el ojo frontal marcaba más de 20000— con *.refeye y *.myeye en 2, y la energía intacta en 3000 durante 40 ciclos.
  2. Contra un extraño que lee sus ojos una sola vez, la firma no coincide (1 contra 2) y el cazador actúa como siempre: giró hasta verlo, le robó energía hasta matarlo antes del ciclo 25 y cerró en 6160, desde los 3000 iniciales.

Paso 2: las trampas de la firma

La firma es una aproximación, y tiene tres baches:

El arreglo es comparar más de una cifra y disparar si alguna no coincide, con or en la zona de condiciones:

' Disparar si alguna cifra de la firma no coincide
cond
 *.eye5 0 =
start
 314 rnd .aimdx store
stop

cond
 *.eye5 0 >
 *.refeye *.myeye !=
 *.refshoot *.myshoot != or
start
 -1 .shoot store
stop

El falso hermano de arriba escribe .shoot cero veces, así que su .refshoot (0) ya no coincide con tu .myshoot (1): en la corrida quedó muerto antes del ciclo 25, con el cazador cerrando en 6160.

Podés sumar una tercera cifra (.refup, .reftie…): cada una independiente hace más difícil la coincidencia casual.

Paso 3: la contraseña

La contraseña la publica cada bot por su cuenta. Alcanza con publicarla una vez: como .out1 nunca se borra y arranca en 0, «mientras valga 0» es «la primera vez». Después, antes de disparar, comparás *.in1 con tu propio *.out1.

' Publicar el codigo de especie, una sola vez
cond
 *.out1 0 =
start
 555 .out1 store
stop

cond
 *.eye5 0 =
start
 314 rnd .aimdx store
stop

' Disparar al que no publica mi codigo
cond
 *.eye5 0 >
 *.in1 *.out1 !=
start
 -1 .shoot store
stop

Dos cuidados. Primero, *.in1 vale 0 tanto si no estás viendo a nadie como si el otro no publica nada: el *.eye5 0 > es el que avisa que hay alguien enfrente. Segundo, elegí un código distinto de 0, que es lo que «publica» cualquier bot que no usa el canal.

Qué deberías ver:

  1. Contra un extraño que no publica nada, la contraseña funciona como una firma más: en la corrida lo cazó igual que antes y cerró en 6152.
  2. Contra un espía, la contraseña muestra su precio: un bot que se limita a copiar en su .out1 lo que lee en *.in1 publica tu código en cuanto te ve. En la corrida, el espía ya anunciaba 555 en el ciclo 5.
  3. Y la consecuencia: contra un intruso que publica tu código, un bot que solo mira contraseñas no dispara. El intruso pasó 40 ciclos a la vista, con la energía intacta.

Es un canal público: sirve para elegir a los tuyos, no para guardar un secreto.

Paso 4: el bot completo

Combinadas, cada señal tapa el hueco de la otra. Pero fijate cómo: hay que disparar si alguna no coincide, con or. Si exigieras que fallen las dos, cada trampa seguiría abierta: al falso hermano lo salvaría la firma, al intruso con el código robado lo salvaría la contraseña.

EnfrenteFirmaContraseñaDispara
Un cloncoincidecoincideno
Un extraño que cuenta igualcoincidenosí
Un intruso con el código robadonocoincidesí

El bot completo —el esqueleto es el de Animal Minimalis, más la contraseña— queda así:

' Publicar el codigo de especie, una sola vez
cond
 *.out1 0 =
start
 555 .out1 store
stop

' Algo adelante que no es de los mios: perseguirlo copiando su velocidad
cond
 *.eye5 0 >
 *.refeye *.myeye !=
start
 *.refveldx .dx store
 *.refvelup 30 add .up store
stop

' Extraño cerca: firma o contrasena que no coincidan
cond
 *.eye5 50 >
 *.refeye *.myeye !=
 *.refshoot *.myshoot != or
 *.in1 *.out1 != or
start
 -1 .shoot store
stop

' Nada adelante, o alguien de los mios: girar buscando
cond
 *.eye5 0 =
 *.refeye *.myeye = or
start
 314 rnd .aimdx store
stop

' Reproducirse cuando sobra energia (10 por ciento para el hijo)
cond
 *.nrg 20000 >
start
 10 .repro store
stop

Cada gen hace una cosa: publicar el código, perseguir a los extraños copiando su velocidad, dispararles cuando están cerca, girar cuando no hay nada —o lo que hay es un hermano—, y dividirse cuando sobra energía. El hijo nace con el mismo ADN, o sea con la misma firma, y publica su 555 en su primer ciclo; mientras tanto, los disparos de su padre no le pegan.

Qué deberías ver:

  1. Contra sus clones, ni un disparo. En la corrida, dos copias giraron cada una por su lado; en el ciclo 35 una tuvo a la otra de frente —*.refeye en 3, *.in1 en 555— y siguió su camino, con la energía intacta.
  2. Contra el intruso de la contraseña robada, la firma lo delató: lo persiguió, le fue sacando energía y quedó muerto antes del ciclo 35, con el bot final cerrando en 5958 desde los 3000 iniciales.
  3. Contra un extraño que cuenta igual —tres lecturas de ojos y un disparo, como el tuyo, pero sin publicar código—, la contraseña lo delató: en cuanto lo vio, empezó a dispararle, y en 60 ciclos lo bajó de 3000 a 2244 de energía.

El bloque entero pasa el lint sin avisos. Cambiale el 555 por un número tuyo (que no sea 0) y tiene que seguir andando igual.

Qué probar después

El espía completo. Las dos señales juntas todavía se pueden engañar: un bot que copie tu contraseña y que además, por casualidad o por diseño, cuente igual que vos engaña al bot completo. Conseguirlo por azar es difícil; cuantas más señales independientes compares, más difícil el engaño.

Parientes que mutaron. Con las mutaciones encendidas (Mutaciones), cada mutación rehace la firma del bot: un descendiente puede quedar con otra cuenta y empezar a recibir fuego amigo de sus parientes. Una mutación también puede tocarle el 555 o el gen que lo publica. Las dos señales derivan con la evolución; mirá Especies y linaje.

Sin verse: por lazos. Un bot atado a otro lo reconoce con .trefeye en vez de refeye, y comparado con %= admite hasta un 10 % de diferencia, útil si esperás parientes que mutaron poco. Para armar lazos, el tutorial es Un multibot.

Contraseñas escondidas. Con .memloc podés espiar cualquier celda del bot que ves y guardar tu código en una variable privada, en vez de publicarlo en out1 (ver Visión). Spoiler: un espía con .memloc también la encuentra: la vista de DarwinBots no tiene secretos.