Seite 2 von 3

Re: Soft-Timeouts auf dem Wettkampf-System

Verfasst: Do 13. Mär 2014, 18:24
von fischfasch
Also ich habe glaube ich das selbe Problem, aber in Java - Ich bekomme folgende ausgabe im log(sin die zeitmessngen die meine KI in der Konsole ausgibt):

t: 1706
t: 1725
t: 1702
t: 1718
t: 1702
t: 1702
t: 1702
t: 1700
t: 1700
t: 1701
t: 1705
t: 1701
t: 1703
t: 1710
t: 1718
t: 1701
t: 2259

Es ist jetz nich so als ob ich mir nicht vorstellen könnte einen Fehler gemacht zu haben, aber es ist schon komisch, dass es fast immer funktioniert, dann jedoch bei einer Berechnung ebenfalls wie bei der anderen Person mit dem Problem 200 Sekunden drüber liegt und vorallem bei mir auch genau dann nicht funktioniert wenn ich es hochlade/in testläufen laufen lasse, aber in einem normalen Spiel immer fehlerfrei durchläuft. Da weiß ich mitlerweile auch nichmehr wo der Fehler jetz liegen könnte. Vielleicht sollte ich ja eine andere herangehensweise wählen? Aktuell arbeite ich mit System.nanoTime() um die Zeiten zu messen und breche einen thread ab wenn eine zeitüberschreitung erreicht ist und versuche so meine Zeit zu regeln... Nach dem 3ten Test hat er es zwar durchegehn lassen aber ich denke wohl nicht, dass das Problem damit gelöst ist.

Re: Soft-Timeouts auf dem Wettkampf-System

Verfasst: Fr 14. Mär 2014, 11:59
von SvenK
Ich bin weiterhin wachsam. Es hilft, wenn ihr mir Links zu Spielen/Tests im Wettkampfsystem schickt, wo solche Timeouts aufgetreten sind, damit ich mir das genauer ansehen kann. Inzwischen haben wir auch weitere Messungen eingebaut, die uns helfen sollen, ein moegliches Problem zu identifizieren.

Re: Soft-Timeouts auf dem Wettkampf-System

Verfasst: Fr 14. Mär 2014, 14:26
von Eror
SvenK hat geschrieben:Ich bin weiterhin wachsam. Es hilft, wenn ihr mir Links zu Spielen/Tests im Wettkampfsystem schickt, wo solche Timeouts aufgetreten sind, damit ich mir das genauer ansehen kann.


Ich habe hier den Client mit dem ich das Zeitlimit geprüft habe.

Die einzigen Unterschiede zum Delphi-SimpleClient liegen in der Unit UClient an den markierten Stellen in Zeile 13, 160, 162 und 204.
Der Client beendet nach 1,5 Sekunden seinen Zug (Zumindest sollte er das).
Auf meinem Rechner läuft dieser Client ohne Zeitprobleme.

Online besteht dieser Client den Test nicht, sondern wird ca. jedes 2. Spiel wegen Soft-Timeout disqualifiziert.
Dieser Fehler tritt auch bei 1,3 Sekunden statt 1,5 auf, nur etwas seltener.

Aus irgendeimem Grund kann ich keine Dateianhänge hochladen ("Konnte Dateianhang nicht nach ./files/111_d9b2e9daf46186af97a2adb2fefe5646 hochladen."), daher hier der Quelltext:

Code: Alles auswählen

unit UClient;

(*
 * Diese Unit enthält die Spiellogik
 *
 * Im Auslieferungszustand ist hier beispielhaft eine einfache Spiellogik implementiert, die das Spiel
 * fehlerfrei spielen kann. Die Züge werden allerdings größtenteils zufällig ausgeführt.
 *)

