Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Strafzeitenverwaltung in eigener Unit (https://www.delphipraxis.net/152335-strafzeitenverwaltung-eigener-unit.html)

torud 18. Jun 2010 17:09


Strafzeitenverwaltung in eigener Unit
 
Hallo Wissende,

nach einiger Abstinenz bin ich nun auch mal wieder hier und hoffe, dass ich meine Frage im richtigen Sub-Forum stelle.

Ich bin gerade dabei ein kleines Uhrenprogramm für Eishockey zu erstellen. In diesem Programm soll eine Spielzeituhr realisiert werden (schon erledigt) und die Strafzeiten müssen für beide Teams erstellt und verwaltet werden.

Ich bin nun etwas am Grübeln, wie ich das am Besten anstellen kann, weil ja die Strafzeiten ablaufen müssen, intern dann aber die eventuell noch 2. laufende Strafzeit des gleichen Teams an Stelle der ersten bereits abgelaufenen Strafzeit gestellt werden soll.

Also mal ganz grob, bevor ich hier zu viel Verwirrung stifte.

Die einfachste Version ist. Das Spiel läuft, es wird gefoult, durch Team A (Heim) und der foulende Spieler erhält eine Zeitstrafe von 2 Minuten. Im Besten Fall läuft die Zeit ab (von 2:00 auf 0:00 oder umgekehrt) und die Uhr kann intern gelöscht werden.

Ungefähre Ausgabe wäre dann:

XML-Code:
<Team who="A" />
<Penalty Nr="1" Time="1:59" />
Nun kann es aber sein, dass innerhalb der aktuell laufenden 2 Minuten Strafe, ein weiteres Foul eines Spielers vom Team A begangen wird. In dem Fall soll also eine weitere Strafzeit hinzugefügt werden. Wir hätten in dem Fall, die noch laufende erste Strafzeit und die neu hinzugekommene Strafzeit.

XML-Code:
<Team who="A" />
<Penalty Nr="1" Time="0:38" />
<Penalty Nr="2" Time="2:00" />
Das Spiel geht nun weiter und beide Strafzeiten laufen. Die "erste" Strafzeit läuft nun auf 0:00 runter. Nun sollte die 2. Strafzeit an Stelle der ersten Strafzeit rutschen.

XML-Code:
<Team who="A" />
<Penalty Nr="1" Time="1:22" />
Ich würde die ganze Logik gern in eine eigene Unit oder Klasse stecken, muss aber zugeben, dass ich nicht wirklich weiss, wo ich anfangen soll. Ich habe schon ein paar Funktionen in Units ausgelagert, aber eine gesamte Struktur noch nie.

Kann mir bitte jemand ein paar Tipps geben? Ich stell auch gern die Sourcen hier ein, wenns soweit ist.

DeddyH 18. Jun 2010 18:21

AW: Strafzeitenverwaltung in eigener Unit
 
Spontan würde ich da eine TObjectList in Betracht ziehen. Du definierst Dir ein Objekt mit den entsprechenden Feldern und fügst dies in die Liste ein. Ist die Zeit abgelaufen, löschst Du das Objekt wieder aus der Liste. Die Ausgabe erfolgt dann zyklisch (Timer) mittels einer Schleife über die Objekte.

Namenloser 18. Jun 2010 18:26

AW: Strafzeitenverwaltung in eigener Unit
 
Man könnte statt der TObjectList auch Delphi-Referenz durchsuchenTQueue benutzen.

DeddyH 18. Jun 2010 18:27

AW: Strafzeitenverwaltung in eigener Unit
 
Das sollte in diesem Fall auf das selbe Ergebnis hinauslaufen, aber klar, wieso nicht?

Namenloser 18. Jun 2010 18:37

AW: Strafzeitenverwaltung in eigener Unit
 
Natürlich kommt das gleiche Ergebnis heraus, wäre ja auch schrecklich, wenn nicht, oder? :shock:
Ich finde, wenn Delphi schon eine Klasse speziell für solche Fälle anbietet, kann man die ruhig auch mal benutzen ;)

torud 18. Jun 2010 18:51

AW: Strafzeitenverwaltung in eigener Unit
 
Hallo,

erstmal danke für Euren Hinweise. Wie gesagt mein Wissen über Units und eigene Klassen ist arg begrenzt. Ich habe jetzt mal so angesetzt. Allerdings erschliesst sich mir noch nicht ganz, wie ich dass dann aufrufen soll, ob ich die Zeiten dann über nen Timer im Hauptfenster aktualisieren muss oder in der Klasse selbst und wo ich nun die Penalties als Liste erhalte...

Fragen über Fragen.

Irgendwas mach/denk ich da noch falsch...

Hier erstmal mein aktueller Stand. Danke für einen prüfend beleerenden Blick.

Delphi-Quellcode:
unit unt_penalties;

interface

type
  TPenalties = class
  public
    Team   : Char;   //character of Team (A or B)
    TTime  : String; //total time of penaltie
    CTime  : String; //current time of penalty
    constructor Create;
    class function AddPenalty(Team:Char;TimeOfPenalty : String): String;   //add a penalty
    class function DeletePenalty(Team:Char;TimeOfPenalty : String): String; //delete a penalty
    class function EditPenalty(Team:Char;TimeOfPenalty : String): String;  //edit a penalty
  end;

implementation

constructor TPenalties.Create;
begin
  inherited;
end;

class function TPenalties.AddPenalty(Team:Char;TimeOfPenalty : String): String;
begin
  //add a penalty
end;

class function TPenalties.DeletePenalty(Team:Char;TimeOfPenalty : String): String;
begin
  //delete a penalty
end;

class function TPenalties.EditPenalty(Team:Char;TimeOfPenalty : String): String;
begin
  //edit a penalty
end;

end.

Namenloser 18. Jun 2010 19:53

AW: Strafzeitenverwaltung in eigener Unit
 
Der Code ist so Unsinn. Du hast hier 2 Klassen zu einer einzigen verschmolzen, bzw. du hast hier eine Klasse, die gleichzeitig die Daten eines einzelnen Eintrages speichert *und* eine Liste von ebendiesen Einträgen verwalten soll. Das kann nicht funktionieren. Grundregel der OOP: Jede Klasse hat genau *eine* Aufgabe zu erfüllen.

Was du brauchst sind 2 Klassen:
- die erste Klasse repräsentiert einen Strafzeit-Eintrag
- die zweite Klasse verwaltet Instanzen dieser Klasse in einer Liste (kann z.B. TQueue oder TObjectList sein)

Ich vermute außerdem, dass du Objekte und Klassen durcheinander wirfst. Ein Objekt ist alles in deiner Umgebung: eine Lampe, ein Schuh, eine Tastatur, eine Maus, ein Mensch... eben Dinge mit bestimmten Eigenschaften (wie z.B. Farbe, Größe etc.) und Methoden (z.B. Laufen, Springen, Essen...).

