¿Cómo distribuyo equitativamente los recursos entre las fábricas cuando los recursos están casi agotados?

12

El recurso principal en mi juego es masivo , almacenado como un número de coma flotante que cambia con el tiempo. Los nodos de recursos aumentan la masa y las fábricas la drenan. Por ejemplo, si tengo un nodo de recursos que produce 5 masas por segundo, ganaré 5 * deltaTmasa en cada paso del juego. La masa se muestra redondeada al entero más cercano, y los indicadores de ganancia / pérdida se muestran en décimas.

¿Cómo debo manejar la masa que llega a cero? Esto crea una condición de carrera si varias fábricas están tratando de construir a la vez: las fábricas primero en la cola o las que consumen menos recursos tienen prioridad una vez que ingresan más recursos y, por lo tanto, construyen más rápido que los demás.

¿Cómo puedo lidiar con esto? ¿Debo omitir el paso por completo?

Multitud
fuente
Bah, mi comentario no se guardó. Tuve una mejor explicación. Básicamente tengo un recurso al que se accede a cada paso por cada objeto. Cada objeto suma o resta del recurso. Mi problema es que si el recurso llega a 0, no sé qué hacer. ¿Debo hacer una cola de algún tipo? ¿Debo omitir el paso de un objeto? ¿Qué?
Multitud el
3
Round Robin. Problema resuelto.
Patrick Hughes el
La respuesta de Roy a continuación combinada con el comentario describe un sistema decente, fácil de mantener y sintonizar round robin. Mientras su problema de diseño inmediato se resuelva, todo está bien =)
Patrick Hughes

Respuestas:

9

Estoy de acuerdo con Petr: no hay una forma establecida de hacerlo. Cómo quieres hacerlo es cuestión de cómo quieres diseñar tu juego.

En esta circunstancia, sin embargo, creo que es inmediatamente obvio el tipo de mecánica que estás tratando de conseguir: solo quieres que las cosas se produzcan lo más rápido posible, dentro de la cantidad de masa que tienes disponible.

Produciendo dentro de la capacidad

Voy a sacar una hoja del libro del Comandante Supremo, ya que estás haciendo un sistema muy parecido al suyo: si estás produciendo por encima de la capacidad, la mejor manera de lidiar con eso es hacer que la producción disminuya en todos los ámbitos. Bajar la capacidad de producción es en realidad bastante simple.

Un mecánico de velocidad de producción.

En cada paso de actualización, sus fábricas no solo producen una cantidad establecida: operan según una velocidad de producción , que determina cuánto progreso logran en cada paso y cuánta masa consumen. Cuando estás produciendo al 75% de su capacidad, tus fábricas avanzan un 75% más en cada paso y usan hasta un 75% de la masa en comparación con el 100% de su capacidad.

Para calcular la velocidad de producción, antes de construir cualquier cosa, debe consultar a sus fábricas para determinar los recursos totales que se utilizarían en este paso a plena capacidad. Luego realiza un cálculo simple:

production speed = (total mass capacity / mass required this step)
if (production speed > 1.0) production speed = 1.0

Digamos que necesita 125 en masa este paso para producir a plena capacidad, pero solo tiene 100 en masa este paso. Esta ecuación le proporciona una velocidad de producción de 0.8 (la representación decimal del 80%). Cuando le dices a tus fábricas que realmente realicen su construcción , les das este valor para decirles a qué velocidad están construyendo: y ahora tu producción se ralentiza en todos los ámbitos.

Alternativas

También podría comenzar a cerrar las fábricas temporalmente hasta que se libere la capacidad de producción, y podría ser muy interesante ver que esto sucede a las fábricas más alejadas de los generadores cuando tienen una capacidad extremadamente baja.

Múltiples recursos?

Depende de usted cómo maneja esto; Hay muchas opciones. El más simple es probablemente calcular una capacidad de producción para cada recurso y luego elegir el más bajo , de modo que su recurso más débil se convierta en un cuello de botella para el resto.

