Hi,
ich hab mal die Klassen für die Spieler, Spielerliste, Spiele und Spielliste fertig gestellt. Leider hab ich das System für den Eintrag eines Spielers in ein neues Spiel noch nicht ganz durchschaut. Für die Gewinner ist das ja recht einfach. Bei den Verlierern hab ich da so meine Probleme. Ich pack hier mal die Procedure rein.
Delphi-Quellcode:
procedure TPlayList.ChangePlay(APlayClass: TPlayClass; AProperty : String);
var AWinner, ALooser : TPlayerClass;
procedure PlayerinGame(APlayer : TPlayerClass; AOldPlay : TPlayClass; winning : Boolean);
var NewPlay : TPlayClass;
begin
if winning then begin
// Spieler ist Gewinner des alten Spieles
case ORD(AOldPlay.FGame) of
ORD('R') : begin
// Gewinner der ersten Runde
if Odd(AOldPlay.Number) then begin
NewPlay := GetPlay('G', 1, (AOldPlay.Number+1) div 2);
if Assigned(NewPlay) then
NewPlay.FPlayer1 := APlayer;
end else begin
NewPlay := GetPlay('G', 1, (AOldPlay.Number) div 2);
if Assigned(NewPlay) then
NewPlay.FPlayer2 := APlayer;
end;
end;
ORD('G') : begin
if Odd(AOldPlay.Number) then begin
NewPlay := GetPlay('G', AOldPlay.FRound+1, (AOldPlay.FNumber+1) div 2);
if Assigned(NewPlay) then begin
NewPlay.FPlayer1 := APlayer;
end else begin
// das war das letzte Gewinnerspiel, ab ins Filale
NewPlay := GetPlay('F', 0, 0);
if Assigned(NewPlay) then
NewPlay.Player1 := APlayer;
end;
end else begin
NewPlay := GetPlay('G', AOldPlay.FRound+1, (AOldPlay.FNumber) div 2);
if Assigned(NewPlay) then begin
NewPlay.FPlayer2 := APlayer;
end else begin
// das war das letzte Gewinnerspiel, ab ins Filale
NewPlay := GetPlay('F', 0, 0);
if Assigned(NewPlay) then
NewPlay.Player1 := APlayer;
end;
end;
end;
ORD('V') : begin
NewPlay := GetPlay('V', AOldPlay.Round + 1, 1);
if Assigned(NewPlay) then begin
NewPlay.FPlayer1 := APlayer;
end else begin
// das war das letzte Gewinnerspiel, ab ins Filale
NewPlay := GetPlay('F', 0, 0);
if Assigned(NewPlay) then
NewPlay.Player2 := APlayer;
end;
end;
end;
end else begin
// Spieler ist Verlierer des alten Spieles
case ORD(AOldPlay.FGame) of
ORD('R') : begin
// Gewinner der ersten Runde
if Odd(AOldPlay.Number) then begin
NewPlay := GetPlay('V', 1, (AOldPlay.Number+1) div 2);
if Assigned(NewPlay) then
NewPlay.FPlayer1 := APlayer;
end else begin
NewPlay := GetPlay('V', 1, (AOldPlay.Number) div 2);
if Assigned(NewPlay) then
NewPlay.FPlayer2 := APlayer;
end;
end;
ORD('G') : begin
// jo, da hab ich noch kein System entdeckt ???????????
end;
ORD('V') : begin
// das wars dann, kein weiteres Spiel :-(
// oder doch? :-) hab ich das System aber auch noch nicht durchschaut
end;
end;
end;
end;
begin
// ein Spieler ist ein Freilos?
if ((AProperty = 'Player1') or (AProperty = 'Player2')) and
(Assigned(APlayClass.Player1) and Assigned(APlayClass.Player2)) and
((APlayClass.Player1.FPlayerType = pt_Looser) or (APlayClass.Player2.FPlayerType = pt_Looser)) then begin
if APlayClass.Player1.FPlayerType = pt_Looser then begin
// Player2 hat gewonnen
AWinner := APlayClass.FPlayer2;
ALooser := APlayClass.FPlayer1;
end else begin
// Player1 hat gewonnen
AWinner := APlayClass.Player1;
ALooser := APlayClass.Player2;
end;
// neues Spiel für Gewinner ermitteln
PlayerinGame(AWinner, APlayClass, True);
// neues Spiel für Verlierer ermitteln
PlayerinGame(ALooser, APlayClass, False);
// Counter der gespielten Spiele der Spieler erhöhen
AWinner.PlayCount := AWinner.PlayCount + 1;
ALooser.PlayCount := ALooser.PlayCount + 1;
// aktuelle Platzierung der Spieler setzen
AWinner.Position := FPlayerList.Count - AWinner.PlayCount;
ALooser.Position := FPlayerList.Count - ALooser.PlayCount - 1;
// Spielstatus auf beendet
APlayClass.Status := ps_finish;
Exit;
end;
// der Spielstand hat sich geändert
if AProperty = 'PlayResult' then begin
if (APlayClass.FPlayResult.Player1 <> 0) or (APlayClass.FPlayResult.Player2 <> 0) then begin
// es gibt einen Spielstand <> 0
if APlayClass.FPlayResult.Player1 > APlayClass.PlayResult.Player2 then begin
// Player1 hat gewonnen
AWinner := APlayClass.Player1;
ALooser := APlayClass.Player2;
end else begin
// Player2 hat gewonnen
AWinner := APlayClass.Player2;
ALooser := APlayClass.Player1;
end;
// neues Spiel für Gewinner ermitteln
PlayerinGame(AWinner, APlayClass, True);
// neues Spiel für Verlierer ermitteln
PlayerinGame(ALooser, APlayClass, False);
// Counter der gespielten Spiele der Spieler erhöhen
AWinner.PlayCount := AWinner.PlayCount + 1;
ALooser.PlayCount := ALooser.PlayCount + 1;
// aktuelle Platzierung der Spieler setzen
AWinner.Position := FPlayerList.Count - AWinner.PlayCount;
ALooser.Position := FPlayerList.Count - ALooser.PlayCount - 1;
// Spielstatus auf beendet
APlayClass.Status := ps_finish;
end;
end;
end;
Hier noch einige Bemerkungen zum Ablauf. Wird in einem Spiel ein Spielstand (oder eine andere Eigenschaft) geändert so ruft das Spiel die Procedure ChangePlay seiner PlayList auf und übergibt sich selbst sowie den Namen der Eigenschaft an die Procedure.
Die Procedure der PlayList macht jetzt folgendes. Erstens wird geschaut, ob der geänderte Parameter des Spiels der Spielstand oder der Typ des Spielers ist (Freilos bei Spieler). Ist ein gültiger Spielstand eingetragen, so wird der Gewinner und Verlierer des Spiels ermittelt. Dann werden diese an die Procedure PlayerinGame übergeben. Diese erhält folgender Werte:
APlayer = Spieler der in ein neues Spiel eingetragen werden soll
AOldPlay = Spiel das gerade zu Ende gespielt wurde
winning = gibt an, ob der Spieler der Gewinner oder Verlierer des Spieles ist.
Nun prüft die Procedure erst mal, welches Spiel das gerade gespielte Spiel ist, um das neue Spiel zu ermitteln, in das der aktuelle Spieler jetzt eingetragen werden soll.
Der erste Block der Abfrage für den Gewinner sollte eigentlich soweit ok sein. Keinen Plan hab ich noch für den zweiten Block, Eintrag des Verlierers. Das vorallem wenn er ein V- oder G-Spiel verloren hat.
Da die Procedure eine eigene Methode der PlayList ist, wird hier auf eigene Hilfsfunktionen zugegriffen. Das ist z.B. die Funktion GetPlay. GetPlay sucht in der Liste nach einem Spiel mit der angegebenen Bezeichnung und gibt die Instanz dieses Spieles als Ergebnis zurück. Wurde kein Spiel mit dieser Bezeichnung gefunden, so liefert die Funktion nil.
Das ergibt natürlich, dass in der Liste alle Spiele schon eingetragen sind. Erledigt wird das bei der Übergabe der Spielerliste an die PlayList. Dabei wird auf Basis der Anzahl der in der PlayerList eingetragenen Spieler der gesamte Spielplan automatisch erstellt und alle Spiele eingetragen. Das ist auch schon fertig und hat so keine großen Probleme bereitet. Hier mal diese Funktion zur Kontrolle:
Delphi-Quellcode:
procedure TPlayList.UpdatePlayCount;
var APlayerCount : Integer;
Counter, CRound : Integer;
procedure AddPlays(AGame : Char; ARound, ANumberCount : Integer);
var BCounter : Integer;
begin
for BCounter := 1 to ANumberCount div 2 - 1 do begin
if not Assigned(GetPlay(AGame, ARound, BCounter)) then begin
// Spiel ist noch nicht angelegt
Add(TPlayClass.Create(AGame, ARound, BCounter));
end;
end;
end;
begin
if not Assigned(FPlayerList) or (FPlayerList.Count = 0) then begin
Clear;
end else begin
Clear;
APlayerCount := FPlayerList.Count;
// bei ungerade Anzahl von Spielern einen dazu
if odd(APlayerCount) then
inc(APlayerCount);
// R-Spiele anlegen
AddPlays('R', 1, APlayerCount div 2);
// G-Spiele anlegen
Counter := APlayerCount div 4;
CRound := 1;
while (Frac(Counter/2) = 0) do begin
AddPlays('G', CRound, Counter);
inc(CRound);
Counter := Counter div 2;
end;
// V-Spiele anlegen
Counter := APlayerCount div 4;
CRound := 1;
while (Frac(Counter/2) = 0) do begin
AddPlays('V', CRound, Counter);
inc(CRound);
if not odd(CRound) then
Counter := Counter div 2;
end;
// Finale anlegen
Add(TPlayClass.Create('F', 0, 0));
end;
end;
Du brauchst die Methoden hier nicht rauskopieren. Ich hab die
Unit mit den Klassen schon fertig und hänge sie hier bei einem der nächsten Beiträge mit ran, dann kannst du sie dir direkt downloaden.
Ja, somit müssen wir nur noch die kleinen Probleme mit der Spielzuordnung für die Verlierer lösen und das Datenmodell ist fertig.
Dann können wir uns um den visuellen Teil kümmern.
Dann bis die Tage,
Gruß oki