Eine Klasse hingegen ist quasi ein Bauplan für ein solches Objekt - sie gibt an, welche Felder, Eigenschaften, Methoden etc. es gibt. Das Objekt, d.h. eine Klasseninstanz, ist dann das konkrete "Ding", das durch die Klasse definiert wurde. Hiervon kann es natürlich auch mehrere geben, genau so wie man mehrere Häuser nach dem gleichen Bauplan bauen kann.

Benutzen tust du in der Regel immer nur die konkreten Objekte, nicht die Klassen. Daher sind auch die vielen class functions sicher nicht das was du willst, diese beziehen sich nämlich nicht auf die Instanzen einer Klasse, sondern auf die Klasse (den Bauplan) selbst, was eigentlich nur für Spezialfälle gedacht ist. Du willst aber mit Objekten arbeiten, und das ist mit class functions, so wie du sie verwendest, nicht machbar, da du z.B. nicht auf ein Feld (Variable) eines einzelnen Objekts zugreifen kannst, da die Klasse gar nicht wissen kann, welches Objekt gemeint ist, denn davon kann (und soll) es ja schließlich mehrere geben.

Ich würde dir dringend empfehlen, ein Tutorial (oder noch besser ein Buch) über OOP zu lesen, bevor du weitermachst. Ohne die Grundlagen zu kennen, wirst du dir nämlich nur unnötig in den Fuß schießen. Als Anfänger kann es sehr leicht passieren, dass man seine Klassen nicht sinnvoll aufteilt (wie man z.B. bei deinem Code sieht), und dann hinterher u.U. ein Programm erhält, dass zwar Klassen und Objekte nutzt, aber in trotzdem in keinster Weise objektorientiert ist.

torud 18. Jun 2010 21:00

AW: Strafzeitenverwaltung in eigener Unit
 
Moin Philip,

danke für deine umfangreichen Ausführungen. Ich glaube/hoffe, dass ich es nun etwas besser verstehe. Ich habe nun auch den Code so aufgesplittet, dass die eigentliche Zeitstrafe eine Klasse abgeleitet von TObject ist und Penalties eine Klasse abgeleitet von TObjectlist ist.

Der Code sollte nun um einiges besser aussehen.

Zum besseren Verständnis erlaube ich mir aber trotzdem noch ein paar Fragen. Vorher aber schon mal der Code. Ich habe ihn so kurz wie möglich gehalten.

Delphi-Quellcode:
unit unt_penalty;

interface

type
  TPenalty = class
  public
    Team   : Char;   //character of Team (A or B)
    TTime  : String; //total time of penaltie
    CTime  : String; //current time of penalty
    Direction : byte; //direction of running time 0:asc;1:desc
    constructor Create;
  end;

implementation

constructor TPenalty.Create;
begin
  inherited;
end;

end.
Delphi-Quellcode:
unit unt_penalties;

interface

uses Contnrs, unt_Penalty;

type
  TPenalties = class(TObjectList)
  public
    constructor Create;
    function AddPenalty(Penalty : TPenalty; PenaltyList : TObjectList): TObjectList;   //add a penalty
    function DeletePenalty(Penalty : TPenalty; PenaltyList : TObjectList): TObjectList; //delete a penalty
    function EditPenalty(Penalty : TPenalty; PenaltyList : TObjectList): TObjectList;  //edit a penalty
  end;

implementation

uses Classes;

constructor TPenalties.Create;
begin
  inherited;
end;

function TPenalties.AddPenalty(Penalty : TPenalty; PenaltyList : TObjectList): TObjectList;
begin
  //add a penalty
  with PenaltyList do
    begin
      Add(Penalty);
    end;
end;

function TPenalties.DeletePenalty(Penalty : TPenalty; PenaltyList : TObjectList): TObjectList;
begin
  //delete a penalty
  with PenaltyList do
    begin
      Delete(IndexOf(Penalty));
    end;
end;

function TPenalties.EditPenalty(Penalty : TPenalty; PenaltyList : TObjectList): TObjectList;
begin
  //edit a penalty
end;

end.
Und so habe ich es testhalber im MainForm mal eingebunden:

Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
var
  MyPenalty  : TPenalty;
  MyPenalties : TPenalties;
begin
  //erzeugen des penalty und zuweisen der daten
  MyPenalty := TPenalty.Create;
  MyPenalty.Team := 'A';
  MyPenalty.TTime:= '00:02:00';
  MyPenalty.CTime:= '00:02:00';
  MyPenalty.Direction:= 0;
  //erzeugen der penaltyliste und hinzufügen des penalty
  myPenalties := TPenalties.Create;
  mypenalties.AddPenalty(MyPenalty, MyPenalties);
end;
Es lässt sich kompilieren, aber ich habe natürlich noch das Problem, dass ich nicht weiss, wie ich dann an die einzelnen Penalty-Einträge in der Penaltyliste komme, wenn ich diese z.B.

Löschen, Editieren oder wegen laufenden Uhr updaten möchte...

Die Daten (die einzelnen Zeitstrafen) muss ich natürlich auch im Programm visualiseren, d.h. ich muss natürlich vorher die Daten nach Teams und Höhe der laufenden Uhr sortieren und dann intern (später auch extern) anzeigen.

Hast Du hierfür noch einen Tipp?
Habe ich sonst noch was falsch gemacht?

jfheins 18. Jun 2010 21:12

AW: Strafzeitenverwaltung in eigener Unit
 
1. Empfehlung: Du solltest TPenalty einen Kontruktor spendieren, dem man alle Daten übergeben kann.
2. Fehler: function AddPenalty BITTE keinen 2. Parameter. Das ist sinnlos, dafür ist doch gerade das Objekt da.
3.
Delphi-Quellcode:
Direction : byte; //direction of running time 0:asc;1:desc
???? Eine Penalty läuft doch immer "ab" oder nicht?
4. Datenhaltung. Strings würde ich hier nicht einsetzen. Viel besser wäre ein Zeitpunkt, zu dem die Strafzteit abläuft. Ich weis jetzt nicht, wie du die Spielzeit intern mitnimmt, aber dementsprechend wäre TTime oder integer angebracht. Daten und Darstellung bitte trennen.

das wäre es erstmal von meiner Seite ;)

torud 18. Jun 2010 21:37

AW: Strafzeitenverwaltung in eigener Unit
 
Hallo,

also ich habe die Penalty etwas angepasst.

Delphi-Quellcode:
unit unt_penalty;

interface

uses Classes;

type
  TPenalty = class
  public
    Team   : Char;   //character of Team (A or B)
    TTime  : String; //total time of penaltie
    CTime  : String; //current time of penalty
    Direction : byte; //direction of running time 0:asc;1:desc
    constructor Create(ATeam:Char; ATTime, ACTime : String; ADirection : byte); overload;
    constructor Create; overload;
  end;