doppelgreener
fuente
Creo que ni siquiera necesita decirle a la fábrica que produzca a una velocidad del 80%, porque todo lo que crea su fábrica utiliza una cantidad fija de masa. Por ejemplo: construyes un tanque que toma 100 masas para construir, normalmente la fábrica puede usar 2 masas en cada ciclo. Esto significa que se necesitan 50 ciclos para completar el tanque y cada ciclo que agrega 2 a la masa actual del tanque. Ahora, solo tiene 1 masa disponible, esto significa que este ciclo, la masa de los tanques gastados actualmente aumenta en 1 en lugar de 2. Después de cada ciclo, simplemente verifique la masa actual frente a la masa total requerida para ver si el tanque está completamente construido o no.
Thomas
Si tiene 0 masa disponible, simplemente no agregue ninguna masa al tanque. El tiempo que lleva construir algo de esta manera puede variar según su ingreso masivo. si tiene 2 fábricas que pueden usar 2 masas / ciclo y solo 3 ingresos, el tanque 1 se construye en 50 ciclos, el tanque 2 en 100. Otra forma es dividir la cantidad total de masa disponible en todas las fábricas que lo usan (son construyendo activamente algo). La cantidad total de masa que puede usar una fábrica podría mejorarse agregando niveles a la fábrica. Por ejemplo, en el nivel 1 pueden gastar 2 en masa, en el nivel 2: 3 en masa, etc., etc.
Thomas
@Thomas Agregar masa a un producto en proceso parece una forma demasiado compleja en comparación con simplemente completar un porcentaje del producto. Especialmente porque su fábrica debe saber todo sobre su sistema de recursos en lugar de una simple propiedad de "tasa de producción". Si el resultado para el jugador es el mismo, mantenga la implementación lo más simple posible. Eso también hace que sea más fácil realizar cambios en el futuro, como cuando agrega / elimina recursos.
Hackworth
@Hackworth Tiendo a estar en desacuerdo, la fábrica no necesita saber sobre el sistema de recursos. La fábrica solo sabe lo que está construyendo y qué tan lejos está. El sistema de recursos solo le dice a la fábrica que agregue una cantidad X a la compilación. De esta manera, no necesita calcular el porcentaje de ingresos de recursos que tiene esta fábrica y no necesita traducir los ingresos de recursos al porcentaje de finalización agregado.
Thomas
6

Aunque me gusta la respuesta de Jonathan Hobbs, creo que un sistema de colas es aún más simple:

Queue<Factory> queue = ...;
int numFactories = ...;

Update()
{
    int resources = GetAllResourcesForThisStep();
    for(int i = 0; i < numFactories; i++)
    {
        if(queue.Peak().RequiredResources <= resources)
        {
            Factory f = queue.Pop();
            resources -= f.RequiredResources;
            queue.Push(f);
        }
        else
        {
            break;
        }
    }
}

Esto probablemente funcionará en promedio de la misma manera que la implementación de Jonathan. Sin embargo, la solución de Jonathan puede dar problemas si la velocidad de trabajo se establece muy baja y mi implementación podría tener una fábrica con una solicitud de recursos muy alta para este marco si bloquea otras fábricas para varios marcos.

Roy T.
fuente
+1 Estoy desarrollando un juego con recursos duales, como en la pregunta, y cuando llegue a resolver el problema del bloqueo de suministros, planeo usar algo similar a esto. No ese código exacto, sino la idea detrás de él. Los consumidores que pueden utilizar los recursos en una marca tendrán una prioridad menor durante la siguiente marca. También planeo agregar una bandera para indicar si este consumidor es de alta prioridad, y darle el control de esa bandera al usuario.
John McDonald
Tenga cuidado con el hambre si les da prioridades separadas. :)
Roy T.
Sin embargo, el objetivo sería morir de hambre con prioridades separadas. ¿Alguna vez jugaste a Settlers 4 o Knights & Merchants? Si sobreconstruye edificios, los recursos limitados se destinan a edificios aleatorios y se tarda una eternidad en terminar cualquier cosa. Pero también le permiten seleccionar si un edificio es importante o no, en cuyo caso, los recursos irán primero a esos edificios importantes. La clave es nunca construir en exceso, o si lo hace, construir en exceso lo menos posible.
John McDonald
5

