บล็อกล้มและรูปร่างที่ซับซ้อน


10

ขณะนี้ฉันมีเกมเหมือน Tetris ที่เรียบง่ายและพบปัญหาที่ฉันไม่สามารถแก้ไขได้

ซึ่งแตกต่างจาก Tetris ที่มีรูปทรงล้มเดียวฉันมีรูปทรงหลายรูปที่เชื่อมต่อกันที่อาจต้องตก ฉันต้องคำนวณตำแหน่งสุดท้ายของพวกเขา พิจารณาสิ่งต่อไปนี้:

ตัวอย่างของปัญหาการล้มบล็อก

  1. ในการคำนวณตำแหน่งสุดท้ายของรูปร่างสีเขียวฉันเพียงแค่สแกนหาทุก ๆ ตารางจนกว่าฉันจะไปถึงอีกสี่เหลี่ยมจัตุรัสหรือขอบของกระดาน เสร็จสิ้น

  2. สำหรับรูปร่างที่เรียบง่ายหลาย ๆ แบบฉันกำลังไต่ขึ้นบอร์ด ดังนั้นสีแดงจึงไม่จำเป็นต้องเคลื่อนไหวสีส้มจะลดลงทีละหนึ่งสีเขียวลดลงสาม เสร็จสิ้น

  3. ฉันไม่รู้วิธีรักษารูปร่างสีเขียวและสีแดงที่เชื่อมต่อกัน การใช้ตรรกะของ # 2 เราจะท้าย "ติด" ลอยกลางอากาศ หากฉันสแกนหารูปร่างสีเขียวฉันจะพบกับสีแดงและไม่เคลื่อนไหวและในทางกลับกันสำหรับสีแดง วิธีแก้ปัญหาอาจใช้รูปร่างสองแบบเป็นหนึ่งเดียว

  4. คล้ายกับ # 3 ในสถานการณ์นี้ฉันสามารถประสบความสำเร็จได้ด้วยการปฏิบัติต่อวัตถุเป็นหนึ่งเดียว

  5. แตกต่างจาก # 3 และ # 4 ฉันไม่สามารถรักษารูปร่างเป็นหนึ่งเป็นรูปร่างสีส้มจะจบลงหนึ่งตารางลอยสูงเกินไป ...

  6. อีกรูปแบบของปัญหา # 6

อาจมีสถานการณ์อื่น ๆ ที่ฉันมีหลายรูปร่างที่คลุกเคล้าในสถานการณ์ที่ซับซ้อนมากขึ้น แต่ฉันคิดว่าข้างต้นครอบคลุมส่วนพื้นฐานที่สุดของปัญหา

ฉันรู้สึกว่ามีวิธีการแก้ปัญหาที่สง่างามที่ฉันยังไม่ได้พบ / คิดและจะขอบคุณมากที่ข้อมูลเชิงลึกความคิดหรือทรัพยากรใด ๆ

สารละลาย

วิธีแก้ปัญหาที่ฉันคิดขึ้นมานั้นสวยงามจริงๆโดยอิงจากคำตอบของ @ user35958 ด้านล่างฉันได้สร้างฟังก์ชั่นแบบเรียกซ้ำต่อไปนี้ (รหัสหลอก)

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);
}

Animated GIF แสดงการแก้ปัญหาแต่ละรอบ

เพื่อสรุป:

  • เมื่อ "หยุด" สี่เหลี่ยมเราก็หยุด:
    • ตารางข้างต้นใด ๆ เสมอ.
    • สี่เหลี่ยมใกล้เคียงที่เราเชื่อมต่อกับ (เช่นรูปร่างเดียวกัน)
  • เราหยุดแถวด้านล่างทั้งหมดและฟังก์ชั่นเกิดขึ้นอีกครั้งผ่านช่องสี่เหลี่ยม
  • เราทำซ้ำจนกว่าจะหยุดสี่เหลี่ยมทั้งหมด
  • จากนั้นเราเคลื่อนไหว

Animated GIF แสดงแต่ละรอบของลำดับตรรกะ


ฉันคิดว่าถ้าคุณแก้ 5 ว่า 6 จะได้รับการแก้ไขเช่นกัน ที่จริงแล้วฉันเชื่อว่าการแก้ไข 5 อาจจะแก้สถานการณ์เหล่านี้ทั้งหมด
UnderscoreZero

+1 ขอบคุณสำหรับการแบ่งปัน ทางออกที่น่าอัศจรรย์ รักอนิเมชั่น :)
ashes999

เสียงไชโยโห่ร้อง 999 ฉันคิดว่าฉันต้องการอนิเมชั่นใหม่พร้อมลูกศรที่แสดงให้เห็นว่าตรรกะลอจิก "ไหล" ขึ้นมาจากแถวล่างและแพร่กระจายไปทั่วทั้งเวที ...
oodavid

คำตอบ:


4