interface
  uses UPlayer, UBoard, UDebugHint, UMyBoard, UMove, UField, ULayMove,
  UExchangeMove, UStone, UUtil, SysUtils, Classes, UInteger,
  Windows;//geändert!!!!!
  type
    TClient = class
      protected
        FMyId : Integer;                        // Die SpielerID dieses Clients (0 oder 1)
        FPlayers : array [0..1] of TPlayer;     // Die beiden teilnehmenden Spieler
        FBoard : TMyBoard;                      // Das Board des Spiels
        FActivePlayer : String;                 // Der Spieler, der gerade an der Reihe ist ("red" oder "blue")
        FTurn : Integer;                        // Nummer des aktuellen Zuges
        Me : TPlayer;                           // Der Spieler, der von diesem Client gesteuert wird
        Opponent : TPlayer;                     // Der Spieler, der vom Client des Gegenspielers gesteuert wird
        LastMove : TMove;                       // Der in diesem Spiel zuletzt getätigte Zug oder nil
      public
        function getPlayer(playerNum : Integer) : TPlayer; overload;
        function getPlayer(displayName : String) : TPlayer; overload;
        function getBoard : TBoard;
        function zugAngefordert : TMove;
        function macheZufallszug : TMove;
        function platziereStein(stone : TStone) : Boolean;

        procedure setId(playerId : Integer);

        property MyId : Integer read FMyId write FMyId;
        property CurrentTurn : Integer read FTurn write FTurn;
        constructor Create(board : TMyBoard);
        destructor destroy; override;
    end;

implementation

