Simulación Basada en Agentes · Tema 15

Espacios continuos

Coordenadas reales y movimiento libre: medir en lugar de contar, deslizar en lugar de saltar.

01 · Punto de partida

El mundo sin casillas

En el Tema 14 el mundo era una grilla y moverse era saltar de celda en celda. Pero una bandada no salta por baldosas, un peatón no pisa el centro de cada casilla, un auto no dobla en 90°. El espacio continuo guarda posiciones reales (0,37, no celda 3) y deja deslizar con cualquier rumbo y cualquier paso.

Esa libertad da realismo y nueva responsabilidad: la distancia es euclídea, los choques son solapamientos suaves y el paso gigante ya no rebota en una celda sino que atraviesa cuerpos sin registrarlos.

  • ¿Con qué precisión se guarda cada posición?
  • ¿Qué distancia cuenta como contacto si no hay celdas?
  • ¿Qué impide que dos cuerpos se solapen?
  • ¿Qué borde frena un desliz sin casillas?

02 · Definición

Posición, distancia y desliz

Todo mundo libre combina tres piezas, del punto al movimiento:

·

Posición

El par real (x, y) en [0, 1]. Dos agentes pueden estar a 0,001 sin compartir nada: no hay casilla que los iguale.

⟷

Distancia

La euclídea con hipotenusa: cerca es número, no celda lindera. Define contactos, contagios y frenos.

≋

Desliz

El vector paso por dirección con cualquier ángulo. El rumbo ya no es cruz: son 360° reales.

El mismo continuo en cada dominio.
MundoPosiciónContacto típico
Bandadapunto libre en el cieloseparación si dist < cuerpo
Multitudcuerpo con radioempuje suave, no rebote de celda
Tráficoauto en carril realfrenar por hueco en metros
Epidemiaencuentro cercanocontacto si dist < 2 m un rato

03 · Contraste

Discreto que cuenta frente a continuo que mide

La casilla ordena gratis; el continuo mide exacto pero exige resolver solapamientos. Elegir uno es elegir qué artefacto se acepta.

Espacio discreto

Casillas que ordenan

Saltar es barato y chocar es binario: libre u ocupada. Ideal para butacas, lotes y Vida, pero escalona diagonales y giros.

Espacio continuo

Reales que deslizan

Deslizar es suave y chocar es gradual: si dist < dmin → separar. Ideal para bandadas y multitudes, pero cada par cuesta y el paso manda.

Coordenada real
Flotante en rango continuo: 0,37 vale distinto que 0,38. La resolución es infinita hasta que el paso la limita.
Espacio personal
Distancia mínima deseada (dmin): por debajo hay incomodidad y empuje. Reemplaza la exclusiva de celda.
Solapamiento
Par con distancia menor al cuerpo o al dmin. No es error de mapa: es la señal para separar.
Paso temporal
Cuánto avanza por ronda (dt × velocidad). Si supera el cuerpo, atraviesa sin tocar: túnel por paso gigante.

04 · Ciclo

El paso que desliza y separa

Cada ronda integra movimiento y resuelve cercanías, en este orden:

percibir→deslizar→separar
  1. 1
    Percibir vecinos reales.

    Listar por distancia euclídea dentro del radio (Tema 13), sin celdas.

  2. 2
    Deslizar la posición.

    Sumar paso por dirección y aplicar borde continuo: muros con tope, toro con módulo (Tema 7).

  3. 3
    Separar solapados.

    Empujar suave a quienes quedaron bajo el espacio personal, antes de decidir el próximo giro.

05 · Representación en Python

Flotantes que se empujan suave

La posición es par de flotantes. Moverse es trigonometría con borde; separar es empujar a lo largo del vector que los une.

Python en tu navegador. Cambiá el espacio personal y observá cuándo dos puntos empiezan a molestarse.

import math

class Agente:
    def __init__(self, x=0.5, y=0.5, rumbo=0.0):
        self.x, self.y, self.rumbo = x, y, rumbo
    def deslizar(self, paso=0.03, borde="muros"):
        nx = self.x + paso * math.cos(self.rumbo)
        ny = self.y + paso * math.sin(self.rumbo)
        if borde == "toro":
            self.x, self.y = nx % 1.0, ny % 1.0
        else:
            self.x, self.y = min(1.0, max(0.0, nx)), min(1.0, max(0.0, ny))
        return (self.x, self.y)

a = Agente(0.95, 0.5, rumbo=0.0)
print(a.deslizar(paso=0.1, borde="muros"))
print(a.deslizar(paso=0.1, borde="toro"))

Con muros queda en 1,0; en toro reaparece por 0,05: el mismo desliz, otro borde continuo.

Separar sin celdas

Si la distancia cae bajo el mínimo, cada uno retrocede la mitad del solape.

