Spieler gleichzeitig auf dasselbe Feld bewegen?

15

Betrachten Sie ein 2 x 2-Gitter von Quadraten. Ein Spieler kann ein Feld betreten, wenn:

  • Kein anderer Spieler möchte in der nächsten Runde auf das Feld ziehen
  • Kein anderer Spieler hat gewartet und belegt in diesem Zug noch das Feld

Beispieldiagramm

Ich habe das Bild oben eingefügt, um mein Problem zu beschreiben.

Spieler bewegen sich gleichzeitig.

Wenn zwei (oder mehr) Spieler versuchen, sich auf dasselbe Feld zu bewegen, bewegt sich keiner.

t123
quelle
1
Kann sich der Spieler in einem Schritt zu den anderen Plättchen bewegen? Können zum Beispiel Gelb und Blau in genau demselben Schritt die Plätze tauschen (Blau geht eine Kachel nach links und Gelb geht eine Kachel nach rechts)?
Ali1S232,
Gajet ja erstmal. Aber irgendwann möchte ich nicht, dass 2 benachbarte Spieler direkt die Plätze tauschen können
t123 29.09.11
dann löst meine Antwort dieses Problem.
Ali1S232,
2
EXTREM relevant: Überprüfen Sie die Bewegungsregeln für die Diplomatie. en.wikipedia.org/wiki/Diplomacy_(game)#Movement_phase
TehShrike

Antworten:

11
  1. Kennzeichnen Sie alle Spieler als stationär oder in Bewegung, je nachdem, ob sie in diesem Zug einen Zug ausgeführt haben.
  2. Gehen Sie die Liste der Züge durch. Wenn zwei Züge auf dieselbe Position zeigen, entfernen Sie sie aus der Liste und stellen Sie die Spieler still.
  3. Durchlaufen Sie die Liste und entfernen Sie alle Züge, die auf einen stationären Spieler oder ein anderes Hindernis zeigen. Tun Sie dies so oft, bis sich die Liste beim Durchlaufen nicht mehr ändert.
  4. Bewegen Sie alle Spieler.

Ich denke das sollte funktionieren. Es funktioniert auf jeden Fall für den Fall, den Sie gepostet haben, und für einige andere triviale Fälle, an denen ich es getestet habe.

SimonW
quelle
Ja, das sollte funktionieren. Beachten Sie, dass Sie die Liste der Spieler nicht wiederholt durchlaufen möchten. In der Praxis wird es viel effizienter sein, Kollisionen durch Rückverfolgung aufzulösen.
Ilmari Karonen
16

Kollisionsauflösung statt Kollisionsverhütung.

Verschieben Sie einfach die Objekte und prüfen Sie, ob Kollisionen aufgetreten sind. Wenn eine Kollision mit einem anderen Block aufgetreten ist, gehen Sie zurück zum vorherigen Feld oder, abhängig vom Spieltyp, zu einem anderen Feld.

ultifinitus
quelle
1
Ja, aber wenn man sich
zurückziehen
2
Sie haben Recht, aber es hängt wieder vom tatsächlichen Spieltyp ab. Weitere Informationen wären erforderlich und die Situation würde sich je nach Typ ändern. Dies war ungefähr die allgemeinste verfügbare Antwort.
Ultifinitus
5
Sie müssen nicht alle Kollisionen in einem Schritt lösen. Verschieben Sie alle Objekte. Überprüfen Sie, ob es Kollisionen gibt. Rückwärtsbewegungen in Bezug auf diese Kollision. Wiederholen Sie diesen Vorgang, bis keine Kollision mehr vorhanden ist.
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

Dies setzt voraus, dass sich jeder Spieler merkt, wo er gerade hingezogen ist, damit er zurückkehren kann, und dass er sich auch daran erinnert, ob er in diesem Zug umgezogen ist. Diese zweite Überprüfung bedeutet, dass jedes Stück nur einmal zurückgegeben werden muss und sicherstellen muss, dass der Algorithmus ordnungsgemäß beendet wird. Es wird auch sichergestellt, dass nur Spieler zurückgegeben werden, die sich bewegt haben - der ursprüngliche Insasse bleibt erhalten, da sie nicht zum Entfernen in Betracht gezogen werden.

Kylotan
quelle
3

Eine andere Lösung besteht darin, eine Karte zu verwenden, die 2x größer ist als das, was Sie anzeigen. Jedes Mal, wenn Sie Spieler verschieben möchten, verschieben Sie diese zweimal, damit die Spieler immer auf Feldern mit gleichem Wert für X und Y landen. Auch hier gibt es einige seltene Fälle, die mehr Aufmerksamkeit erfordern, aber die meisten möglichen Fälle sind gelöst (wie der von Ihnen) beschrieben) ohne nachzudenken.

Ali1S232
quelle
Ich denke, dass Sie hier etwas im Sinn haben, aber es kommt in Ihrer Antwort nicht durch. Wie löst die Verwendung einer 2x-Karte das Kollisionsproblem?
Zan Lynx
Okay. Ich glaube ich sehe die Antwort. Zwei Teile, die sich in entgegengesetzte Richtungen bewegen, landen auf demselben Feld und kollidieren. Teile, die sich im Uhrzeigersinn bewegen, bewegen sich in halben Schritten und lassen immer einen freien Raum, in den sich ein anderes Teil bewegen kann.
Zan Lynx
@ZanLynx: Genau so wird das Problem gelöst. Das einzige Problem besteht darin, dass zwei Teile (z. B. Grün und Blau) kollidieren und ein weiteres Teil (Gelb) die letzte Position von Grün ausfüllt. In ähnlichen Fällen (sofern möglich) müssen Sie die Kollisionen wie vom Ultifinitus vorgeschlagen beheben.
Ali1S232
Die einfachste Implementierung, die ich für die Kollisionserkennung kenne, ist eine Mischung aus meiner und Ultifinitus. Meins ist gut, um zu überprüfen, ob sich Teile kreuzen, und Unltifinitus ist gut, um andere Arten von Kollisionen zu lösen.
Ali1S232
0

Registrieren Sie alle angeforderten Züge mithilfe eines Arrays oder einer Karte.

Wenn ein Konflikt vorliegt, setzen Sie die betreffende Verschiebungsanforderung zurück. Wenn das Objekt auf ein Feld zurückgesetzt wird, das ein anderes Objekt zu besetzen versucht, setzen Sie die Anforderung des anfordernden Objekts zurück.

Pseudocode:

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);
    }
}
Charles Goodwin
quelle
0

Aufbauend auf der Antwort von SimonW folgt ein expliziter Algorithmus:

Sei squaresein Array, das von den Player-Standorten indiziert wird und für jeden möglichen Standort entweder den Index eines anderen Standorts oder den speziellen Wert enthält NULL. (Möglicherweise möchten Sie dies als spärliches Array speichern.) Die möglichen Werte der Einträge in diesem Array können wie folgt interpretiert werden:

  • Wenn squares[S]ja NULL, kann das Quadrat Sfrei betreten werden.
  • Wenn squares[S] == Ssich entweder der Spieler von Snicht bewegen kann oder will oder zwei (oder mehr) Spieler gleichzeitig zu bewegen versuchten Sund beide abgelehnt wurden.
  • Andernfalls squares[S]wird der Index des Quadrats enthalten, von dem ein Spieler zum Quadrat wechseln möchte S.

Initialisieren Sie in jeder Runde alle Einträge von squaresto NULLund führen Sie dann den folgenden Algorithmus aus:

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

Danach durchlaufen Sie die Liste der Spieler noch einmal und verschieben Sie diejenigen, die dazu in der Lage sind:

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

Da jeder Zug nur einmal geplant und höchstens einmal abgebrochen werden kann, wird dieser Algorithmus auch im schlimmsten Fall in O ( n ) Zeit für n Spieler ausgeführt.

( Leider hindert dieser Algorithmus die Spieler nicht daran, Plätze zu wechseln oder Pfade diagonal zu kreuzen. Es ist möglicherweise möglich, Gajets Zweistufentrick darauf abzustimmen , aber die völlig naive Art, dies zu tun, funktioniert nicht und ich bin zu müde um einen besseren Weg zu finden.)

Ilmari Karonen
quelle