implementation

constructor TPenalty.Create;
begin
  inherited;
end;

constructor TPenalty.Create(ATeam:Char; ATTime, ACTime : String; ADirection : byte);
begin
  inherited Create;
  Team     := ATeam;
  TTime    := ATTime;
  CTime    := ACTime;
  Direction := ADirection;
end;

end.
Das Create ist nun doppelt drin. Vielleicht kann das eine ja nun auch ganz raus!?

Zu Deinen Punkten Julius:
1. erledigt
2. ich bin echt ´n Blinder. :cyclops:
3. Wie sicher bist Du Dir da? Ich habe heute einiges an Zeit verbracht dies auf Offiziellen Seiten nachzulesen. Fakt ist. Die reine Spielzeit kann sowol aufsteigen, als auch absteigend angezeigt werden. Kommt auf die Liga an. Insofern, dachte ich mir, dass es günstig sein könnte diese Eigenschaft zu vergeben...
4. Ja. Das ist aktuell meinem internen Zeitverfahren geschuldet und der Frage, an welcher Stelle ich denn dann nun die Zeiten (aktuell Spielzeit und jede einzelne laufende Strafzeit) intern und später dann auch extern aktualisieren lassen soll. Aktuell läuft auf dem Hauptform einfach nur ein Timer, der die Sekunden und Minuten hoch- oder runterzählt.

Verrückt ist im übrigen auch, dass folgendes nach dem Zuweisen der ersten Testdaten nicht möglich ist:
Delphi-Quellcode:
  //erzeugen des penalty und zuweisen der daten
  MyPenalty := TPenalty.Create;
  MyPenalty.Team := 'A';
  MyPenalty.TTime:= '00:02:00';
  MyPenalty.CTime:= '00:02:00';
  MyPenalty.Direction:= 0;
  //erzeugen der penaltyliste und hinzufügen des penalty
  myPenalties := TPenalties.Create;
  mypenalties.AddPenalty(MyPenalty);
  //erneutes zuweisen des penalty aus der liste, um zugriff zu prüfen
  MyPenalty := mypenalties[0];
  ShowMessage(MyPenalty.Team);
Inkompatible Typen TPenalty und TObject (ein as TObject half auch nicht...)

Namenloser 18. Jun 2010 21:56

AW: Strafzeitenverwaltung in eigener Unit
 
Das liegt daran, dass die Eigenschaft Items deiner TPenalties-Klasse (worauf du mit dem []-Operator implizit zugreifst) von TObjectList geerbt ist. TObjectList wurde so konzipiert, dass es Objekte aller Arten speichern kann, deshalb wurde bei der Deklaration der "Urahn" aller Klassen unter Delphi, TObject, gewählt. Da du aber wie gesagt jedes erdenkliche Objekt in dieser Liste speichern kannst, beschwert sich Delphi: Denn es könnte ja etwas völlig anderes als eine TPenalty-Instanz dort gespeichert sein, und das gäbe dann einen Fehler.

Du hast zwei Möglichkeiten: Entweder du machst einen Typecast auf TPenalty, oder du überschreibst gleich in TPenalties die Items-Property. Das geht etwa so:

Delphi-Quellcode:
TPenalties = class(TObjectList)
private
  function GetItem(Index: integer): TPenalty;
  procedure SetItem(Index: integer; AItem: TPenalty);
public
  // Siehe dazu die Online-Hilfe zum Stichwort Properties...
  property Items[Index: integer]: TPenalty read GetItem write SetItem; default;
end;

function TPenalties.GetItem(Index: integer): TPenalty;
begin
  // per inherited wird der gleichnamige Getter von TObjectList aufgerufen,
  // das Ergebnis wird nach TPenalty gecastet
  Result := TPenalty(inherited GetItem(Index));
end;

procedure TPenalties.SetItem(Index: integer; AItem: TPenalty);
begin
  // Hier ist kein Typecast nötig, weil TObject der "Urahn" von allen Klassen
  // und somit auch TPenalty ist, daher also alle Klassen zu den Schnittstellen von
  // TObject kompatibel sind.
  inherited SetItem(Index, AItem);
end;
Natürlich ist es sinnvoll, in dem Zug auch gleich die Methoden Add, Remove etc zu überschreiben, sodass diese ebenfalls typensicher sind, sprich als Parameter TPenalty statt TObject entgegen nehmen. So sicherst du die Klasse auch gegen Bedienfehler von außen ab, denn solange der Nutzer der Klasse es nicht gerade mit Typecasts darauf anlegt, Fehler zu provozieren, schmeißt der Compiler beim Kompilieren jedes mal einen Fehler und bricht den Kompiliervorgang ab, wenn irgendwo ein falsches Objekt zugewiesen wird.

torud 19. Jun 2010 11:09

AW: Strafzeitenverwaltung in eigener Unit
 
Hallo,

vielen Dank für die helfenden Hinweise und das Codebeispiel. Ich denke, dass ich dabei wieder was gelernt habe!

Ich würde nun gern Eure Meinung wissen, wie Ihr die laufenden Uhren verwalten/steuern würdet.
Aktuell ist die laufende Hauptzeit über einen Timer gelöst.

Schön ist sicher anders, aber ich wusste mir nicht anders zu helfen. Soll ich das Increasen/Decreasen der Strafzeitenuhren dann auch hier über den Timer machen, oder wäre das eher nicht so gut!?

Delphi-Quellcode:
//globale Deklaration
var
  original: TSystemTime;

procedure TForm1.int_clockTimer(Sender: TObject);
begin
  //check, how the clock should run
  case rad_direction.ItemIndex of
    0 : begin // clock should run asc
          original.wsecond:= original.wSecond + 1;

          if original.wSecond = 60 then begin
            original.wSecond :=0;
            original.wMinute :=original.wMinute + 1;
          end;
        end;
    1 : begin // clock should run desc
          //stop clock and end case, cause time is up
          if (original.wSecond = 0) and (original.wMinute = 0) then
            begin
              //stop timer
              int_clock.Enabled := false;
            end
          else
            begin
              if original.wSecond = 0 then begin
                original.wSecond := 59;
                original.wMinute := original.wMinute - 1;
              end
              else
                original.wsecond := original.wSecond - 1;
            end;
        end;
  end;
  //show the clock - internal
  lbl_mtime_int.Caption := Format('%.2d:%.2d', [original.wMinute,original.wSecond]);
  btn_set_data.Enabled := not(int_clock.Enabled);
end;

alcaeus 19. Jun 2010 11:41

AW: Strafzeitenverwaltung in eigener Unit
 
Hallo,

Zitat:

Zitat von torud (Beitrag 1030046)
Ich würde nun gern Eure Meinung wissen, wie Ihr die laufenden Uhren verwalten/steuern würdet.
Aktuell ist die laufende Hauptzeit über einen Timer gelöst.

Schön ist sicher anders, aber ich wusste mir nicht anders zu helfen. Soll ich das Increasen/Decreasen der Strafzeitenuhren dann auch hier über den Timer machen, oder wäre das eher nicht so gut!?

Genauer gesagt musst du das sogar. Im internationalen Eishockey wird die letzte Minute inkl. Zehntelsekunden abgearbeitet - wenn jetzt jemand 52.5 Sekunden vor Schluss nen Penalty kommt darfst du diese halbe Sekunde nicht untern Tisch fallen lassen.
Ich empfehle dir hierfuer uebrigens ein Observer-Pattern. Kurz eine Erklaerung:
Du hast eine Klasse GameClock. Diese Methode kapselt einen Timer und hat eine Start/Stop-Methode. Start startet die Uhr, Stop haelt sie an. Beim Starten der Uhr schickst du dann eine Message an alle registrierten PenaltyClocks, dass diese auch starten. Beim Stop funktioniert das analog.

Bei dieser Gelegenheit noch nen Hinweis: beachte dass du nie mehr als 2 Strafzeiten laufen lassen darfst. Ein kleines Beispiel: Mannschaft A kassiert 2 Minuten. PP beginnt, Mannschaft A kassiert nochmal 2 Minuten. Jetzt laufen beide Strafzeiten und A spielt in doppelter Unterzahl. Wenn jetzt nochmal eine Strafe fuer A ausgesprochen wird, landen die 2 Minuten auf der Uhr, werden aber nicht runtergezaehlt bis nicht eine der vorherigen Strafzeiten abgelaufen sind.
Im Beispiel oben bedeutet das: dein Observer-Pattern darf nur die ersten beiden PenaltyClocks einer Mannschaft starten. Laeuft eine PenaltyClock aus, muss sie die erste nicht laufende PenaltyClock der eigenen Mannschaft starten.

So, ich hoffe das macht noch halbwegs Sinn was ich da geschrieben habe ;)

Greetz
alcaeus

torud 19. Jun 2010 12:43

AW: Strafzeitenverwaltung in eigener Unit
 
Hallo,

Zitat:

Zitat von alcaeus (Beitrag 1030052)
Hallo, Genauer gesagt musst du das sogar.

Genau die Antwort, die ich brauchte.

Zitat:

Zitat von alcaeus (Beitrag 1030052)
Im internationalen Eishockey wird die letzte Minute inkl. Zehntelsekunden abgearbeitet - wenn jetzt jemand 52.5 Sekunden vor Schluss nen Penalty kommt darfst du diese halbe Sekunde nicht untern Tisch fallen lassen.

Ups, dass hatte ich so detailliert nicht auf dem Zettel. Vielleicht macht es hier ja auch Sinn in der Uhrenklasse die Zehntel optional zu halten. Ich müsste dann aber sozusagen aus den 1000ms im Timer eine 100 machen. Sollte ich die 1000 bis zum Erreichen der Minute lassen und dann wenn ich Minute = 0 und Sekunde > 0 ist, den Timer.Interval auf 100 stellen oder grundsätzlich immer?

Zitat:

Zitat von alcaeus (Beitrag 1030052)
Ich empfehle dir hierfuer uebrigens ein Observer-Pattern. Kurz eine Erklaerung:
Du hast eine Klasse GameClock. Diese Methode kapselt einen Timer und hat eine Start/Stop-Methode. Start startet die Uhr, Stop haelt sie an. Beim Starten der Uhr schickst du dann eine Message an alle registrierten PenaltyClocks, dass diese auch starten. Beim Stop funktioniert das analog.

Das hier verstehe ich nicht ganz. Der Timer würde dann im private der Uhrenklasse gekapselt werden. So weit ist alles klar. Start-Stop ist auch klar. Was soll aber passieren, wenn ich die Message an die PenaltyClocks (die es ja aktuell noch nicht gibt) sende? Ich dachte, dass der gekapselte Timer alle Uhren "steuert", also die Hauptuhr und die Strafzeituhren zum laufen bringt, indem ER selbst die einzelnen Uhren "zählt". Ist es also so zu verstehen, dass der gekapselte Timer nur die anderen Timer anschieben/anhalten soll???

Zitat:

Zitat von alcaeus (Beitrag 1030052)
Bei dieser Gelegenheit noch nen Hinweis: beachte dass du nie mehr als 2 Strafzeiten laufen lassen darfst. Ein kleines Beispiel: Mannschaft A kassiert 2 Minuten. PP beginnt, Mannschaft A kassiert nochmal 2 Minuten. Jetzt laufen beide Strafzeiten und A spielt in doppelter Unterzahl. Wenn jetzt nochmal eine Strafe fuer A ausgesprochen wird, landen die 2 Minuten auf der Uhr, werden aber nicht runtergezaehlt bis nicht eine der vorherigen Strafzeiten abgelaufen sind.

Jo, davon hatte ich was gehört. Mir ist noch nicht ganz klar, wie das bei den 5-10 und 20-Minuten-Strafen ist, wo ja der Ausschluss des Spielers noch hinzukommt. Bei manchen Strafen ist es wohl so, dass DER oder EIN Spieler raus muss, aber natürlich nicht die vollen 10 Minuten absitzt. Dann gibt es da noch die Regel, dass die 2 Minuten-Strafzeit sofort gelöscht wird, wenn das in Unterzahl befindliche Team ein Tor "bekommt", respektive, dass bei einer 2+2-Strafe die ersten 2 Minuten gelöscht werden und direkt die 2. Strafzeit losläuft. Ziemlich irre! :)

Zitat:

Zitat von alcaeus (Beitrag 1030052)
Im Beispiel oben bedeutet das: dein Observer-Pattern darf nur die ersten beiden PenaltyClocks einer Mannschaft starten. Laeuft eine PenaltyClock aus, muss sie die erste nicht laufende PenaltyClock der eigenen Mannschaft starten.

Jep! Eigentlich ist es ja dann auch so, dass die bis dahin aktuell 2. Uhr an 1. Stelle rutschen muss und die neu zu startende Uhr an 2. Stelle => Wenn die Strafzeit grösser ist als die Restzeit der ersten. Das aber nur am Rande, weil ich die Uhren ja auch irgendwann mal rausschicken muss und der Empfänger natürlich grosse Lust drauf hat die Uhr korrekt sortiert zu erhalten.

Zitat:

Zitat von alcaeus (Beitrag 1030052)
So, ich hoffe das macht noch halbwegs Sinn was ich da geschrieben habe ;)

Jo, im Grossen und Ganzen scheinst Du nicht nur Ahnung vom Programmieren zu haben, sondern auch einiges über die Regeln im Eishockey zu wissen. Cool!