Estoy desarrollando un sistema de suministro similar en mi propio juego, por lo que también he estado pensando en cómo resolver el problema del bloqueo de suministro y el favoritismo. Para ilustrar el problema, crearé un ejemplo simple:

Si tiene una lista: [productor1, consumidor1, consumidor2, consumidor3] y actualiza en orden, comenzando en la oferta = 0, obtendrá esto:

producer1 produces 5 mass. You now have 5 mass
consumer1 wants 3 mass. Success, you now have 2 mass
consumer2 wants 3 mass. Fail
consumer3 wants 3 mass. Fail
[next tick]
producer1 produces 5 mass. You now have 7 mass
consumer1 wants 3 mass. Success, you now have 4 mass
consumer2 wants 3 mass. Success, you now have 1 mass
consumer3 wants 3 mass. Fail
etc...

El consumidor 1 obtiene toda la diversión, mientras que los consumidores 2 y 3 pasan hambre hasta que el consumidor 1 está satisfecho. Dependiendo de su juego, esto puede no ser deseable. Lo sé en mi juego, no lo es. Cuando llegue a eso, voy a crear una cola en la que los consumidores que han sido alimentados con una marca se moverán al final de la cola para la siguiente, lo que creo que es lo que Roy T. está haciendo. El ejemplo anterior se vería así:

producer1 produces 5 mass. You now have 5 mass
consumer1 wants 3 mass. Success, you now have 2 mass. <-- Move to end of queue
consumer2 wants 3 mass. Fail
consumer3 wants 3 mass. Fail
[next tick]
producer1 produces 5 mass. You now have 7 mass
consumer2 wants 3 mass. Success, you now have 4 mass  <-- Note the order change
consumer3 wants 3 mass. Success, you now have 1 mass
consumer1 wants 3 mass. Fail
etc...

De esta manera, todos obtendrán su parte justa de los recursos.

También planeo implementar una cola adicional que se utilizará como una cola de prioridad para que el usuario pueda seleccionar ciertas estructuras para tener prioridad de recursos. La cola prioritaria siempre se servirá antes que la cola estándar. Asegúrese de que todos los productores se actualicen primero, luego consuma todos los recursos en segundo lugar, de lo contrario, la cola se romperá cuando produzca recursos en medio de una marca y algunos consumidores ya hayan muerto de hambre.

Para resumir: actualice los productores, luego la cola de prioridad, moviendo los consumidores alimentados al final de la cola de prioridad, luego actualice la cola estándar, moviendo los consumidores alimentados al final de la cola estándar.

John McDonald
fuente
Llevado al límite, podría significar que ningún consumidor termina hasta que todos los consumidores puedan terminar. En un escenario de cadena de producción realista, eso es bastante improbable, y podría ser bastante desastroso si alguien quisiera tener una cola de construcción para un ejército masivo. Estará prácticamente sin tropas durante todo el tiempo en que se esté construyendo el ejército.
Cardin
Esa respuesta fue mi pensamiento inicial cuando leí la pregunta. Además, debe tenerse en cuenta que la masa consumida por marca no es necesariamente la masa para crear una unidad completa, sino el costo unitario durante el tiempo requerido, por lo que no estoy seguro de que las preocupaciones de @ Cardin sean válidas, a menos que su unidad El costo por marca está muy cerca de su tasa de recolección total. Simplemente tendría la cola prioritaria administrada explícitamente por el jugador, para que él pueda decidir quién muere de hambre.
brice
@Cardin, tienes razón, pero también se puede usar como mecánica de juego. Settlers 4, Knights & Merchants, Total Annihilation, Supreme Commander son juegos que sé que hicieron esto. El truco es no alcanzar este bloqueo de suministro, y si lo hace, asegúrese de salir lo antes posible. Agregar una cola prioritaria permite a las personas una forma de salir más fácilmente.
John McDonald
3

Bueno, ampliaré la idea de John, ya que discutimos esto un poco en el chat .

editar: esta solución solo es preferible si el consumibleAmount es relevante para la frecuencia con la que la fábrica debería obtener un lote de recursos. Si todo es lo mismo, entonces puedes usar una cola.

