ย้ายผู้เล่นไปที่ช่องสี่เหลี่ยมเดียวกันพร้อมกันไหม


15

ลองพิจารณาตารางกำลังสอง x 2 ผู้เล่นสามารถย้ายไปยังช่องสี่เหลี่ยมถ้า:

  • ผู้เล่นคนอื่นไม่ต้องการย้ายเข้าไปในจัตุรัสถัดไป
  • ไม่มีผู้เล่นคนอื่นรอและยังคงครองจัตุรัสในเทิร์นนี้

ตัวอย่างไดอะแกรม

ฉันได้รวมภาพด้านบนเพื่ออธิบายปัญหาของฉัน

ผู้เล่นเคลื่อนที่พร้อมกัน

หากผู้เล่น 2 คน (หรือมากกว่า) พยายามที่จะย้ายเข้าไปในสี่เหลี่ยมเดียวกันไม่ขยับ


1
ผู้เล่นสามารถย้ายไปยังไทล์ของแต่ละคนในขั้นตอนเดียวได้ไหม ตัวอย่างเช่นสวิตช์สีเหลืองและสีน้ำเงินสามารถวางในขั้นตอนเดียวกันทุกประการ (สีฟ้าไปทางซ้ายหนึ่งไทล์และสีเหลืองไปทางขวาหนึ่งไทล์)?
Ali1S232

ตอนนี้ใช่แล้ว แต่ในบางจุดฉันไม่ต้องการให้ผู้เล่น 2 คนที่อยู่ใกล้เคียงสามารถแลกเปลี่ยนสถานที่ได้โดยตรง
t123

จากนั้นคำตอบของฉันจะแก้ไขปัญหานั้น
Ali1S232

2
มีความเกี่ยวข้องอย่างยิ่ง: ตรวจสอบกฎการเคลื่อนไหวเพื่อการทูต en.wikipedia.org/wiki/Diplomacy_(game)#Movement_phase
TehShrike

คำตอบ:


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

ฉันคิดว่าควรจะทำงาน มันใช้งานได้กับกรณีที่คุณโพสต์และอีกสองกรณีที่ฉันทดสอบเล็กน้อย


ใช่สิ่งนี้น่าจะใช้ได้ โปรดทราบว่าคุณไม่ต้องการวนซ้ำในรายชื่อผู้เล่น ในทางปฏิบัติมันจะมีประสิทธิภาพมากขึ้นในการแก้ไขการชนโดยการย้อนรอย
Ilmari Karonen

16

การแก้ปัญหาการชนแทนการป้องกันการชน

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


1
ใช่ แต่ถ้าต้องย้ายกลับคนอื่นก็จะต้องย้ายกลับด้วย ...
t123

2
คุณถูกต้อง แต่อีกครั้งมันขึ้นอยู่กับประเภทของเกมจริงจะต้องมีข้อมูลเพิ่มเติมและสถานการณ์จะเปลี่ยนไปตามประเภท นี่เป็นคำตอบทั่วไปที่มีอยู่
ultifinitus

5
คุณไม่จำเป็นต้องแก้ไขการชนทั้งหมดในขั้นตอนเดียว ย้ายวัตถุทั้งหมดตรวจสอบว่ามีการย้อนกลับของการชนใด ๆ ที่เกี่ยวข้องกับการชนกันหรือไม่ให้ทำซ้ำกระบวนการนี้จนกว่าจะไม่มีการชนกัน
Ali1S232

4
Move all players according to their request.
while there are still some squares multiply occupied:
    For each square that is now multiply occupied:
        For each player in that square that moved there this turn:
            Return them to their previous square
            Mark them as having not moved this turn

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


3

อีกวิธีหนึ่งคือการใช้แผนที่ 2x ใหญ่กว่าที่คุณแสดง แต่ละครั้งที่คุณต้องการย้ายผู้เล่นคุณต้องย้ายพวกเขาสองครั้งดังนั้นผู้เล่นจะลงจอดบนไทล์ด้วยค่าที่เท่ากันสำหรับทั้ง X และ Y อีกครั้งจะมีบางกรณีที่หายากที่จะต้องให้ความสนใจมากขึ้น อธิบาย) โดยไม่ต้องคิดสองครั้ง


ฉันคิดว่าคุณมีบางสิ่งบางอย่างในใจที่นี่ แต่มันไม่ผ่านในคำตอบของคุณ การใช้แผนที่ 2x ช่วยแก้ปัญหาการชนได้อย่างไร
Zan Lynx

ตกลง. ฉันคิดว่าฉันเห็นคำตอบ สองชิ้นเคลื่อนที่ไปในทิศทางตรงกันข้ามกับที่ดินในจตุรัสเดียวกันและชนกัน ชิ้นส่วนที่เคลื่อนที่ไปตามเข็มนาฬิกาจะขยับครึ่งก้าวตามเข็มนาฬิกาโดยเว้นช่องว่างไว้เพื่อให้ชิ้นส่วนอื่นเคลื่อนเข้ามา
Zan Lynx