Die Uhrenklasse habe ich jetzt erstmal so aufgesetzt. Natürlich fehlen da noch die Funktionen "nach aussen hin".
Delphi-Quellcode:
unit unt_game_clock;

interface

uses ExtCtrls;

type
  TGameClock = class
  private
    GameClock : TTimer;
  public
    constructor Create;
    Procedure StartClock;
    Procedure StopClock;
  end;

implementation

constructor TGameClock.Create;
begin
  inherited;
end;

Procedure TGameClock.StartClock;
begin
  GameClock.Enabled := True;
end;

Procedure TGameClock.StopClock;
begin
  GameClock.Enabled := False;
end;

end.

alcaeus 20. Jun 2010 10:04

AW: Strafzeitenverwaltung in eigener Unit
 
Hallo,

Zitat:

Zitat von torud (Beitrag 1030061)
Ups, dass hatte ich so detailliert nicht auf dem Zettel. Vielleicht macht es hier ja auch Sinn in der Uhrenklasse die Zehntel optional zu halten. Ich müsste dann aber sozusagen aus den 1000ms im Timer eine 100 machen. Sollte ich die 1000 bis zum Erreichen der Minute lassen und dann wenn ich Minute = 0 und Sekunde > 0 ist, den Timer.Interval auf 100 stellen oder grundsätzlich immer?

Ich wuerde dir empfehlen, die Zeit immer in Hunderstelsekunden zu messen (Interval = 10ms), damit es wirklich passt.

Zitat:

Zitat von torud (Beitrag 1030061)
Das hier verstehe ich nicht ganz. Der Timer würde dann im private der Uhrenklasse gekapselt werden. So weit ist alles klar. Start-Stop ist auch klar. Was soll aber passieren, wenn ich die Message an die PenaltyClocks (die es ja aktuell noch nicht gibt) sende? Ich dachte, dass der gekapselte Timer alle Uhren "steuert", also die Hauptuhr und die Strafzeituhren zum laufen bringt, indem ER selbst die einzelnen Uhren "zählt". Ist es also so zu verstehen, dass der gekapselte Timer nur die anderen Timer anschieben/anhalten soll???

Ich versuchs mal mit Pseusocode (Delphi ist ein paar Jahre her ^^):
Code:
class GameClock
{
   private timer;
   
   private homePenaltyClocks;
   private awayPenaltyClocks;
   
   public function create()
   {
      this->timer = new Timer;
   }
   
   public function addPenaltyClock(team, clock)
   {
      clock->team = team;
      clock->gameClock = this;
      
      if (team == 'home')
      {
         this->homePenaltyClocks->push(clock);
      }
      else
      {
         this->awayPenaltyClocks->push(clock);
      }
   }
   
   public function start()
   {
      this->timer->start();
      
      for (i = 0; i < this->homePenaltyClocks->count() && i < 2; i++)
      {
         this->homePenaltyClocks[i]->start();
      }
      for (i = 0; i < this->awayPenaltyClocks->count() && i < 2; i++)
      {
         this->awayPenaltyClocks[i]->start();
      }
   }
   
   public function stop()
   {
      this->timer->stop();
      
      for (i = 0; i < this->homePenaltyClocks->count() && i < 2; i++)
      {
         this->homePenaltyClocks[i]->stop();
      }
      for (i = 0; i < this->awayPenaltyClocks->count() && i < 2; i++)
      {
         this->awayPenaltyClocks[i]->stop();
      }
   }
   
   public function penaltyClockComplete(team)
   {
      // Erstes Element aus dem Array entfernen
      // Wenn dann immer noch 2 Strafzeiten da sind, die zweite starten.
   }
}
Ein paar kurze Erklaerungen: es gibt einen Timer fuer die Zeitmessung, sowie zwei Arrays von PenaltyClocks. Die Methode addPenaltyClock fuegt eine PenaltyClock der GameClock hinzu und uebergibt der PenaltyClock ein paar Informationen.
start() und stop() starten/stoppen die Zeitmessung sowie die der ersten beiden PenaltyClocks (soweit vorhanden).
penaltyClockComplete() sagt der GameClock, dass eine Strafzeit abgelaufen ist und eine eventuell weitere gestartet werden muss (das darfst du dann selbst implementieren - ist aber auch keine Kunst).

Code:
class PenaltyClock
{
   private timer;
   public gameClock;
   public team;
   
   public function create()
   {
      this->timer = new Timer();
   }
   
   public function start()
   {
      this->timer->start();
   }
   
   public function stop()
   {
      this->timer->stop();
   }
   
   public function onTimerComplete()
   {
      if (!this->gameClock || !this->team)
      {
         return;
      }
      
      this->gameClock->penaltyClockComplete(team);
   }
}
Die PenaltyClock enthaelt einen eigenen Timer, da sie unabhaengig zur GameClock laufen muss.
start() und stop() brauchen ja keine Informationen.
Im onTimerComplete()-Event wird dann (sofern team und gameClock gesetzt sind) der entsprechenden GameClock gesagt, dass eine Strafzeit fuer eine entsprechende Mannschaft abgelaufen ist.
Das sollte das Prinzip ein bisschen naeher bringen. Der Code ist nicht der schoenste, aber nachdem du eh Delphi-Code brauchst musst du ihn sowieso neu schreiben - so dass auch weniger Code doppelt vorkommt ;)

Zitat:

Zitat von torud (Beitrag 1030061)
Jo, davon hatte ich was gehört. Mir ist noch nicht ganz klar, wie das bei den 5-10 und 20-Minuten-Strafen ist, wo ja der Ausschluss des Spielers noch hinzukommt. Bei manchen Strafen ist es wohl so, dass DER oder EIN Spieler raus muss, aber natürlich nicht die vollen 10 Minuten absitzt. Dann gibt es da noch die Regel, dass die 2 Minuten-Strafzeit sofort gelöscht wird, wenn das in Unterzahl befindliche Team ein Tor "bekommt", respektive, dass bei einer 2+2-Strafe die ersten 2 Minuten gelöscht werden und direkt die 2. Strafzeit losläuft. Ziemlich irre! :)