uses UNetwork, Math;
  destructor TClient.destroy;
  begin
    if(FPlayers[0] <> nil) then FPlayers[0].Free;
    if(FPlayers[1] <> nil) then FPlayers[1].Free;
    inherited;
  end;

  (*
   * Platziert den gegebenen Stein an einer zufälligen, gültigen Position
   * (Probiert alle freien Felder aus, die an bereits belegte Felder angrenzen)
   *)
  function TClient.platziereStein(stone : TStone) : Boolean;
  var
    x, y : Integer;
  begin
    Result := true;
    for x := 0 to 15 do begin
      for y := 0 to 15 do begin
        if FBoard.isOccupied(x, y) then begin  // Finde belegtes Feld
          if FBoard.layStoneAt(stone, x - 1, y) then exit; // Probiere links davon
          if FBoard.layStoneAt(stone, x + 1, y) then exit; // Probiere rechts davon
          if FBoard.layStoneAt(stone, x, y - 1) then exit; // Probiere oberhalb
          if FBoard.layStoneAt(stone, x, y + 1) then exit; // Probiere unterhalb
        end;
      end;
    end;
    Result := false;
  end;

  (*
   * Macht einen mehr oder weniger zufällig ausgewählten Zug.
   *
   * 1. Fall: Mache den allerersten Zug des Spiels:
   * Versuche, zwei Steine zu finden, die zusammen zufällig auf dem Brett platziert
   * werden können.
   *
   * 2. Fall:
   * Probiere der Reihe nach alle Steine durch. Versuche, für jeden Stein eine
   * gültige Position zum Anlegen zu finden.
   *
   * In beiden Fällen wird, falls kein Legezug gefunden wird, eine zufällige Anzahl
   * an Steinen eingetauscht.
   *)
  function TClient.macheZufallszug : TMove;
    var
      layMove : TLayMove;               // Der Legezug, der gemacht wird, wenn einer gefunden wird
      exchangeMove : TExchangeMove;     // Der Tauschzug, der gemacht wird, wenn kein Legezug gefunden wurde
      n, o, x, y: Integer;
      stone, stone2 : TStone;
    begin
      writeln('');
      write('Punkte danach: ');
      writeln(IntToStr(FBoard.getScoresForPlayer(Me.PlayerID)));

      layMove := nil;
      exchangeMove := TExchangeMove.create;
      // Wenn Anfangszug: Zwei Steine finden, die zusammenpassen und diese zufällig positionieren
      if LastMove = nil then begin
        for n := 0 to Me.Stones.Count - 1 do begin
          if layMove <> nil then Break; // Wenn bereits ein Zug gefunden wurde, breche ab
          stone := TStone(Me.Stones[n]);
          if (RandomRange(0, 2) = 0) then exchangeMove.addStoneToExchange(stone);  // Füge Stein möglicherweise zum Tauschzug hinzu
          for o := n + 1 to Me.Stones.Count - 1 do begin
            if layMove <> nil then Break; // Wenn bereits ein Zug gefunden wurde, breche ab
            stone2 := TStone(Me.Stones[o]);
            // Prüfe, ob die beiden Steine zusammen liegen dürfen
            if stone.canBeInSameRowWith(stone2) then begin
              // Passende Steine gefunden, positioniere sie irgendwo horizontal nebeneinander
              y := RandomRange(0, 16);
              x := RandomRange(0, 15);
              layMove := TLayMove.create;
              layMove.addStoneToField(stone, FBoard.getField(x, y));
              layMove.addStoneToField(stone2, FBoard.getField(x + 1, y));
            end;
          end;
        end;
        if layMove = nil then begin
          // Sicherstellen, dass der Tauschzug mindestens einen Stein enthält
          if exchangeMove.stonesToExchange.Count = 0 then exchangeMove.addStoneToExchange(TStone(Me.Stones[0]));
          Result := exchangeMove;
        end else begin
          Result := layMove;
        end;
      end else begin
        // Wenn kein Anfangszug, dann alle liegenden Steine durchgehen
        // Jeden Stein zufällig für einen möglichen Tauschzug auswählen
        // Außerdem für jeden Stein prüfen, ob er irgendwo angelegt werden kann
        // Wenn ein Stein zum Anlegen gefunden wurde, diesen Zug ausführen.
        for n := 0 to Me.Stones.Count - 1 do begin
          stone := TStone(Me.Stones[n]);
          if (RandomRange(0, 2) = 0) then exchangeMove.addStoneToExchange(stone);  // Füge Stein möglicherweise zum Tauschzug hinzu
          if platziereStein(stone) then Break; // Versuche, den Stein anzulegen
        end;

        // Wenn ein möglicher Anlegezug gefunden wurde, diesen ausführen, ansonsten den Tauschzug ausführen
        layMove := FBoard.createLayMove;
        if (layMove = nil) then begin
          // Sicherstellen, dass der Tauschzug mindestens einen Stein enthält
          if exchangeMove.stonesToExchange.Count = 0 then exchangeMove.addStoneToExchange(TStone(Me.Stones[0]));
          Result := exchangeMove;
        end else begin
          exchangeMove.Free;
          Result := layMove;
        end;
      end;
    end;

  (*
  Wird aufgerufen, wenn ein Zug angefordert wurde.
  Soll einen gültigen Zug zurückliefern. Gibt diese Funktion keinen
  oder einen ungültigen Zug zurück, ist das Spiel verloren.
  *)
  function TClient.zugAngefordert : TMove;
    var
      mov : TMove;

      Start:Cardinal;//geändert!!!!!
    begin
      Start:=Gettickcount;//geändert!!!!!

      // Die beiden Spieler zur Übersicht als Ich und Gegner ordnen
      if(FPlayers[0].PlayerID = FMyId) then begin
        Me := FPlayers[0];
        Opponent := FPlayers[1];
      end
      else begin
        me := FPlayers[1];
        opponent := FPlayers[0];
      end;

      write('Punkte vor dem Zug: ');
      writeln(IntToStr(FBoard.getScoresForPlayer(Me.PlayerID)));

      if FBoard.LastMove <> nil then begin
        LastMove := FBoard.LastMove;
        write('Letzter Zug: ');
        writeln(FBoard.LastMove.toString());
      end;

      writeln(FBoard.toString());

      // Zufälligen Zug berechnen lassen
      mov := macheZufallszug;

      if (mov <> nil) then begin
        writeln('Zug gefunden: ');
        if mov is TLayMove then begin
          writeln('Legezug');
          mov.addHint(TDebugHint.create('Legezug'));
        end else if mov is TExchangeMove then begin
          writeln('Tauschzug');
          mov.addHint(TDebugHint.create('Tauschzug'));
        end;
        writeln(mov.toString);
      end else begin
        writeln('KEIN ZUG GEFUNDEN!');
      end;

      Result := mov;

      while GetTickCount-Start<1500 do ;//geändert!!!!!
    end;

  procedure TClient.setId(playerId : Integer);
    begin
      FMyId := playerId;
    end;

  function TClient.getPlayer(playerNum : Integer) : TPlayer;
    begin
      Result := FPlayers[playerNum];
    end;

  function TClient.getPlayer(displayName : String) : TPlayer;
    begin
      Result := nil;
      if(FPlayers[0].DisplayName = displayName) then begin
        Result := FPlayers[0];
      end
      else if(FPlayers[1].DisplayName = displayName) then begin
        Result := FPlayers[1];
      end;
    end;

  function TClient.getBoard : TBoard;
    begin
      Result := FBoard;
    end;

  constructor TClient.Create(board : TMyBoard);
    begin
      inherited Create;
      // Die zwei Spieler werden schonmal erstellt.
      FPlayers[0] := TPlayer.Create('Spieler 1');
      FPlayers[1] := TPlayer.Create('Spieler 2');

      Randomize;
      FBoard := board;
    end;