Mi solución: todas las fábricas que figuran en una cola prioritaria. La prioridad aumenta a medida que una fábrica sufre de hambre. Hambre, prioridad, establecida en cero cuando la fábrica ha consumido recursos. La máxima prioridad siempre será obtener el próximo lote de recursos.

Al determinar qué fábrica obtiene qué recursos, en algún tipo de pseudocódigo:

iterator i = factoryqueue.start()
bool starvation = false
while(i.next())
  if(i.ready)
    if (!starvation) 
      if (i.consumeAmount < resource.count) starvation = true
      else 
        i.consume(resource)
        i.priority = 0
    if (starvation)
      i.priority += 1

De esta manera, sus fábricas fabricarán 1 producto cada una por turno, si desea ajustar teniendo en cuenta el consumoAmount para que los productos más baratos se fabriquen con mayor frecuencia, podría aumentar la prioridad en 1 / consumeAmount, por ejemplo.

Toni
fuente
Me gustaría votar esto, pero no estoy seguro de lo que está destinado a hacer: realiza un seguimiento de la inanición, pero de lo contrario (presumiblemente) simplemente gira a través de la cola exactamente como es normal, y tanto la inanición como la prioridad nunca terminan apareciendo hacer cualquier cosa.
doppelgreener
la diferencia se hace evidente si aumenta la prioridad en + = 1 / amountThisFactoryConsumes, entonces los que requieren más recursos para crear un producto se retrasarán un poco, permitiendo que los menos costosos tomen proporcionalmente más lotes de recursos. Esto igualaría la relación de recursos por fábrica. Sin embargo, esto no es exactamente una prueba infalible, ya que el número de inanición se establece en el número mágico 0 cada vez que los recursos son consumidos por la fábrica, por lo que no será distribuido de manera equitativa cuando la renovación de recursos fluctúe.
Toni
En realidad, ahora no estoy tan seguro si en realidad no está garantizado. Necesitaría dibujar algunos gráficos y probarlo para estar seguro.
Toni
ah, y la prioridad es una calidad de la cola de prioridad en sí misma. No voy a molestarme en explicar cómo construir uno. La cola de prioridad en sí misma siempre se ordena según el valor de prioridad de sus miembros.
Toni
+1 Entendiendo que es una cola prioritaria, su funcionamiento ahora parece simple: tamizar a través de la cola y elegir lo más pronto que pueda consumir recursos. Si la capacidad está muy dividida (tiene 1,000 recursos en esta marca, pero cien construcciones de 100 recursos) esto no debería ser un problema, y ​​las cosas se alimentan bastante bien. Incluso si algo está muy por encima de sus recursos en este momento, podría ahorrar lo suficiente como para progresar un poco, lo que tiene el impacto de ralentizarlo o cerrar grandes cosas por completo a favor de cosas más pequeñas, lo cual es algo bueno. Me gusta esto muchisimo. :)
doppelgreener
2

Extraña pregunta.

Mi problema es que si el recurso llega a 0, no sé qué hacer. ¿Debo hacer una cola de algún tipo? ¿Debo omitir el paso de un objeto? ¿Qué?

Lo que debe hacer depende de la lógica del juego que cree. Puedes hacer una cola, puedes saltarte. Depende de cómo creas que debería comportarse tu juego. Corrígeme, si me equivoco en tu pregunta.

Petr Abdulin
fuente
1

Puede mantener una cantidad de la demanda total de recursos por marca para todas las construcciones. Si el almacenamiento de un recurso alcanza menos de esta cantidad requerida, entonces toda la construcción se detendría por completo hasta que el almacenamiento se haya reunido lo suficiente como para soportar al menos 1 tick de producción. Entonces la producción puede reanudarse.

Entonces, en lugar de almacenar la tasa de producción como flotante, es binaria, ya sea que su fábrica produce a toda velocidad o no.

Dicho esto, este enfoque es esencialmente el mismo que el de la respuesta de Jonathan, para los casos especiales de tasa de producción 0.0 y 1.0: una flotación arbitraria f con 0.0 <= f <= 1.0 es probablemente más elegante ya que no se obtienen movimientos bruscos de la cantidad de almacenamiento , pero la lógica debería ser un poco más simple.

Hackworth
fuente