Blocchi cadenti e forme complesse


10

Al momento ho un semplice gioco simile a Tetris e ho riscontrato un problema che non posso risolvere.

A differenza di Tetris, dove esiste una singola forma che cade, ho forme multiple, potenzialmente ad incastro, che devono cadere; Devo calcolare le loro posizioni finali. Considera quanto segue:

esempi del problema dei blocchi cadenti

  1. Per calcolare la posizione finale della forma verde, eseguo semplicemente la scansione di ogni quadrato fino a quando non colpisco un altro quadrato o il bordo del tabellone. Fatto

  2. Per forme multiple e semplici lavoro a modo mio sulla tavola. Quindi il rosso non ha bisogno di muoversi, l'arancione scende di uno, il verde di tre. Fatto

  3. Non so come trattare le forme verdi e rosse interconnesse. Usando la logica del n. 2 finiremmo per "bloccarci" fluttuando a mezz'aria. Se cerco la forma verde verso il basso, incontro il rosso e quindi non mi muovo, e viceversa per il rosso. La soluzione potrebbe essere quella di trattare le due forme come una.

  4. Simile al n. 3, in questo scenario sono riuscito anche a trattare gli oggetti come uno.

  5. A differenza del n. 3 e del n. 4, non potevo considerare la forma come una poiché la forma arancione finiva per galleggiare di un quadrato troppo in alto ...

  6. Un'altra variante del problema n. 6.

Potrebbero esserci altri scenari in cui ho molte forme che si intrecciano in scenari sempre più complessi, ma penso che quanto sopra copre le parti più fondamentali del problema.

Sento che esiste una soluzione elegante che devo ancora incontrare / pensare e che sarei molto grato a qualsiasi intuizione, idea o risorsa.

SOLUZIONE

La soluzione che ho trovato è davvero elegante, basata sulla risposta di @ user35958 di seguito, ho creato la seguente funzione ricorsiva (pseudo codice)

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 animata che mostra ogni passaggio della soluzione

Riassumere:

  • Quando "fermiamo" un quadrato, ci fermiamo anche:
    • QUALSIASI quadrato sopra di esso. SEMPRE.
    • Quadrato vicino al quale siamo collegati (cioè la stessa forma).
  • Interrompiamo l'intera riga inferiore e la funzione ricorre nei quadrati.
  • Ripetiamo fino a quando tutti i quadrati non vengono fermati.
  • Quindi animiamo.

GIF animata che mostra ogni passaggio della sequenza logica


Immagino che se risolvessi 5, anche il 6 sarebbe risolto. In effetti, credo che risolvere 5 probabilmente risolverebbe tutte queste situazioni.
UnderscoreZero

+1 grazie per la condivisione. Soluzione incredibile. Adoro l'animazione :)
ashes999

Saluti ashes999, penso di aver bisogno di una nuova animazione con frecce che mostrino come la logica di stop "scorre" dalla fila in basso e prolifera attraverso l'intero palco ...
oodavid,

Risposte:


4

Bene, non hai esattamente bisogno di trattare le forme come una se c'è una distinzione tra forme che si muovono e forme che sono a riposo. Una forma (A) potrebbe rilevare una forma (B) direttamente sotto di essa e se si sta muovendo, allora la forma B potrebbe quindi vedere se c'è qualcosa direttamente sotto di essa, e se c'è una forma a riposo, allora A e B ora stanno riposando, e se non c'è nulla, entrambi si spostano verso il basso, ma se c'è una forma mobile, questa nuova forma sarà trattata da A e B come A trattata B, quindi è una specie di ricorsivo. Tieni presente che per ogni passaggio, le forme più basse devono prima verificare le forme sottostanti.

Quindi, per il problema n. 6, la forma verde è la forma mobile più bassa e vedrebbe che l'unica forma che è direttamente sotto di essa è la forma rossa, quindi la forma rossa non rileverebbe nulla direttamente sotto di essa e si sposterebbero verso il basso . Una volta che la forma verde è adiacente alla forma arancione, si riposerebbe e la forma rossa si sposterebbe in basso e quindi rileverebbe la forma verde a riposo, e si riposerebbe anche.


Ho ragione nel pensare che dovremmo presumere che tutte le forme non siano a riposo finché non proviamo il contrario?
oodavid,

Ho appena trascorso un po 'di tempo a meditare su questo e devo dire che sembra un'ottima tecnica. Lo proverò domani / il fine settimana e vedrò come funziona.
oodavid,

3

Sembra che il problema con i casi n. 5 e n. 6 provenga da una singola radice: stai eseguendo solo un passaggio di controlli di movimento.Dovresti continuare a spostare le cose verso il basso (chiamiamolo un "passaggio di gravità") fino a quando non sai che nulla si è mosso.

Ad esempio, nel caso 6, questo è ciò che accadrebbe se si utilizzassero più passaggi:

  • L'arancia si sposta verso il basso
  • Il verde si sposta verso il basso
  • L'arancia si sposta verso il basso
  • Il verde si sposta verso il basso
  • L'arancia si sposta verso il basso
  • Niente si sposta verso il basso (fatto!)

Questa strategia di passaggi di gravità multipli potrebbe risolvere anche il n. 5, anche se non aiuterà con i casi n. 3 e n. 4 in cui sembra che tu debba trattarli come un pezzo unico.

Per distinguere quando due o più pezzi dovrebbero essere trattati come un singolo pezzo, penso che l'algoritmo più semplice sia verificare se vi sono "buchi" nello spazio combinato di tutti i pezzi. Se ci sono, può essere trattato come più pezzi.


1
Con il n. 3 e il n. 4 potrebbero esserci anche variazioni in cui le forme 2 o 3 sono completamente racchiuse da una forma a "C" più grande, capire se i pezzi sono coagulati potrebbe sollevare ulteriori problemi. Ci proverò e vedrò cosa ne esce! Saluti @ ashes999
oodavid,

@oodavid i tuoi requisiti / design mi sembrano inutilmente complicati. Inizia con qualcosa di più semplice e sali su mentre risolvi questi problemi.
ashes999,

Nahhhh, il problema sopra è un modo completamente semplificato / astratto per descrivere un problema molto più complesso. Lo sto facendo per il brivido dell'inseguimento!
oodavid,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.