end.


Überprüf das gerne. 500 bzw. 700ms Verzögerung scheint mir doch ein wenig zu hoch, zumal dies in den letzten Jahren, wie bereits erwähnt nicht auftrat.

Re: Soft-Timeouts auf dem Wettkampf-System

Verfasst: Mo 17. Mär 2014, 14:31
von SvenK
Bitte testet Eure Clients jetzt nochmal bezueglich der Timeouts auf dem Wettkampsystem. Ich habe einige Aenderungen vorgenommen und mein Test-Client, der bis auf 50ms an das Soft-Timeout rangeht laeuft jetzt ohne Probleme. Bitte gebt mir hier schnellstmoeglich bescheid, ob das Problem auch bei euren Clients verschwunden ist.

Re: Soft-Timeouts auf dem Wettkampf-System

Verfasst: Mo 17. Mär 2014, 17:45
von Eror
SvenK hat geschrieben:Bitte testet Eure Clients jetzt nochmal bezueglich der Timeouts auf dem Wettkampsystem.


Das mit abgewandeltem Delphi-Simpleclient gemessene Zeitlimit liegt jetzt irgendwo zwischen 1500 und 1550 ms. Dies entspricht einer Steigerung von 200 ms. Erwähnenswert finde ich auch dass diese Begrenzung nun stabil ist, vorher hatte es immer mal eine Disqualifikation gegeben und mal nicht.

Ich bin mir nicht sicher ob ich mich damit schon zufrieden geben kann, zumal immer noch 25% der Zeit verloren gehen.

SvenK hat geschrieben:Ich habe einige Aenderungen vorgenommen und mein Test-Client, der bis auf 50ms an das Soft-Timeout rangeht laeuft jetzt ohne Probleme.


Handelt es sich dabei um einen Delphi-Client? Wenn nicht könntest Du bitte auch einen solchen testen? Den Quelltext, wie ich es machen würde habe ich bereits gepostet.

Re: Soft-Timeouts auf dem Wettkampf-System

Verfasst: Di 18. Mär 2014, 11:26
von SvenK
Eror, ich habe mir die Server-Logs Deiner Tests gestern Nachmittag angesehen. Der Simpleclient mit Limit 1900ms ueberschreitet nur noch ganz marginal das Timeout (um etwa 50ms). D.h. auch beim Delphi-Client sollte es keine Probleme geben, wenn man eine Toleranz von etwa 200ms mit einberechnet. Seltsamerweise haben auch Deine spaeteren Tests mit niedrigeren Limits sehr aehnliche Zeitmessungen wie der 1900er Client. Bist Du sicher, dass diese Clients nicht irrtuemlich auch das 1900er Limit benutzen?

