Falling Block dan bentuk kompleks

10

Saat ini saya memiliki permainan sederhana seperti Tetris dan telah menemukan masalah yang tidak bisa saya selesaikan.

Tidak seperti Tetris di mana ada satu bentuk jatuh, saya memiliki beberapa bentuk yang berpotensi saling bertautan yang perlu jatuh; Saya perlu menghitung posisi akhir mereka. Pertimbangkan yang berikut ini:

contoh masalah blok jatuh

  1. Untuk menghitung posisi akhir dari bentuk hijau, saya cukup memindai ke bawah untuk setiap kotak sampai saya menekan kotak lain atau tepi papan. Selesai

  2. Untuk beberapa bentuk sederhana saya bekerja dengan cara saya naik papan. Jadi merah ditemukan tidak perlu bergerak, oranye turun satu, hijau turun tiga. Selesai

  3. Saya tidak tahu bagaimana memperlakukan bentuk hijau dan merah yang saling terkait. Menggunakan logika # 2 kita akan berakhir "terjebak" mengambang di udara. Jika saya memindai ke bawah untuk bentuk hijau, saya menemukan merah dan karenanya tidak bergerak, dan sebaliknya untuk merah. Solusinya mungkin memperlakukan dua bentuk sebagai satu.

  4. Mirip dengan # 3, dalam skenario ini saya juga bisa berhasil dengan memperlakukan objek sebagai satu.

  5. Tidak seperti # 3 dan # 4 saya tidak bisa memperlakukan bentuk sebagai satu karena bentuk oranye akan berakhir mengambang satu-persegi terlalu tinggi ...

  6. Variasi lain dari masalah # 6.

Mungkin ada skenario lain di mana saya memiliki banyak bentuk yang terjalin dalam skenario yang lebih kompleks, tetapi saya pikir di atas mencakup bagian paling mendasar dari masalah.

Saya merasa ada solusi elegan yang belum saya temui / pikirkan dan akan sangat berterima kasih atas wawasan, ide, atau sumber daya apa pun.

LARUTAN

Solusi yang saya buat memang elegan, berdasarkan jawaban @ user35958 di bawah ini, saya telah membuat fungsi rekursif berikut (kode semu)

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 animasi yang menunjukkan setiap celah solusi

Untuk meringkas:

  • Saat "menghentikan" kotak, kami juga berhenti:
    • SETIAP persegi di atasnya. SELALU.
    • Tetangga tetangga tempat kita terhubung (yaitu bentuk yang sama).
  • Kami menghentikan seluruh baris bawah, dan fungsinya berulang melalui kotak.
  • Kami ulangi sampai semua kotak dihentikan.
  • Lalu kita hidup.

GIF animasi yang menampilkan setiap pass dari urutan logis

oodavid
sumber
Saya membayangkan jika Anda memecahkan 5 bahwa 6 akan diselesaikan juga. Bahkan, saya percaya memecahkan 5 mungkin akan menyelesaikan semua situasi ini.
UnderscoreZero
+1 terima kasih telah berbagi. Solusi luar biasa. Love the animation :)
ashes999
Cheers ashes999, saya pikir saya perlu animasi baru dengan panah yang menunjukkan bagaimana logika berhenti "mengalir" dari baris paling bawah dan berkembang biak di seluruh panggung ...
oodavid

Jawaban:

4

Nah, Anda tidak perlu memperlakukan bentuk sebagai satu jika ada perbedaan antara bentuk yang bergerak dan bentuk yang diam. Bentuk (A) dapat mendeteksi bentuk (B) langsung di bawahnya dan jika bergerak, maka bentuk B kemudian dapat melihat apakah ada sesuatu yang langsung di bawahnya, dan jika ada bentuk istirahat, maka A dan B sekarang sedang beristirahat, dan jika tidak ada apa-apa, keduanya bergerak ke bawah, tetapi jika ada bentuk yang bergerak, maka bentuk baru ini akan diperlakukan oleh A dan B sebagai A yang diperlakukan B, jadi itu semacam rekursif. Ingatlah bahwa untuk setiap langkah, bentuk terendah harus memeriksa bentuk di bawahnya terlebih dahulu.

Jadi, untuk masalah # 6, bentuk hijau adalah bentuk bergerak terendah, dan ia akan melihat bahwa satu-satunya bentuk yang langsung di bawahnya adalah bentuk merah, sehingga bentuk merah akan mendeteksi tidak ada yang langsung di bawahnya, dan mereka akan bergerak ke bawah . Setelah bentuk hijau berdekatan dengan bentuk oranye, itu akan beristirahat, dan bentuk merah akan bergerak ke bawah dan kemudian mendeteksi bentuk hijau sisanya, dan itu akan beristirahat juga.

awsumpwner27
sumber
Apakah saya benar dalam berpikir bahwa kita harus menganggap semua bentuk tidak diam sampai kita membuktikan sebaliknya?
oodavid
Saya baru saja menghabiskan waktu merenungkan ini dan saya harus mengatakan itu terdengar seperti teknik yang sangat bagus. Saya akan mencobanya besok / akhir pekan dan lihat hasilnya.
oodavid
3

Sepertinya masalah dengan kasus # 5 dan # 6 berasal dari satu root: Anda hanya melakukan satu pass gerakan. Anda harus terus memindahkan barang ke bawah (sebut saja "lintasan gravitasi") sampai Anda tahu tidak ada yang bergerak.

Misalnya, dalam kasus 6, inilah yang akan terjadi jika Anda menggunakan beberapa lintasan:

  • Oranye bergerak ke bawah
  • Hijau bergerak ke bawah
  • Oranye bergerak ke bawah
  • Hijau bergerak ke bawah
  • Oranye bergerak ke bawah
  • Tidak ada yang bergerak (selesai!)

Strategi multiple pass gravitasi ini dapat menyelesaikan # 5 juga, walaupun ini tidak akan membantu dengan kasus # 3 dan # 4 di mana Anda perlu memperlakukannya seperti sepotong.

Untuk membedakan kapan dua atau lebih bagian harus diperlakukan sebagai satu bagian, saya pikir algoritma termudah adalah untuk memeriksa apakah ada "lubang" di ruang gabungan semua bagian. Jika ada, dapat diperlakukan sebagai beberapa bagian.

ashes999
sumber
1
Dengan # 3 dan # 4 juga bisa ada variasi di mana katakanlah 2 atau 3 bentuk tertutup sepenuhnya oleh bentuk "C" yang lebih besar, mencari tahu apakah potongan-potongan yang dikoagulasi dapat menimbulkan masalah lebih lanjut. Saya akan mencobanya dan melihat apa yang terjadi! Cheers @ ashes999
oodavid
@oodavid, persyaratan / desain Anda sepertinya tidak perlu rumit bagi saya. Mulailah dengan sesuatu yang lebih sederhana dan selesaikan saat Anda menyelesaikan masalah ini.
ashes999
Nahhhh, masalah di atas adalah cara yang benar-benar disederhanakan / abstrak untuk menggambarkan masalah yang jauh lebih kompleks. Saya melakukan ini untuk sensasi pengejaran!
oodavid