Ok, Eishockey-Regelkunde: mal abgesehn von der "niemals mehr als 2 Strafzeiten-Regel" gibt es folgendes zu beachten:
  • 2+2 ist ein Sonderfall, ueber den du dir Gedanken machen musst. Das sind naemlich zwei Strafzeiten, die aber nicht parallel ablaufen duerfen (waere ja witzlos). Auf der anderen Seite wuerde ein Tor eine der beiden Strafzeiten negieren. Den Teil ueberlass ich dir. Eine Moeglichkeit waere, in der PenaltyClock auch abzuspeichern, was fuer eine Strafe es ist. Das brauchst du eh um bei einem Tor Minors und Majors unterscheiden zu koennen ;)
  • 2-Minuten-Strafen enden bei einem Tor der Ueberzahl-Mannschaft.
  • 5-Minuten-Strafen enden bei einem Tor der Ueberzahl-Mannschaft nicht.
  • Bei 2+10, 5+10, 2+2+10, 5+20 (2+20 gibts eigentlich nicht) wird die Disziplinarstrafe (10 bzw. 20 Minuten) nicht auf die Anzeigetafel gesetzt, sie laeuft aber ab.
  • Der Spieler, der die Strafe begangen hat, sitzt die Disziplinarstrafe ab, waehrend die eigentliche Strafzeit von einem anderen Spieler abgesessen wird (aehnlich wie bei der "zuviel Personal"-Regel oder wenn ein Goalie 2 Minuten kassiert ;)).
  • Ob die Disziplinarstrafe sofort lostickt oder erst nach Ablauf der ersten 2 Minuten kann dir ein Eishockey-Regelbuch sagen, ich habs grad nicht im Kopf.
  • Alternativ geh zu einem Eishockeyspiel in einer unteren Liga (<= 2. Bundesliga) und frag die Zeitnahme, ob sie dir bisserl was erzaehlen koennen waehrend das Spiel laeuft. Die Jungs sind meistens sehr kommunikativ ;)

Zitat:

Zitat von alcaeus (Beitrag 1030052)
Im Beispiel oben bedeutet das: dein Observer-Pattern darf nur die ersten beiden PenaltyClocks einer Mannschaft starten. Laeuft eine PenaltyClock aus, muss sie die erste nicht laufende PenaltyClock der eigenen Mannschaft starten.

Jep! Eigentlich ist es ja dann auch so, dass die bis dahin aktuell 2. Uhr an 1. Stelle rutschen muss und die neu zu startende Uhr an 2. Stelle => Wenn die Strafzeit grösser ist als die Restzeit der ersten. Das aber nur am Rande, weil ich die Uhren ja auch irgendwann mal rausschicken muss und der Empfänger natürlich grosse Lust drauf hat die Uhr korrekt sortiert zu erhalten.

Zitat:

Zitat von torud (Beitrag 1030061)
Jo, im Grossen und Ganzen scheinst Du nicht nur Ahnung vom Programmieren zu haben, sondern auch einiges über die Regeln im Eishockey zu wissen. Cool!

Danke ;)

Greetz
alcaeus

torud 20. Jun 2010 10:23

AW: Strafzeitenverwaltung in eigener Unit
 
Moin,

@alcaeus: Vielen Dank für Deine Mühe. Dein Code riecht sehr nach php. :-) Ich werde ihn mir im Laufe des Tages mal anschauen und versuchen ihn zu implementieren bzw. zu verstehen. Versuchen deshalb, weil ich natürlich nicht ganz faul war. Ich poste hier mal meine bisherige Uhrenklasse. Da ist nun schon fast alles drin, wenngleich in Deinem letzten Post auch noch mal Hinweise drin waren, die ich auch wieder nicht auf dem Zettel hatte (z.b. interne Trennung von 2+2).

Insofern läuft das mit der Zeit jetzt schon. Allerdings hat meine Version ein paar Pferdefüsse.
- Intervall im Timer bei 1000 -> mir ist nicht klar, wie ich das mit 10 und dem Hochzählen machen soll
- Alle Uhren laufen derzeit syncron. Somit kann es hier und da zu diversen kleinen Differenzen kommen
- Der Timer im Hauptform steuert die Hauptuhr und liest die Daten aus der PenaltyList aus, die über einen anderen Timer (GameClock) gesteuert werden

Gelöst ist schon
- das man variabel sagen kann, wieviele Strafzeiten max. gleichzeitig laufen dürfen
-- die anderen uhren "rutschen" dann nach
- eine Ausgabe ob gerade Powerplay ist und welches Team das hat

Und fairerweise hier noch mein Code.

Delphi-Quellcode:
unit unt_game_clock;

interface

uses Windows, Dialogs, SysUtils, ExtCtrls, unt_penalties, unt_penalty, myGlobals,
     ShellApi;

type
  TGameClock = class
  private
    GameClock : TTimer;          //this is the timer
    max_RunningPenalties : byte; //this is a number of max. running penalties per team
  public
    Direction : byte;            //this is the direction of the running clock
    IsPowerplay : Boolean;       //this is a flag for powerplay
    PP_OnTeam : byte;            //this is a flag for the team, which is under powerplay
    constructor Create;
    Procedure StartClock;
    Procedure StopClock;
    Procedure GameClockTimer(Sender: TObject);
  end;

implementation

uses Math;

constructor TGameClock.Create;
begin
  inherited;
  //create timer and init
  GameClock := TTimer.Create(nil);
  max_RunningPenalties := 2;
  isPowerplay := False;
end;

procedure TGameClock.GameClockTimer(Sender: TObject);
var
  i, ListOffset : integer;
  TimeHolder : TSystemTime;
  h,m,s,msec : Word;
  IncreaseOffset : Boolean;
  int_team_a, int_team_b : byte;
begin
  //init of variables
  int_team_a := 0;
  int_team_b := 0;
  ListOffset := 0;

  //walk over all penalties
  for i := 0 to PenaltyList.Count -1 do
    begin
      if not(PenaltyList.Items[i-ListOffset] <> nil) then exit;
      if PenaltyList.Items[i-ListOffset].Team = 'A' then inc(int_team_a);
      if PenaltyList.Items[i-ListOffset].Team = 'B' then inc(int_team_b);
      //here we check, if we have a powerplay-situation
      if ((int_team_a <= max_RunningPenalties) and (int_team_b <= max_RunningPenalties)) then
        begin
          //set isPowerplay true or false
          if int_team_a <> int_team_b then
            IsPowerplay := True
          else
            IsPowerplay := False;
          //set the team, which is on powerplay
          if int_team_a > int_team_b then
            PP_OnTeam := 1
          else
            PP_OnTeam := 2;
        end;
      //here we check, if a team has more then the allowed max number of penalties
      //if yes => we dont count the timing for this penalty
      if ((PenaltyList.Items[i-ListOffset].Team = 'A') and (int_team_a <= max_RunningPenalties)) or
        ((PenaltyList.Items[i-ListOffset].Team = 'B') and (int_team_b <= max_RunningPenalties)) then
          begin
            IncreaseOffset := False;
            DecodeTime(StrToTime(PenaltyList.Items[i-ListOffset].CTime),h,m,s,msec);
            TimeHolder.wHour  := h;
            TimeHolder.wMinute := m;
            TimeHolder.wSecond := s;
            TimeHolder.wMilliseconds := msec;
            case PenaltyList.Items[i-ListOffset].Direction of
              0 : begin // clock should run asc
                    TimeHolder.wsecond:= TimeHolder.wSecond + 1;

                    if TimeHolder.wSecond = 60 then begin
                      TimeHolder.wSecond :=0;
                      TimeHolder.wMinute :=TimeHolder.wMinute + 1;
                    end;
                  end;
              1 : begin // clock should run desc
                    //delete that penalty, cause time is over
                    if (TimeHolder.wSecond = 0) and (TimeHolder.wMinute = 0) then
                      begin
                        //delete it later, after sending out the 0:00
                        IncreaseOffset := True;
                      end
                    else
                      begin
                        if TimeHolder.wSecond = 0 then begin
                          TimeHolder.wSecond := 59;
                          TimeHolder.wMinute := TimeHolder.wMinute - 1;
                        end
                        else
                          TimeHolder.wsecond := TimeHolder.wSecond - 1;
                      end;
                  end;
            end;
            //adwise the new CurrentTime
            PenaltyList.Items[i-ListOffset].CTime := Format('%.2d:%.2d:%.2d', [TimeHolder.wHour,TimeHolder.wMinute,TimeHolder.wSecond]);
            //we have to delete an item
            if IncreaseOffset then
              begin
                PenaltyList.Delete(i-ListOffset);
                inc(ListOffset);
              end;
        end;
    end;