Re: Soft-Timeouts auf dem Wettkampf-System

Verfasst: Di 18. Mär 2014, 22:23
von Eror
SvenK hat geschrieben:Bist Du sicher, dass diese Clients nicht irrtuemlich auch das 1900er Limit benutzen?


Ja, ich habe das gerade eben noch einmal getestet indem ich mir die gewartete Zeit ausgeben lasse:

Code: Alles auswählen

mov.addHint(TDebugHint.create(IntToStr(Gettickcount-Start)+'ms'));

Diese Zeile steht bei mir am Ende von TClient.zugAngefordert.

und komme dabei auf ziemlich genau 1550ms, 1900ms und 1500ms, wie es sich gehört. Beim erneuten Testen ist übrigens auch der 1500ms-Client bei einem von zwei Spielen disqualifiziert worden.


SvenK hat geschrieben:Seltsamerweise haben auch Deine spaeteren Tests mit niedrigeren Limits sehr aehnliche Zeitmessungen wie der 1900er Client.


Entweder die Zeit braucht der Client nachdem er aus TClient.zugangefordert raus ist, wobei er dann ja auch auf meinem Rechner disqualifiziert werden müsste, oder der Zug wird seeehr langsam gesendet oder das Problem liegt auf den Servern, die die Zeit falsch messen (warumauchimmer).

SvenK hat geschrieben:Der Simpleclient mit Limit 1900ms ueberschreitet nur noch ganz marginal das Timeout (um etwa 50ms).


Woran erkennst Du das? Überseh ich da etwas in den Logdateien? Oder schreibt der Server extra Logdateien, die ich nicht einsehen kann?

Re: Soft-Timeouts auf dem Wettkampf-System

Verfasst: Mi 19. Mär 2014, 07:49
von SvenK
Der Server zeichnet die gemessenen Zugzeiten auf, die dann auch entscheidend für eine Disqualifikation sind. Und da wurden jetzt durchgehend Zeiten von etwa 2040ms bei einem SoftTimeout aufgezeichnet, sowohl beim 1500ms Client als auch beim 1900ms Client.

Re: Soft-Timeouts auf dem Wettkampf-System

Verfasst: Mi 19. Mär 2014, 17:26
von Eror
SvenK hat geschrieben:Der Server zeichnet die gemessenen Zugzeiten auf, die dann auch entscheidend für eine Disqualifikation sind. Und da wurden jetzt durchgehend Zeiten von etwa 2040ms bei einem SoftTimeout aufgezeichnet, sowohl beim 1500ms Client als auch beim 1900ms Client.


Und wieso weichen diese von meinen im Debug-Hinweis angegeben Zeiten ab?
Du weichst meinen Fragen aus.

Re: Soft-Timeouts auf dem Wettkampf-System

Verfasst: Do 20. Mär 2014, 07:56
von SvenK
Es wird immer eine Abweichung geben, da die vom Server gemessene Zeit die Zeit vom Senden der Zuganforderung an den Client bis zum vollstaendigen Emfpang der Antwort des Clients ist, der Client aber bestenfalls die Zeit vom Empfang der Zuganforderung bis zum Senden der Antwort messen kann. Vorausgesetzt, die Zeitmessung auf dem Client erfasst auch wirklich diese gesamte Zeit, sollte die Abweichung relativ gering sein. Schwankungen lassen sich aber nicht vermeiden und koennen je nach verwendeter Technologie sehr unterschiedlich ausfallen. Bis auf weiteres muessen wir uns mit dem jetzigen Stand zufrieden geben, aber da sowieso einige grosse Aenderungen am System geplant sind, werde ich das in dem Zusammenhang nochmal untersuchen.