@ZanLynx: นั่นเป็นวิธีแก้ปัญหาปัญหาเดียวที่เกิดขึ้นเมื่อสองชิ้น (พูดว่าสีเขียวและสีน้ำเงิน) กำลังชนกันและอีกชิ้นหนึ่ง (สีเหลือง) จะเติมตำแหน่งสุดท้ายของสีเขียว ในกรณีที่คล้ายกับสิ่งเหล่านี้ (ถ้าเป็นไปได้) คุณจำเป็นต้องแก้ไขการชนตามคำแนะนำของ ultifinitus
Ali1S232

การใช้งานที่ง่ายที่สุดที่ฉันรู้สำหรับการตรวจจับการชนกันคือการผสมผสานระหว่างของฉันและ ultifinitus ของฉันเป็นสิ่งที่ดีที่จะตรวจสอบว่าชิ้นส่วนที่มีการข้ามซึ่งกันและกันและ unltifinitus เป็นสิ่งที่ดีในการแก้ปัญหาการปะทะกันประเภทอื่น ๆ
Ali1S232

0

ลงทะเบียนการเคลื่อนไหวที่ร้องขอทั้งหมดโดยใช้อาร์เรย์หรือแผนที่

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

รหัสหลอก:

int[][] game; // game board

var doMoves() {
    int[][] dest = [][]; // destinations; cleared each run

    for (obj in gameObjects)
        if (obj.moveRequest) {
            var o = dest[obj.moveX][obj.moveY];
            if (o) {
                // collision!
                o.doNotMove = true;
                obj.doNotMove = true;
            } else {
                dest[obj.moveX][obj.moveY] = obj;
            }
        }
    }

    // check move validity
    for (obj in gameObjects) {
        if (obj.doNotMove) continue;

        var o = game[obj.moveX][obj.moveY];
        if (o and o.doNotMove)
            revertRequest(obj, dest);
    }

    // process moves
    //etc
}

// recursive function to back up chained moves
var revertRequest(obj, dest) {
    if (!obj.doNotMove) {
        obj.doNotMove = true;
        var next = dest[obj.x][obj.y];
        if (next)
            revertRequest(next, dest);
    }
}

0

อาคารในคำตอบของ SimonWที่นี่เป็นขั้นตอนอย่างชัดเจน:

อนุญาตเป็นอาร์เรย์จัดทำดัชนีโดยสถานที่เล่นการพนันและมีสำหรับสถานที่ที่เป็นไปได้ในแต่ละทั้งดัชนีของสถานที่อื่นหรือมูลค่าพิเศษsquares NULL(คุณอาจต้องการเก็บสิ่งนี้เป็นอาร์เรย์หร็อมแหร็ม) ค่าที่เป็นไปได้ของรายการในอาร์เรย์นี้อาจตีความได้ดังนี้:

  • ถ้าsquares[S]เป็นNULLเช่นนั้นสี่เหลี่ยมSมีอิสระที่จะย้ายเข้าไป
  • หากsquares[S] == Sผู้เล่นที่Sไม่สามารถหรือไม่เคลื่อนไหวหรือผู้เล่นสองคน (หรือมากกว่า) พยายามย้ายไปSในเวลาเดียวกันและถูกปฏิเสธทั้งคู่
  • มิฉะนั้นจะมีดัชนีของตารางจากการที่ผู้เล่นต้องการที่จะย้ายไปที่ตารางsquares[S]S

ในแต่ละเทิร์นให้เริ่มต้นรายการทั้งหมดของsquaresถึงNULLแล้วเรียกใช้อัลกอริทึมต่อไปนี้:

for each player:
   current := the player's current location;
   target := the location the player wants to move to (may equal current);
   if squares[target] is NULL:
      squares[target] := current;  // target is free, mark planned move
   else
      // mark the target square as contested, and if necessary, follow
      // the pointers to cancel any moves affected by this:
      while not (target is NULL or squares[target] == target):
         temp := squares[target];
         squares[target] := target;
         target := temp;
      end while
      // mark this player as stationary, and also cancel any moves that
      // would require some else to move to this square
      while not (current is NULL or squares[current] == current):
         temp := squares[current];
         squares[current] := current;
         current := temp;
      end while
   end if
end for

หลังจากนั้นวนรอบรายชื่อผู้เล่นอีกครั้งและย้ายผู้ที่สามารถทำได้:

for each player:
   current := the player's current location;
   if not squares[current] == current:
       move player;
   end if
end for

เนื่องจากการย้ายแต่ละครั้งสามารถวางแผนได้เพียงครั้งเดียวและยกเลิกได้มากที่สุดหนึ่งครั้งอัลกอริทึมนี้จะทำงานในเวลา O ( n ) สำหรับผู้เล่นnคนแม้ในกรณีที่เลวร้ายที่สุด

(อนิจจาอัลกอริธึมนี้จะไม่หยุดผู้เล่นจากการเปลี่ยนสถานที่หรือเส้นทางข้ามในแนวทแยงมุมมันอาจเป็นไปได้ที่จะปรับกลอุบายสองขั้นตอนของ Gajetแต่วิธีที่ไร้เดียงสาอย่างสมบูรณ์ในการทำเช่นนั้นจะไม่ทำงาน เพื่อหาวิธีที่ดีกว่าตอนนี้)

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