def separar(a, b, dmin=0.05):
    dx, dy = b.x - a.x, b.y - a.y
    d = math.hypot(dx, dy)
    if d == 0 or d >= dmin:
        return False
    empuje = (dmin - d) / 2
    ux, uy = dx / d, dy / d
    a.x -= empuje * ux; a.y -= empuje * uy
    b.x += empuje * ux; b.y += empuje * uy
    return True

a, b = Agente(0.5, 0.5), Agente(0.52, 0.5)
print(separar(a, b), round(math.hypot(b.x - a.x, b.y - a.y), 3))

06 · Exploración

Laboratorio: espacio personal en desliz libre

Los agentes deslizan al azar con paso fijo 0,03. El círculo pálido es su espacio personal: si dos círculos se tocan hay roce y el modelo los cuenta. Las líneas rojas son roces de este paso. Ajustá el espacio y observá cuándo la libertad se vuelve multitud.

EXPERIMENTO 15

Libres pero no amontonados

si dist < dmin → roce

Los resultados numéricos aparecen debajo.
Roces0
Vecino medio0,00
Cobertura0/16
LecturaHol­gura

Con 40 agentes y espacio 0,05, los roces son ocasionales.

Cada punto desliza libre sin casillas; el halo es su espacio personal. Las líneas rojas marcan pares en roce. Pulsá Nueva réplica para otra caminata con los mismos parámetros.

Preguntas para explorar

  1. Con espacio 0 y 80 rondas, ¿cuántos roces hay? ¿Por qué sin dmin no hay roce aunque se pisen?
  2. Subí el espacio al máximo con 100 agentes. ¿Qué le pasa al vecino medio y a la cobertura?
  3. Repetí la misma configuración 3 veces. ¿Los roces son idénticos? ¿Qué parte es desliz y qué parte es encuentro?
Ver respuestas sugeridas
  1. Cero: sin umbral no hay criterio de contacto. El continuo mide, pero el roce lo define el dmin declarado.
  2. El vecino medio se achica en términos relativos y los roces se disparan; la cobertura apenas cambia porque el mapa es el mismo: más exigencia, misma superficie.
  3. No: la caminata arma encuentros distintos. El desliz con paso fijo es la regla; la historia de cercanías no.

07 · Comprensión

Confusiones frecuentes

«Continuo es discreto con celdas chicas»

Celdas chicas siguen saltando por centros y rebotando en binario. Continuo es flotante con distancia euclídea y empuje gradual.

«Sin celdas no hay choques»

Hay roces por distancia: si dist < dmin se separan. Sin esa regla los cuerpos se atraviesan como fantasmas.

«El paso grande cubre más y listo»

El paso mayor que el cuerpo tuneliza: cruza sin registrar contacto ni contagio. Continuo exige paso chico frente a cuerpo.

«Vecinos por radio sale gratis»

Cada par cuesta: N agentes son N² distancias por paso. Sin grillas espaciales ni topes, el continuo no escala (Temas 46–47).

08 · Práctica guiada

Ejercicios con Python

Ejercicio 1: medir en vez de contar

Ejecutá y verificá la distancia real. Luego mové el segundo a (0.6, 0.8) y comprobá que la celda habría dicho lo mismo.

import math
print(round(math.hypot(0.6 - 0.5, 0.8 - 0.5), 3))
Ver solución razonada

Da 0,316: lejos en continuo aunque caigan en celdas vecinas. La celda iguala; el flotante distingue.

Ejercicio 2: predecir el túnel

Sin ejecutar primero: cuerpo 0,04 y paso 0,10. ¿Puede cruzar a otro sin tocarlo? Comprobalo con dos posiciones.

x0, x1, otro = 0.40, 0.50, 0.45
print("salta por encima:", abs(x1 - otro) < 0.04 or abs(x0 - otro) < 0.04)
Ver solución

Registra False en ambos extremos aunque pasó por 0,45: el salto tunelizó el contacto. Paso chico o chequeo intermedio lo evita.

Ejercicio 3: roce que separa

Dos agentes a 0,03 con dmin 0,05. ¿Hay roce y a qué distancia quedan tras separar?

Ver una posible respuesta
import math
a, b, dmin = [0.5, 0.5], [0.53, 0.5], 0.05
d = math.hypot(b[0]-a[0], b[1]-a[1])
print(d < dmin, round(dmin, 3))

Hay roce (True) y quedan a 0,05: el empuje reparte el solape. Sin separar, el próximo paso decide sobre cuerpos pisados.

09 · Síntesis

Ideas para recordar

  • Continuo es posición real, distancia euclídea y desliz con cualquier rumbo.
  • El contacto es roce por dmin con empuje suave, no celda libre u ocupada.
  • El paso debe ser chico frente al cuerpo: si no, tuneliza encuentros.
  • El borde continuo se declara (muros con tope, toro con módulo) como en discreto.
  • En Python, deslizar suma vector y separar reparte el solape a lo largo del eje.

En el próximo tema estudiaremos la actualización síncrona: todos los agentes cambian a la vez.