ทีนี้คุณไม่จำเป็นต้องรักษารูปร่างเหมือนกันถ้ามีความแตกต่างระหว่างรูปร่างที่กำลังเคลื่อนที่และรูปร่างที่เหลือ รูปร่าง (A) สามารถตรวจจับรูปร่าง (B) ได้โดยตรงจากด้านล่างและถ้ามันเคลื่อนไหวแล้วรูปร่าง B นั้นจะสามารถดูว่ามีสิ่งใดที่อยู่ด้านล่างหรือไม่และถ้ามีรูปร่างที่พักผ่อนแล้ว A และ B ก็จะพักอยู่และ หากไม่มีอะไรพวกเขาทั้งคู่เลื่อนลง แต่ถ้ามีรูปร่างที่เคลื่อนไหวแล้วรูปร่างใหม่นี้จะได้รับการปฏิบัติโดย A และ B ในฐานะ A ที่ได้รับการรักษา B ดังนั้นมันจึงเป็นการเรียกซ้ำ โปรดทราบว่าในแต่ละขั้นตอนรูปร่างต่ำสุดจำเป็นต้องตรวจสอบรูปร่างด้านล่างก่อน

ดังนั้นสำหรับปัญหา # 6 รูปร่างสีเขียวเป็นรูปร่างเคลื่อนไหวที่ต่ำที่สุดและจะเห็นว่ารูปร่างเดียวที่อยู่ด้านล่างโดยตรงคือรูปร่างสีแดงดังนั้นรูปร่างสีแดงจะตรวจจับสิ่งใดไม่ได้ด้านล่างและพวกเขาจะเลื่อนลง . เมื่อรูปร่างสีเขียวอยู่ติดกับรูปร่างสีส้มก็จะพักและรูปร่างสีแดงจะเลื่อนลงจากนั้นตรวจจับรูปร่างสีเขียวที่วางอยู่และจะพักด้วย


ฉันคิดถูกว่าเราจะต้องสมมติว่ารูปร่างทั้งหมดไม่เหลือจนกว่าเราจะพิสูจน์เป็นอย่างอื่นหรือไม่?
oodavid

ฉันเพิ่งใช้เวลาคิดไตร่ตรองและฉันต้องบอกว่ามันดูเหมือนเทคนิคที่ดีมาก ฉันจะลองดูพรุ่งนี้ / วันหยุดสุดสัปดาห์และดูว่ามันแพนอย่างไร
oodavid

3

ดูเหมือนว่าปัญหาของกรณี # 5 และ # 6 เกิดจากรูทเดียว: คุณทำการตรวจสอบการเคลื่อนไหวเพียงครั้งเดียว คุณควรเคลื่อนย้ายสิ่งต่าง ๆ ลงเรื่อย ๆ (เรียกว่า "แรงโน้มถ่วงผ่าน") จนกว่าคุณจะรู้ว่าไม่มีอะไรเคลื่อนไหว

ตัวอย่างเช่นในกรณีที่ 6 นี่คือสิ่งที่จะเกิดขึ้นหากคุณใช้บัตรผ่านหลายใบ:

  • ออเรนจ์เคลื่อนตัวลง
  • สีเขียวเลื่อนลง
  • ออเรนจ์เคลื่อนตัวลง
  • สีเขียวเลื่อนลง
  • ออเรนจ์เคลื่อนตัวลง
  • ไม่มีอะไรเลื่อนลง (เสร็จสิ้น!)

กลยุทธ์การส่งผ่านแรงโน้มถ่วงหลายตัวสามารถแก้ไข # 5 ได้เช่นกันแม้ว่ามันจะไม่ช่วยกรณี # 3 และ # 4 ซึ่งดูเหมือนว่าคุณจะต้องปฏิบัติต่อพวกมันเหมือนชิ้นเดียว

การแยกแยะว่าควรปฏิบัติต่อชิ้นส่วนสองชิ้นหรือมากกว่าเป็นชิ้นเดียวฉันคิดว่าอัลกอริทึมที่ง่ายที่สุดคือการตรวจสอบว่ามี "หลุม" ในพื้นที่รวมของชิ้นส่วนทั้งหมดหรือไม่ หากมีก็สามารถถือว่าเป็นหลายชิ้น


1
ด้วย # 3 และ # 4 อาจมีการแปรผันที่รูปร่าง 2 หรือ 3 ถูกล้อมรอบอย่างสมบูรณ์ด้วยรูปร่าง "C" ที่ใหญ่ขึ้นการหาว่าชิ้นส่วนใดที่แข็งตัวสามารถทำให้เกิดปัญหาเพิ่มเติมได้ ฉันจะไปดูว่ามีอะไรเกิดขึ้นบ้าง! ไชโย @ ashes999
oodavid

@oodavid ความต้องการ / การออกแบบของคุณดูเหมือนจะไม่จำเป็นสำหรับฉัน เริ่มด้วยบางสิ่งที่ง่ายขึ้นและหาทางแก้ไขเมื่อคุณแก้ปัญหาเหล่านี้
ashes999

Nahhhh ปัญหาข้างต้นเป็นวิธีที่เรียบง่าย / เป็นนามธรรมอย่างละเอียดเพื่ออธิบายปัญหาที่ซับซ้อนมากขึ้น ฉันกำลังทำสิ่งนี้เพื่อความตื่นเต้นในการไล่ล่า!
oodavid
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.