A la mayoría de los personajes simulados se les dice qué hacer. Una máquina de estados nombra los estados y cada transición entre ellos. Un árbol de comportamiento nombra las ramas en orden de prioridad. Ambos funcionan, y ambos fallan en la misma dirección: cada nuevo recurso, estación o interrupción multiplica los bordes que alguien tiene que crear a mano.
La planificación de la acción orientada a objetivos invierte la autoría. Declaras lo que un personaje quiere como condición en el mundo, declaras cada acción como una condición previa que necesita y un efecto que causa, y dejas que una búsqueda arme la secuencia. La secuencia nunca está escrita. Quería saber qué poca estructura escrita necesita realmente una ciudad en funcionamiento, así que construí una: seis especialistas, nueve estaciones, un mundo compartido y un planificador que se repite en el momento en que la realidad deja de coincidir con el plan.
Un objetivo es una condición, no un guión.
El modelo son tres declaraciones y nada más.
Un fact es un número en uno de dos grupos. Los datos mundiales (🌐) son compartidos por todos:tools,iron,bread. Los hechos de los agentes (🎒) pertenecen a un personaje: la madera que llevan en los brazos, la comida que llevan. Una clave faltante se lee como cero. Esa es toda la representación del estado: dos mapas planos de cadena a número, sin entidades, sin propiedad, sin objetos de inventario.
A goal es una lista de condiciones sobre esos hechos, y una condición es solo fact >= min. El cocinero quiere 🎒 fed ≥ 1. El herrero del pueblo quiere 🌐 tools ≥ 2. No hay negación ni límite superior en el lenguaje, lo cual es una restricción real más que una omisión: obliga a que cada cuota se exprese como algo que se acumula.
Un action es un operador: una estación en la que situarse, una duración, un coste, condiciones previas, efectos.lightFire necesita 🎒 wood ≥ 1; gasta esa madera y establece 🌐 fireLit = 1. Nada en esa declaración menciona cortar y nada menciona comer.
El planificador se une a ellos. Es un avance A* sobre los estados del mundo: cada nodo lleva una copia completa de ambos grupos de hechos más la cadena de acciones que lo produjeron,g acumula el costo de la acción y la heurística h es simplemente el número de condiciones objetivo aún sin cumplir. Los sucesores de un nodo son las acciones cuyas condiciones previas se cumplen en el estado de ese nodo. Un conjunto cerrado codificado en un hash ordenado de ambos grupos impide volver a visitar un estado alcanzado por una ruta diferente, y la expansión tiene un límite de 5000 nodos, después de lo cual el planificador no devuelve nada en lugar de detener el marco.
Esa heurística es deliberadamente ingenua. Cuenta las condiciones no cumplidas en lugar de estimar el trabajo necesario para cumplirlas, y sólo es admisible mientras ninguna acción única cierre dos condiciones a la vez. Para una ciudad de este tamaño eso es suficiente, y una búsqueda legible vale más en un artefacto explicativo que un límite más estricto que nadie puede leer fuera de la pantalla.
Observa cómo se arma una búsqueda
MISMA EJECUCIÓN / EN VIVOUn plan que desmantela su propia condición previa
El escenario más pequeño tiene un personaje. El cocinero quiere 🎒 fed ≥ 1, y las cuatro acciones disponibles son chopWood, lightFire, cookMeal y eatMeal. El planificador devuelve esas cuatro acciones en ese orden, no porque alguien lo haya escrito, sino porque es la única cadena cuyas precondiciones encajan.
La parte interesante es cookMeal. Requiere 🌐 fireLit ≥ 1y sus efectos son🎒 meal +1y🌐 fireLit = 0. Cocinar consume el fuego que necesitaba. Entonces, cuando el ciclo se reinicia, el cocinero no repite una rutina almacenada; una nueva búsqueda va contra los hechos actuales, encuentra el fuego apagado y las armas vacías, y regresa a los mismos cuatro pasos por una nueva razón.
La ejecución añade una regla más. En el primer tic de actuación, cada condición previa se compara nuevamente con el mundo real, porque el plan se construyó con una instantánea que otros personajes pueden haber invalidado. Si la prueba falla, el personaje abandona el plan, pasa al modo inactivo y registra el motivo. Una vez que la acción está realmente en marcha, es atómica: no hay más controles, los efectos se aplican al finalizar. Ésa es la unión donde un planificador se convierte en una simulación: buscar sobre una instantánea, verificar con la realidad, replanificar sobre la diferencia.
Lee el plan de un personaje mientras se ejecuta.
MISMA EJECUCIÓN / EN VIVOLa espera es un resultado de búsqueda, no un estado
Dos personajes comparten el siguiente escenario. La fundición extrae mineral y lo funde hasta obtener 🌐 ironIngot , un hecho mundial compartido. El herrero quiere 🌐 tools ≥ 1, y la única ruta hacia una herramienta pasa por collectIron, que requiere 🌐 ironIngot ≥ 1.
Al inicio del día no hay lingotes. La búsqueda del herrero amplía lo que puede, lo cierra y termina sin plan. No existe un comportamiento inactivo creado al que recurrir, por lo que el personaje entra en una fase de espera, muestra el motivo palabra por palabra como No hay plan viable: esperando a que el mundo cambie y vuelve a intentarlo aproximadamente una vez por segundo simulado. Cuando el primer lingote de la fundición cae en el grupo compartido, el siguiente reintento tiene éxito y el herrero camina hacia el horno.
Nadie escribió espera la fundición. Ninguno de los personajes sabe que el otro existe. La dependencia es una propiedad del hecho que ambos nombran, y la espera es la sombra observable de una búsqueda fallida.
Mira cómo se forma la dependencia entre dos desconocidos
MISMA EJECUCIÓN / EN VIVOSeis especialistas, doce deseos, un mundo compartido
Toda la ciudad hace funcionar la misma maquinaria a una escala en la que empieza a comportarse mal de manera útil. El minero almacena mineral, el fundidor convierte el mineral en hierro, el herrero convierte el hierro en herramientas y el granjero y el carpintero acceden a 🌐 tools ≥ 1, por lo que un herrero desbloquea dos ramas al mismo tiempo. El panadero se sienta dos pasos detrás del granjero y es el último en tener algo que hacer.
Ahora cada uno de los seis lleva dos objetivos en lugar de uno: la cuota de su oficio y un hambre que sube según su propio reloj. Hay una mesa, el pan se recoge en el horno y se come en la mesa, y nadie tiene programado comer. Cada personaje decide, una y otra vez, cuál de sus dos deseos vale la pena planificar ahora mismo; la siguiente sección desarma esa decisión.
Dos detalles hacen que la celosía se mantenga bajo esa presión. En primer lugar, la contienda se maneja con optimismo. No hay reservas, bloqueos ni colas: dos personajes pueden planear tomar la misma unidad de hierro, y el que llega en segundo lugar no pasa la nueva verificación y vuelve a planificar. Esto es más barato que un protocolo de reclamación y produce un comportamiento más atractivo, porque el perdedor reconsidera visiblemente en lugar de quedarse estancado en una cola.
En segundo lugar, los objetivos iniciales se formulan en función de recuentos y no de grupos. El objetivo del minero es 🌐 oreMined ≥ 3, no 🌐 ore ≥ 3, porque el fundidor drena el depósito de mineral aguas abajo; un objetivo establecido frente a un consumible nunca puede quedar satisfecho, por lo que el minero minaría para siempre. Separar un recuento monótono del stock drenable es la solución más pequeña, y es la única decisión de diseño que no habría predicho antes de ejecutarlo. El hambre lleva esa lección un paso más allá: en cuanto seis personajes comen del depósito de pan compartido, la cuota del panadero tiene que ser su propio recuento 🎒 breadBaked ≥ 4, porque los panes por los que se le mide dejan de existir al minuto de salir del horno.
El día igual se cierra. Todas las cuotas se cumplen dentro del primer 56 % del día —la del minero cerca de la cuarta parte, la del panadero al final— y todos comen: cuatro de ellos una vez, y el granjero y el panadero tres veces cada uno, porque sus dependencias aguas arriba los dejan inactivos el tiempo suficiente para que el hambre siga ganando. Nada de ese orden está programado. Lo cual responde la pregunta que la primera versión de este artículo dejó abierta: la contención optimista sí se mantiene una vez que la elección de qué querer también se busca, y se mantiene de forma observable.
Al amanecer, cada hecho mundial se restablece a la semilla del escenario, cada insistencia vuelve a su valor inicial y cada personaje se reconstruye, salvo por una reserva inicial de dos panes, sin la cual el hambre es inalcanzable hasta que exista el primer pan, y un deseo inalcanzable pasa la mañana fijando en silencio su insistencia en el techo.
Deja que seis planes interfieran entre sí.
MISMA EJECUCIÓN / EN VIVOQuerer también es una búsqueda
Ahora un personaje sostiene un conjunto de objetivos en lugar de uno solo, y cada objetivo lleva una insistencia: un número entre 0 y 1 que dice qué tan fuerte suena en este momento. La insistencia no se escribe cuadro por cuadro; cada objetivo declara una regla de deriva y la regla se encarga de hablar.
Una necesidad sube. El hambre se acumula a una tasa fija por segundo simulado, se limita en 1 y vuelve a su valor inicial en cuanto el objetivo se cumple, momento en el que las condiciones se gastan de verdad, así que la comida se consume en lugar de quedar marcada para siempre. Las tasas están escalonadas entre los seis de la ciudad, de 0.014 a 0.024, y esa es toda la razón por la que las comidas se reparten a lo largo del día en vez de que seis personas coincidan en la mesa.
Una cuota es la imagen inversa: insistencia = urgencia × avance del día × déficit, donde el déficit es la fracción del objetivo que sigue sin cumplirse. Por eso una cuota está callada al amanecer aunque no haya nada hecho, se vuelve más fuerte a medida que el día se consume y se apaga a medida que se llena. La presión de la fecha límite no es un caso especial en el ejecutor; es una multiplicación.
Elegir entre ellos es una sola línea, y lo interesante es el segundo término:
puntaje = insistencia − 0.02 × costo del plan
El costo del plan es real: puntuar un objetivo significa ejecutar el planificador contra él desde el estado actual del personaje. Un deseo que resulta caro desde aquí queda descontado exactamente por eso, y un deseo sin ningún plan viable no puntúa y sale de la votación, que es la forma en que «me estoy muriendo de hambre pero no hay pan en ninguna parte» se resuelve como sigue trabajando y no como parálisis. El peso 0.02 es deliberadamente pequeño: el costo rompe empates, no anula una necesidad genuina.
Dos guardas evitan que esto se convierta en un tic. Un retador tiene que superar al titular por más de 0.15 para tomar el control, así que los objetivos que rondan puntajes parecidos no se pasan al personaje de un lado a otro en cada tic; y cuando el cambio ocurre, el inspector deja constancia del motivo en texto plano. Esa línea se compone en tiempo de ejecución y aparece en inglés incluso con la interfaz en español: Hunger (0.72) overtook Smelt iron (0.51) («Hambre (0.72) superó a Fundir hierro (0.51)»). Y el arbitraje solo corre en puntos seguros: al entrar en inactivo, en cada reintento de espera y después de una acción terminada. Nunca a mitad de una acción, nunca a mitad de un trayecto. Por debajo de 0.05 en todo, descansan.
El escenario más pequeño para ver esto son tres especialistas y una economía de un solo pan. El fundidor quiere 🎒 ironSmelted ≥ 3 y el herrero quiere 🎒 toolsForged ≥ 2, ambos recuentos, según la regla que enseñó la ciudad. El panadero rompe esa regla a propósito. Su cuota es 🌐 bread ≥ 4: un depósito, drenable, formulado exactamente contra el consumible contra el que dije que nunca hay que formular un objetivo. Porque aquí ese es el trabajo. Mantener el estante surtido es un nivel de existencias, no un recuento de producción, y que el fundidor y el herrero se coman su pan no es un inconveniente para su objetivo: es el mecanismo que lo vuelve a abrir. La misma formulación que hacía que el minero minara para siempre hace que el panadero reponga para siempre, y para siempre es el comportamiento correcto para un estante.
Mira cómo a un deseo lo callan a gritos
MISMA EJECUCIÓN / EN VIVOEl mecanismo que especifiqué y el comportamiento que no escribí
El mecanismo original es pequeño y específico: dos grupos de hechos con alcance con un único operador de comparación, un A* directo cuya heurística es un recuento de condiciones no cumplidas, instantáneas del tiempo del plan verificadas nuevamente en el momento de la ejecución, una votación de insistencia menos costo con un margen de histéresis que decide qué planificar a continuación, y ninguna capa de coordinación entre personajes.
El comportamiento observable es lo que no escribí. Una herramienta completa desbloquea dos profesiones no relacionadas en el mismo segundo. Un personaje se queda quieto con una razón visible adjunta. Un panadero repone un estante bajo demanda durante todo un día, sin que la demanda esté modelada en ninguna parte: reacciona a un número que mueven los almuerzos de los demás. Los personajes toman descansos en los huecos que les dejan sus dependencias, y los que no tienen a nadie aguas arriba comen una vez y siguen con lo suyo. La mañana del pueblo es lenta y la tarde es ocupada, y ninguno de los dos ritmos está programado en ninguna parte.
El siguiente experimento es la nueva brecha honesta, y es espacial. Cada personaje aquí camina en línea recta hasta la estación que necesita: a través de las paredes, a través del horno de fundición, a través de los demás. No hay búsqueda de caminos y no hay colas: dos personas que usan la forja en el mismo instante simplemente ocupan la misma casilla, lo cual se ve bien de reojo y se cae en cuanto uno se fija. La versión interesante de esa solución no es un A sobre una cuadrícula; es convertir la ocupación en un hecho como cualquier otro, para que la forja está ocupada* sea algo que el planificador pueda ver, costear y rodear, y para que hacer fila se vuelva otro resultado de búsqueda en lugar de otro estado escrito a mano.