end;

Procedure TGameClock.StartClock;
begin
  GameClock.OnTimer := GameClockTimer;
  GameClock.Enabled := True;
end;

Procedure TGameClock.StopClock;
begin
  GameClock.Enabled := False;
end;

end.
So und jetzt schau ich mir Deins mal näher an.

schlecki 20. Jun 2010 11:56

AW: Strafzeitenverwaltung in eigener Unit
 
versuchs mal mit:

Delphi-Quellcode:
type
  TPenalties = class(TObjectList)
  private
    function GetItems(Idx: Integer): TPenalty;
    procedure SetItems(Idx: Integer; Value: TPenalty);
  public
    property Items[Idx: Integer]: TPenalty read GetItems write SetItems;
  end;

...

function TPenalties.GetItems(Idx: Integer): TPenalty;
begin
  Result := (inherited GetItems(Idx)) as TPenalty;
end;

procedure TPenalties.SetItems(Idx: Integer; Value: TPenalty);
begin
  inherited SetItems(Idx, Value);
end;
ungetestet, sollte aber so gehen...


Edit: hm, irgendwie hab ich die letzten Beiträge nicht gesehen... sorry...

alcaeus 20. Jun 2010 13:03

AW: Strafzeitenverwaltung in eigener Unit
 
Zitat:

Zitat von torud (Beitrag 1030235)
@alcaeus: Vielen Dank für Deine Mühe. Dein Code riecht sehr nach php. :-) Ich werde ihn mir im Laufe des Tages mal anschauen und versuchen ihn zu implementieren bzw. zu verstehen. Versuchen deshalb, weil ich natürlich nicht ganz faul war. Ich poste hier mal meine bisherige Uhrenklasse. Da ist nun schon fast alles drin, wenngleich in Deinem letzten Post auch noch mal Hinweise drin waren, die ich auch wieder nicht auf dem Zettel hatte (z.b. interne Trennung von 2+2).

Hmm...ich dachte ich haette das PHP gut genug versteckt, aber anscheinend nicht :mrgreen:
Ich hab aber darauf geachtet, es so zu schreiben dass es relativ leicht verwendbar ist. Voraussetzung ist aber, dass Delphi Objektreferenzen speichert und keine Kopien der Objekte. Wie das gehandhabt wird hab ich nicht mehr im Kopf.

Ich geh mal in Ruhe deinen Code durch - das dauert bei mir etwas laenger, da ich seit mehr als 4 Jahren (!) keine einzige Zeile Delphi geschrieben hab :oops:

Greetz
alcaeus

xZise 20. Jun 2010 14:09

AW: Strafzeitenverwaltung in eigener Unit
 
Zitat:

Zitat von alcaeus (Beitrag 1030309)
[…]Hmm...ich dachte ich haette das PHP gut genug versteckt, aber anscheinend nicht :mrgreen: […]

WTF das soll versteckt sein :mrgreen: wobei ich auch fast auf C++ getippt hätte (habe aber keine großen Erfahrungen mit C++).

Zitat:

Zitat von alcaeus (Beitrag 1030309)
[…]Voraussetzung ist aber, dass Delphi Objektreferenzen speichert und keine Kopien der Objekte. Wie das gehandhabt wird hab ich nicht mehr im Kopf.[…]

Passt ;) Das gibt ja immer schön verwirrung, warum auf einmal das alte Objekt mit geändert wird. Also solange nicht .Assign() oder .AssignTo() verwendet wird natürlich.

MfG
Fabian

alcaeus 20. Jun 2010 16:11

AW: Strafzeitenverwaltung in eigener Unit
 
Zitat:

Zitat von xZise (Beitrag 1030331)
WTF das soll versteckt sein :mrgreen: wobei ich auch fast auf C++ getippt hätte (habe aber keine großen Erfahrungen mit C++).

:duck:

Zitat:

Zitat von xZise (Beitrag 1030331)
Passt ;) Das gibt ja immer schön verwirrung, warum auf einmal das alte Objekt mit geändert wird. Also solange nicht .Assign() oder .AssignTo() verwendet wird natürlich.

Gut, dann hatte ich das richtig in Erinnerung. Danke :)

Greetz
alcaeus

David Martens 21. Jun 2010 13:31

AW: Strafzeitenverwaltung in eigener Unit
 
Entschuldigt wenn ich mich einmische, aber ich hätte da ein paar Ideen einzuwerfen.

@TE: in der TPenalty Klasse speichers du die Zeit als string

Zitat:

4. Ja. Das ist aktuell meinem internen Zeitverfahren geschuldet und der Frage, an welcher Stelle ich denn dann nun die Zeiten (aktuell Spielzeit und jede einzelne laufende Strafzeit) intern und später dann auch extern aktualisieren lassen soll. Aktuell läuft auf dem Hauptform einfach nur ein Timer, der die Sekunden und Minuten hoch- oder runterzählt.
, aber bei deinem Timer benutzt du original.wSecond / wMinute. Da hast du deine eigene Argumentation wiederlegt.

Aber jetzt zu meinem Vorschlag:



Delphi-Quellcode:
  TPenalty = class(TObject)
  public
    Team : boolean;   // Team (A oder B) (there will be no more than 2 teams a game)
    Start,           // start of penalty
    Ende : LongInt;  // end of penalty   (oder auch Dauer, wenn man will)

    constructor Create; overload;
    constructor Create(fTeam : boolean; fStart, fEnde : LongInt); overload;
  end;

  TPenalties = class(TObjectList)
  private
    function GetItem(Index: integer): TPenalty;
    procedure SetItem(Index: integer; Value: TPenalty);
  public
    property Items[Index: integer]: TPenalty read GetItem write SetItem; default;
  end;

  TGameClock = class
  private
    PenaltyList : TPenalties;
    max_RunningPenalties : byte;
    isPowerplay : boolean;
    GameClock : TTimer;
    Clock : LongInt;

    procedure Tick(Sender: TObject);
  public
    constructor Create;

    procedure StartGame;
    procedure StartClock;
    procedure StopClock;

    // will hold the logic of no more than 2 penalties a team
    procedure AddPenalty(fTeam : boolean; fDuration : LongInt);
  end;

implementation

{$R *.dfm}

function TPenalties.GetItem(Index: Integer): TPenalty;
begin
  Result := (inherited GetItem(Index)) as TPenalty;
end;

procedure TPenalties.SetItem(Index: Integer; Value: TPenalty);
begin
  inherited SetItem(Index, Value);
end;

constructor TGameClock.Create;
begin
  inherited;
  //create timer and init
  GameClock := TTimer.Create(nil);
  max_RunningPenalties := 2;
  isPowerplay := False;
end;

procedure TGameClock.StartClock;
begin
  GameClock.OnTimer := Tick;
  GameClock.Enabled := True;
end;

procedure TGameClock.StartGame;
begin
  Clock := 0;
  GameClock.Enabled := True;
end;

procedure TGameClock.StopClock;
begin
  GameClock.Enabled := False;
end;

procedure TGameClock.AddPenalty(fTeam : boolean; fDuration : LongInt);
var
  i : integer;
  FirstRunning, Last, New : TPenalty;
begin
  for i := 0 to PenaltyList.Count - 1 do
  begin
    if (PenaltyList.Items[i].Start < Clock) and
       (PenaltyList.Items[i].Ende > Clock) and
       (PenaltyList.Items[i].Team = fTeam) then
    begin
      if not Assigned(FirstRunning) then
      begin
        FirstRunning := PenaltyList.Items[i];
      end
      else
      begin
        Last := PenaltyList.Items[i];
      end;
    end;
  end;
  // FirstRunning is now the first running penalty and
  // Last is the last given penalty besides the first running

  // first set standard values
  New := TPenalty.Create(fTeam, Clock, Clock + fDuration);

  if Assigned(FirstRunning) then
  begin
    if Assigned(Last) then
    begin
      // if two or more add penalty time at end of last penalty
      New.Start := Last.Ende;
      New.Ende := Last.Ende + fDuration;
    end;
  end;

  PenaltyList.Add(New);
end;

procedure TGameClock.Tick(Sender: TObject);
var
  i, ListOffset : integer;
  int_team_a, int_team_b : byte;
  PP_OnTeam : byte;
begin
  //init of variables
  int_team_a := 0;
  int_team_b := 0;

  // next Tick of clock
  Clock := Clock + GameClock.Interval; // add intervall to our clock


  for i := 0 to PenaltyList.Count - 1 do
  begin
    if (PenaltyList.Items[i].Start <= Clock) and
       (PenaltyList.Items[i].Ende > Clock) then
    begin
      if PenaltyList.Items[i].Team then
        inc(int_team_a)
      else
        inc(int_team_b);
    end;
  end;

  //here we check, if we have a powerplay-situation
  if ((int_team_a <= max_RunningPenalties) and (int_team_b <= max_RunningPenalties)) then
  begin
    IsPowerplay := int_team_a <> int_team_b;

    //set the team, which is on powerplay
    if IsPowerplay then
    begin
      if int_team_a > int_team_b then
        PP_OnTeam := 1
      else
        PP_OnTeam := 2;
    end;
  end;

  //walk over all penalties
  for i := 0 to PenaltyList.Count - 1 do
  begin
    // only running ones
    if (PenaltyList.Items[i].Start <= Clock) and
       (PenaltyList.Items[i].Ende > Clock) then
    begin
      // show penalties
      // assign to whatever it should display (differentiation not done)

      // start of penalty
      TimeToStr(PenaltyList.Items[i].Start / 1000); // "/ 1000" because all times are stored in milliseconds

      // start of penalty
      TimeToStr(PenaltyList.Items[i].Ende / 1000);

      // if the clock is running the backwards then
      // TimeToStr(gamelength - PenaltyList.Items[i].Ende / 1000); // gamelength is the length of the game in milliseconds
    end;
  end;
  // at the end show current time

   TimeToStr(Clock / 1000);
end;

{ TPenalty }

constructor TPenalty.Create;
begin
  inherited;
end;

constructor TPenalty.Create(fTeam: boolean; fStart, fEnde: LongInt);
begin
  Create;

  Team := fTeam;
  Start := fStart;
  Ende := fEnde;
end;
Was haltet ihr davon?
Ich gehe die Sache andersherum an. Die Penalty Klassen sind nur für die "Datenablage" und die Timerklasse koordiniert alles. Damit habe ich dann auch gleich eine Historie aller Strafen und kann später eine Auswertung implementieren wenn ich will.

Gruß David

Namenloser 21. Jun 2010 14:07

AW: Strafzeitenverwaltung in eigener Unit
 
Ich find es generell nicht besonders sinnvoll, Boolean für Daten zu missbrauchen, die nicht "wahr" oder "falsch" sind. Das verwirrt nur. Wenn du einen Datentyp mit 2 Werten haben willst, nimm dafür ein Enum:
Delphi-Quellcode:
  TTeam = (tmTeamA, tmTeamB);

  TPenalty = class(TObject)
  public
    Team : TTeam;
    ...
[edit]
Und ich würde etwas mehr auf die Namenskonventionen achten: Felder sollte man mit dem Präfix F (für Field) beginnen. Also
Delphi-Quellcode:
  TPenalty = class(TObject)
  public
    FTeam : TTeam;
    FStart,
    FEnde : LongInt;
statt
Delphi-Quellcode:
  TPenalty = class(TObject)
  public
    Team : TTeam;
    Start,
    Ende : LongInt;
Parameter von Funktionen erhalten hingegen kein Präfix. Wenn es Mehrdeutigkeiten oder Namenskonflikte gibt, wird ihnen manchmal ein A vorangestellt. F als Präfix für Parameter ist jedoch irreführend, da F wie gesagt für Field steht.

Und ich würde noch darauf achten, durchgehend englische Bezeichner zu verwenden, aber das ist Geschmackssache.

Ansonsten ist dein Vorschlag, die Objekte als reine Datenobjekte zu handhaben, imo gut. Man sollte die Datenspeicherung und die Logik immer versuchen zu trennen. Hier hat es außerdem den Vorteil, dass man mit nur einem Timer auskommt.
[/edit]


Alle Zeitangaben in WEZ +1. Es ist jetzt 20:44 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz