# Frage zur Spielsteuerung bei einem rundenbasiertes Spiel



## Bernd72 (16. Feb 2008)

Hallo zusammen,

habe eine Frage bei der ich einfach nicht weiter komme:
Ich habe ein rundenbasiertes Spiel mit Netzwerkschnittstelle und Computerspieler programmiert.
Soweit läuft eigentlich alles, aber ich habe es folgendermaßen gelöst:
Es läuft eine while (true)-Schleife, die ständig überprüft, ob ein Computerspieler an der Reihe ist um die entsprechende Methode zu starten. Dadurch wird der Prozessor stark belastet auch wenn ein menschlicher Spieler an der Reihe ist, der überlegt.
Hatte vorher die Lösung, das am Ende eines Zuges der nächste Zug aufgerufen wird, das gibt aber eine Verschachtelung, die nicht gewollt ist.
Beim menschlichen Spieler kann man prima mit einem ActionListener arbeiten, der auf Mausklick reagiert. Am liebste wäre mir eine Lösung, die nach diesem prinzip arbeitet, aber ich habe keine Idee wie.
Vielen Dank für eure Hilfe,

Gruß Bernd


----------



## Campino (16. Feb 2008)

Du lässt einfach den Spieler einen Button "fertig" klicken, das hat zur Folge, dass der Computer den nächsten Spieler drannimmt ODER die Runde beendet. Wenn der Spieler ein Computerspieler ist ruft dein Programm die entsprechende Methode auf. Sobald der CS fertig ist, ruft er die Methode auf, die auch aufgerufen wird, wenn dein Mensch seinen FERTIG- Knopf drückt. Wo ist das Problem?


----------



## Bernd72 (17. Feb 2008)

Hallo Campino,
erst mal vielen Dank für deine Antwort.
Den Button "Fertig" benötige ich beim menschlichen Spieler nicht, da die Runde abgeschlossen wird, in dem er auf ein Feld klickt. Hier habe ich kein Problem.
Aber nachdem der menschliche Spieler an der Reihe ist, muss ich überprüfen ob gerade ein menschlicher Spieler, ein lokaler Computerspieler oder ein entfernter Computerspieler an der Reihe ist.
Na klar könnte ich als letzten Befehl der Zugmethoden die Überprüfung stattfindenlassen, aber habe ich dann nicht folgendes Problem?
Methode zugMenschlicherSpieler() ruft im letzten Befehl
werIstDran() auf, diese ruft je nachdem
zugMenschlicherSpieler(), zugLokalerComputerSpieler() oder zugEntfernterComputerSpieler auf, welche im letzten Befehl dann wieder
werIstDran() aufrufen usw.
So wird doch keine Methode zu Ende ausgeführt, ist das kein Problem?

Mir ist eben noch eingefallen ich könnte für jede Spielart eine Spielsteuerung machen, aber ich habe 9 Spielarten ( im Sinne von Mensch gegen Mensch, Mensch gegen lokalen Computer, Mensch gegen entfernten Computer usw.)

Ich hoffe das ist nicht zu verwirrend.

Gruß Bernd


----------



## LordLuzifer (17. Feb 2008)

Ich würde mir mit werIstDran() keine Methode, sondern ein Field zurückgeben lassen. Führe eine Statusvariable ein mit drei Einstellungen Mensch, LokalerComputer, EntfernerComputer und mach davon abhängig was passiert, dann solltest du keine Probleme haben.


----------



## Marco13 (17. Feb 2008)

Das mit der while-Schleife nennt sich "busy waiting" und ist ...  :autsch: (macht man nicht!)

Ganz allgemein: Dafür ist der wait/notify-Mechanismus da!

Allerdings sollte der nur für den Menschlichen SPieler gebraucht werden. Außer wenn die Computerpsieler ihre Züge in eigenen Threads berechnen.

Diese "verschachtelten" Aufrufe sollte man nicht machen (damit müllt man sich den Stack zu - es wird - wie dua auch sagtest - ja NIE eine Methode beendet)

Beschreib' vielleicht mal, wie der grundsätzliche Spielablauf ist oder sein soll. Wenn es ein "klassisches" Rundenbasiertes Spiel ist, kommen doch eigentlich in jeder Runde alle Spieler dran!? Und wenn nicht, dann muss DAS SPIEL wissen, welcher seiner Spieler einen Zug machen muss...

Die Klassenstruktur und die Abläufe sind jetzt nicht ganz klar, aber grundsätzlich könnte das ja sowas sein wie

```
class Game
{
    void play()
    {
        while(!finished())
        {
             if (shouldMove(player0)) player0.doMove();
             if (shouldMove(player1)) player1.doMove();

             // Oder auch sowas wie 
             // activePlayer.doMove();
             // activePlayer = computeNextActivePlayer();
        }
    }
}

abstract class Player { abstract void doMove(); }

class HumanPlayer extends Player implements ActionListener
{
     void doMove()
     {
          moveWasDone = false;
          while (!moveWasDone)
          {
              synchronized(this)
              {
                  try
                  {
                       this.wait(); // Warte, bis der Zug gemacht wurde 
                       //(d.h bis ein Button geklickt und ActionPerformed aufgerufen wurde)
                  } catch (InterruptedException e) {}
              }
         }
     }

      public void actionPerformed(ActionEvent e)
      {
           executeMove(computeMoveFrom(e));
           moveWasDone = true;
           synchronized(this)
           {  
                this.notify(); // Sag' bescheid, dass es bei dem 'wait' oben jetzt weitergehen kann
            }
      }
}


class ComputerPlayer extends Player
{
     void doMove()
     {
           executeMove(computeBestMove());
     }
}
```


----------



## Bernd72 (17. Feb 2008)

Hallo zusammen,

vielen Dank für eure Hilfe.
Das Posting von Marco13 hat mir super geholfen.
Im Prinzip hatte ich es so gemacht bei meiner Lösung mit dem busy waiting. Nur das ich den menschlichen Spieler hier nicht eingebaut hatte und die Schleife  dann nicht auf den Klick gewartet hat, sondern die Schleife ständig durchlief bis wieder ein Computerspieler an der Reihe war.
Jetzt habe ich noch ein Problem mit dem aktualisieren der Grafik während der Züge (Ich weiß, mit Threads arbeiten, aber ich kriegs einfach nicht hin), aber ich denke das würde hier zu weit führen.

Schöne Grüße
Bernd


----------

