Bloques que caen y formas complejas


10

Actualmente tengo un juego simple similar al Tetris y me he encontrado con un problema que no puedo resolver.

A diferencia de Tetris, donde hay una sola forma de caída, tengo varias formas potencialmente entrelazadas que deben caerse; Necesito calcular sus posiciones finales. Considera lo siguiente:

ejemplos del problema de bloques que caen

  1. Para calcular la posición final de la forma verde, simplemente escaneo hacia abajo para cada cuadrado hasta que golpee otro cuadrado o el borde del tablero. Hecho

  2. Para formas múltiples y simples, trabajo hacia ARRIBA del tablero. Por lo tanto, se descubre que el rojo no necesita moverse, el naranja baja en uno y el verde en tres. Hecho

  3. No sé cómo tratar las formas verdes y rojas entrelazadas. Usando la lógica del # 2, terminaríamos "atrapados" flotando en el aire. Si escaneo hacia abajo para encontrar la forma verde, encuentro el rojo y, por lo tanto, no me muevo, y viceversa para el rojo. La solución podría ser tratar las dos formas como una sola.

  4. Similar al # 3, en este escenario también podría tener éxito al tratar los objetos como uno solo.

  5. A diferencia de # 3 y # 4, no podría tratar la forma como una, ya que la forma naranja terminaría flotando un cuadrado demasiado alto ...

  6. Otra variación del problema # 6.

Podría haber otros escenarios en los que tengo muchas formas que se entrelazan en escenarios cada vez más complejos, pero creo que lo anterior cubre las partes más fundamentales del problema.

Siento que hay una solución elegante que todavía tengo que encontrar / pensar y estaría muy agradecido por cualquier idea, idea o recurso.

SOLUCIÓN

La solución que se me ocurrió es elegante, basada en la respuesta de @ user35958 a continuación, he creado la siguiente función recursiva (pseudocódigo)

function stop(square1, square2){
    // Skip if we're already stopped
    if(square1.stopped){
        return;
    }
    // Are we comparing squares?
    if(!square2){
        // We are NOT comparing squares, simply stop.
        square1.stopped = true;
    } else {
        // Stop IF
        // square1 is directly above square2
        // square1 is connected to square2 (part of the same complex shape)
        if(square1.x == square2.x && square1.y == (square2.y+1) || isConnected(square1, square2)){
            square1.stopped = true;
        }
    }
    // If we're now stopped, we must recurse to our neighbours
    stop(square1, squareAbove);
    stop(square1, squareBelow);
    stop(square1, squareRight);
    stop(square1, squareDown);
}

GIF animado que muestra cada paso de la solución

Resumir:

  • Cuando "paramos" un cuadrado, también paramos:
    • CUALQUIER cuadrado encima de él. SIEMPRE.
    • Cuadrado vecino al que estamos conectados (es decir, la misma forma).
  • Paramos toda la fila inferior y la función se repite a través de los cuadrados.
  • Repetimos hasta que se detengan todos los cuadrados.
  • Entonces nos animamos.

GIF animado que muestra cada paso de la secuencia lógica


Me imagino que si resuelves 5, ese 6 también se resolvería. De hecho, creo que resolver 5 probablemente resolvería todas estas situaciones.
UnderscoreZero

+1 gracias por compartir. Increíble solución Me encanta la animación :)
ashes999

Cheers ashes999, creo que necesito una nueva animación con flechas que muestren cómo la lógica de parada "fluye" desde la fila inferior y prolifera en todo el escenario ...
oodavid

Respuestas:


4

Bueno, no es necesario que trates las formas como si fueran una distinción entre las formas que se mueven y las que están en reposo. Una forma (A) podría detectar una forma (B) directamente debajo de ella y si se está moviendo, entonces la forma B podría ver si hay algo directamente debajo de ella, y si hay una forma en reposo, entonces A y B ahora están descansando, y si no hay nada, ambos se mueven hacia abajo, pero si hay una forma en movimiento, entonces esta nueva forma será tratada por A y B como A tratada a B, por lo que es algo recursivo. Tenga en cuenta que para cada paso, las formas más bajas deben verificar primero las formas debajo de ellas.

Entonces, para el problema # 6, la forma verde es la forma más baja en movimiento, y vería que la única forma que está directamente debajo es la forma roja, por lo que la forma roja no detectaría nada directamente debajo y se moverían hacia abajo . Una vez que la forma verde es adyacente a la forma naranja, descansaría, y la forma roja se movería hacia abajo y luego detectaría la forma verde en reposo, y también descansaría.


¿Estoy en lo cierto al pensar que tendríamos que asumir que todas las formas no están en reposo hasta que demostremos lo contrario?
oodavid

Acabo de pasar un tiempo reflexionando sobre esto y debo decir que suena como una muy buena técnica. Lo intentaré mañana / el fin de semana y veré cómo funciona.
oodavid

3

Parece que el problema con los casos n. ° 5 y n. ° 6 proviene de una sola raíz: solo está realizando una pasada de comprobaciones de movimiento. Debes seguir moviendo cosas hacia abajo (llamémosle un "paso de gravedad") hasta que sepas que nada se movió.

Por ejemplo, en el caso 6, esto es lo que sucedería si usara varios pases:

  • Naranja se mueve hacia abajo
  • El verde se mueve hacia abajo
  • Naranja se mueve hacia abajo
  • El verde se mueve hacia abajo
  • Naranja se mueve hacia abajo
  • Nada se mueve hacia abajo (¡hecho!)

Esta estrategia de pases de gravedad múltiple también podría resolver el n. ° 5, aunque no ayudará con los casos n. ° 3 y n. ° 4, donde parece que debe tratarlos como si fueran una sola pieza.

Para distinguir cuándo dos o más piezas deben tratarse como una sola pieza, creo que el algoritmo más fácil es verificar si hay "agujeros" en el espacio combinado de todas las piezas. Si los hay, se pueden tratar como piezas múltiples.


1
Con el n. ° 3 y el n. ° 4 también podría haber variaciones en las que, por ejemplo, 2 o 3 formas están completamente encerradas por una forma de "C" más grande, descubrir si las piezas están coaguladas podría generar más problemas. ¡Lo intentaré y veré qué sucede! Cheers @ ashes999
oodavid

@oodavid tus requisitos / diseño me parecen innecesariamente complicados. Comience con algo más simple y vaya ascendiendo a medida que resuelve estos problemas.
cenizas999

No, el problema anterior es una forma completamente simplificada / abstracta de describir un problema mucho más complejo. Estoy haciendo esto por la emoción de la persecución!
oodavid
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.