AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Netzwerke Delphi Pokerprojekt realisierung
Thema durchsuchen
Ansicht
Themen-Optionen

Pokerprojekt realisierung

Ein Thema von .chicken · begonnen am 28. Mär 2007 · letzter Beitrag vom 15. Mai 2007
Antwort Antwort
Seite 4 von 7   « Erste     234 56     Letzte »    
.chicken

Registriert seit: 5. Dez 2006
459 Beiträge
 
#31

Re: Pokerprojekt realisierung

  Alt 4. Apr 2007, 13:40
Ok, aber er gibt immernoch ein Problem aus!

Und zwar:
"Project LAN_Poker raised exception class EStackOverflow with message 'Stack overflow'"

Ich werd daraus net schlau sorry (hoffe es ist nicht wieder son dummer Fehler)!
  Mit Zitat antworten Zitat
Der_Unwissende

Registriert seit: 13. Dez 2003
Ort: Berlin
1.756 Beiträge
 
#32

Re: Pokerprojekt realisierung

  Alt 4. Apr 2007, 13:52
Zitat von .chicken:
Und zwar:
"Project LAN_Poker raised exception class EStackOverflow with message 'Stack overflow'"
Das tritt auf, wenn Du eine Rekursion hast, die nicht abbricht. Der Stack ist ein Stapel, auf dem Du Dinge ablegst. Du legst einfach was oben rauf und merkst Dir die Reihenfolge. Beim Runternehmen gehst Du (wie bei jedem Stapel) andersherum vor, das was oben liegt kommt zuerst runter. Der wird für verschiedene Dinge benutzt, z.B. werden hier Dinge abgelegt, wenn eine Methode sich selbst aufruft. Beispiel wäre die Fakultät, n! ist ja gerade n * (n-1)!. Nimmst Du nur diese Formel, dann merkt sich Delphi n (auf dem Stack) und berechnet (n-1)!, für (n-1)! wird (n-1) gemerkt und ((n-1)-1)! berechnet. Das Problem auch hier, es gibt noch keinen Rekursionsanker (wann ist man fertig). Natürlich gibt es den bei der Fakultät, hier gilt dass 0! = 0 ist und/oder 1! = 1. Irgendwann wurde also ganz viel von n abgezogen, so dass Du die Fakultät von 1 berechnen kannst und die kennst Du. Dann springt der zurück und findet dort 2* (1!), 1! kennst Du nun und kannst das ausrechnen, springst zurück und hast 3 * (2!),... Das zurückspringen nimmt einfach die Daten wieder vom Stack runter.
Der Stack ist dabei ein Speicher mit einer max. Größe. Legst Du also nur lang genug was darauf ab, gibt es einen Stackoverflow. Die Grenze ist dabei sehr hoch gesetzt, kommt es zu einem Stackoverflow, liegt das i.d.R. wirklich am Programm!

Schau einfach mal, wo sich eine Prozedur selbst aufruft (oder Du sonst einen Kreis hast). Als Hilfe kannst Du einfach einen Breakpoint (diese roten Punkte/ F5) setzen. Dort hält Delphi dann an, wenn Du das Programm ausführst. Hier kannst Du nun mit F7 in die Ausführung reinspringen und siehst, was Dein Code gerade macht. Bei größeren Schleifen kann das nerven, hier kannst Du auch einfach auf die Zeile hinter die Schleife einen neuen Breakpoint setzen und mit F9 die Ausführung fortsetzen. Die geht normal weiter, bis das Programm endet, ein Fehler auftritt oder ein Breakpoint den Ablauf erneut unterbricht.
  Mit Zitat antworten Zitat
.chicken

Registriert seit: 5. Dez 2006
459 Beiträge
 
#33

Re: Pokerprojekt realisierung

  Alt 4. Apr 2007, 14:10
Yeeehaw soweit klappts
Super, vielen Dank und die Sache mit dem Breakpoint ist auch nicht schlecht zu wissen

(Der Fehler war übrigens, dass ich den Konstruktor des Servers falsch deklariert hatte (ohne "AOwner: TComponent"))
  Mit Zitat antworten Zitat
.chicken

Registriert seit: 5. Dez 2006
459 Beiträge
 
#34

Re: Pokerprojekt realisierung

  Alt 5. Apr 2007, 16:08
Ok, also bisher geht alles ganz gut, bin grad bei dem Senden und Auswerten von Nachrichten!

Klappt soweit auch, nur weiss ich nicht, wie ich den Array der Spieler versenden soll.
Alle anderen Werte sind ja nur Integer bzw Strings und auhc nur einzelne Werte!+
Das ist ja ein Array eines bestimmten Typs!

Delphi-Quellcode:
type
  TKarte = class
    FBild, FFarbe: Integer;
    FVerdeckt: Boolean;
  Private
  Public
    property Bild: Integer read FBild write FBild; //Bild der Karte
    property Farbe: Integer read FFarbe write FFarbe; //Farbe der Karte
    property Verdeckt: Boolean read FVerdeckt write FVerdeckt; //Status der Karte
  end;

  TSpieler = class
    FHand: Array [1..2] of TKarte;
    FFolded: Boolean;
    FGeld, FBet: Integer;
    procedure SetHand(Index: Integer; Value: TKarte);
    function GetHand(Index: Integer): TKarte;
  Private
  Public
    property Hand[Index: Integer]: TKarte read GetHand write SetHand;
    property Folded: Boolean read FFolded write FFolded;
    property Geld: Integer read FGeld write FGeld;
    property Bet: Integer read FBet write FBet;
  end;

var
  Spieler: Array off TSpieler;
Also so sehen die Typen aus und ich muss jetzt vom ServerSocket irgendwie die Spieler auf dem ClientSocket aktualisiern lassen. Wie mache ich das am besten? Weil mit SendText wärn das ja dann doch ziemlich viele Nachrichten!

PS: Ich hab die Units nochmal angehängt!

Edit: Sollt ich mich vielleicht doch in die IndyKomponenten einarbeiten? Ist das damit einfacher zu realisieren?
Angehängte Dateien
Dateityp: rar texas_hold_em_480.rar (3,7 KB, 6x aufgerufen)
  Mit Zitat antworten Zitat
.chicken

Registriert seit: 5. Dez 2006
459 Beiträge
 
#35

Re: Pokerprojekt realisierung

  Alt 5. Apr 2007, 23:55
Und ich hab noch eine Frage:
Wie kann ich alle aktiven Server im Netzwerk anzeigen lassen?
Sodass die Clients dann auch darauf connecten koennen!
  Mit Zitat antworten Zitat
Der_Unwissende

Registriert seit: 13. Dez 2003
Ort: Berlin
1.756 Beiträge
 
#36

Re: Pokerprojekt realisierung

  Alt 6. Apr 2007, 10:41
Zitat von .chicken:
Klappt soweit auch, nur weiss ich nicht, wie ich den Array der Spieler versenden soll.
Alle anderen Werte sind ja nur Integer bzw Strings und auhc nur einzelne Werte!+
Das ist ja ein Array eines bestimmten Typs!
Du musst ein wenig von der Speicherstruktur abstrahieren. Wie bereits erwähnt kann man nicht einfach eine ganze Klasse verschicken, sondern muss diese serialisieren (genauer kann man überhaupt nur serialisierbare Klassen verschicken). Die Frage ist ob Du wirklich all das brauchst. Die Informationen, die Du hast sind sehr viel einfacher, Du musst nur das verschicken, was von einem Spieler wirklich allen bekannt sein muss. Das wären (denke ich) nur der Name, der aktuelle Chip-Stand und ggf. noch die Position am Tisch.
Tritt ein neuer Spieler dem Spiel bei, so muss allen "alten" Spielern nur ein Datum (der neue Spieler) mitgeteilt werden. Umgekehrt muss dieser neue Spieler natürlich auch die Daten von allen "alten" Spielern bekommen. Das ganze machst Du einfach, in dem Du nacheinander die einzelnen Spieler an ihn schickst. Natürlich kannst Du auch direkt ein komplettes Array verschicken (minimiert den Overhead), aber das ist für Dein Spiel nicht zwingend nötig (werden ja kaum 1000e Spieler auf einem Server sein und kann man auch nachträglich ändern).

Zitat von .chicken:
Also so sehen die Typen aus und ich muss jetzt vom ServerSocket irgendwie die Spieler auf dem ClientSocket aktualisiern lassen. Wie mache ich das am besten? Weil mit SendText wärn das ja dann doch ziemlich viele Nachrichten!
Ziemlich viele Nachrichten ist sehr relativ. Textnachrichten haben einen sehr einfachen Vorteil, Du hast etwas das sehr unabhängig von Sender und Empfänger ist. Damit hast Du zwar die doppelte Umwandlung, für heutige Systeme sollte die aber (bei der zu erwartenden Menge von Nachrichten) kaum ins Gewicht fallen.
Die Frage ist, ob Du wirklich so viele Nachrichten verschicken musst, wie Du fürchtest. Letztlich solltest Du immer nur die Information verschicken, die gerade benötigt wird. Dazu solltest Du Dir einfach mal anschauen, was alles passieren kann:
  • Spiel wird eröffnet, noch gar nichts passiert (der Server kennt schon alle Daten)
  • Spieler tritt Spiel bei
  • Spiel wird begonnen
  • Spieler ist dran
  • Spieler setzt
  • Hand wird gegeben
  • Flop wird gegeben (auch einzelne weitere Karten)
  • Spiel endet

Ganz grob wären das die ersten Dinge, die mir einfallen. Das sind schon nicht so viele Nachrichten (imho). Jetzt wäre die Frage, welche Information zu welchem Ereignis gehört.
Bei der Eröffnung ist nichts zu tun, da findet alles lokal statt und der Server kennt die Daten natürlich schon.
Tritt nun ein Spieler dem Spiel bei, so interessieren nur die genannten Informationen, wo sitzt der Spieler, wieviel Geld hat er und wie heißt er. Im Gegenzug bekommt dieser Spieler die gleichen Daten aller anderen Spieler.
Wird eine Runde begonnen, so erhält ein Spieler den Dealer-Button (es wird also die Reihenfolge festgelegt). Zudem müssen zwei Spieler den Big bzw. Small-Blind setzen. Das ist dann eine Aufforderung (Nachricht) an je einen Spieler. Im Gegenzug muss das setzen bestätigt werden.
Dann werden die Hände gegeben und ein Spieler bekommt die Nachricht, dass er dran ist. Nun hat er die Auswahl, was genau er machen möchte (Setzen, Callen, Passen, ...). Was auch immer gemacht wird ist nur eine Nachricht von einem Spieler. Wurde die Aktion ausgeführt, so verliert der Spieler das Recht etwas zu machen und jmd. anderes bekommt die Nachricht, dass er dran ist.
Der Server merkt sich dabei, wann eine Runde zu enden ist. Dabei kann es sein, dass sich der Flop ändert. Hier muss allen Spieler die Information der neuen Karten (und ggf. Position) mitgeteilt werden, also max. 3 Nachrichten auf einmal.
Zu guter Letzt gibt es noch das Ende eines Spiels. Hier wird dann mitgeteilt, wer gewonnen hat, dieser Person wird sein Gewinn übermittelt und ggf. werden den Spielern die aufgedeckten Karten mitgeteilt.
(ist nicht ganz vollständig, aber halt so grob der Ansatz).

Der Letzte Punkt dürfe die meisten Nachrichten produzieren, hier kannst Du also gut abschätzen, wie groß die Menge der Nachrichten maximal wird. Dazu muss natürlich feststehen, in welcher Form Du Nachrichten überträgst. Wichtig ist, dass jede Nachricht eindeutig identifiziert werden kann (es macht einen Unteschied, ob man die Karten des Flops sieht oder die aufgedeckten des Gegners). Diese Identifikation kannst Du durch Konstanten festlegen. Da kämen Cardinal/Integer Werte (4 Byte) oder eindeutige Strings in Frage. Bei Strings hängt die Größe von der Länge des Strings ab. Sagen wir mal, deine Konstanten bestehen aus max. 50 Zeichen (sollten eigentlich deutlich weniger werden, oder?), dann wären das 50 Byte pro String.
Dann haben wir noch die eigentlichen Werte. Auch hier können wir die größte Nachricht abschätzen. Das dürften solche sein, bei denen ein Spieler (Spielername dominiert mit seiner Größe), Karten aufdeckt. Sagen wir auch, dass Du für Spielernamen nur eine Länge von 50 Zeichen zulässt, also wieder 50 Byte. Eine Karte besteht aus einer Farbe und einem Wert. Sehr großzügig schätze ich auch diese Information mit 50 Byte ab. Insgesamt würde also das größte Datum hier 200 Byte enthalten. Das ganze wird jetzt für jeden Spieler verschickt und auch noch an jeden Spieler. Schätzen wir mal die Spielerzahl mit 20 ab, dann hätten wir also max. 20*20*200 Byte, also < 80 KByte. Dabei habe ich hier schon sehr sehr großzügig abgeschätzt und das ist der gesamte Traffic für diese Nachricht, wenn Du sie für jeden Spieler abschickst (also noch 20 Spieler im Spiel waren) und jeder sie empfängt. Pro Spieler kommen nur 4000 Byte (< 4 KByte) an, die meisten Webseiten dürften deutlich größer sein.
An sich dürftest Du sogar sehr viel kleinere Werte erwarten, da kaum jmd. ernsthaft 50 Zeichen im Namen hat oder diese für die Identifikation einer Karte benötigt werden.
Natürlich kannst Du auch Karten, Beträge und die Identifikation der Nachricht in einem Cardinal/Integer Wert speichern, dann nehmen diese konstant nur noch 4 Byte ein. Das gleiche geht sogar mit den Spielern, dabei musst Du nur einmal die Assoziation zwischen Spielername und Nummer mitteilen und bei jedem Spieler speichern, dann kannst Du auch anhand der Nummer den Spieler ermitteln, an sich sollte das aber einfach nicht nötig sein.

Wie gesagt, ich denke so richtig viele Nachrichten sind es nicht und es ist der leichteste Weg. Natürlich kannst Du auch die Spieler serialisieren und die komplette Information verschicken. Dies bringt aber deutlich größere Strukturen mit sich und macht das Erweitern und die Fehlersuche imho etwas schwerer.

Zitat von .chicken:
Edit: Sollt ich mich vielleicht doch in die IndyKomponenten einarbeiten? Ist das damit einfacher zu realisieren?
Die Indys ändern da nicht viel. Bleib ruhig bei dem, wo Du gerade bist (oder gibt es etwas, was Dir hier fehlt?). Hast Du mit einer Komponente begonnen, solltest Du nicht wahllos nach Alternativen suchen. Das macht man i.d.R. vor dem Beginn eines Projekts Die machen aber in deinem Fall auch nichts leichter!

Zitat:
Wie kann ich alle aktiven Server im Netzwerk anzeigen lassen?
Sodass die Clients dann auch darauf connecten koennen!
Das kommt immer ganz auf das Netzwerk an. An sich gibt es immer zwei Möglichkeiten, einen zentralen und einen dezentralen Ansatz. Zentral bezieht sich dabei immer auf einen Server. Dieser hat eine Adresse (entweder statische IP oder halt ein DynDNS-Derivat, so dass der über den DNS-Eintrag immer gefunden wird). Jedes Spiel wird dann bei diesem Server angemeldet.
Hier ist es wichtig zu unterscheiden, der Server, an dem Du arbeitest, den nenne ich mal A. A ist für ein Spiel zuständig. Der zentrale Server heißt jetzt B. Nur B muss unter einem festen Namen erreichbar sein. Startest Du ein neues Spiel (erstellst also einen A), dann meldest Du Dein Spiel (Dein A) bei dem zentralen Server B an. Starte ich jetzt das Programm und möchte mich einem Spiel anschließen, so verbinde ich mich mit B (der ist ja bekannt). B zeigt mir dann alle Server (As) an, die momentan verfügbar sind. Da würde dann Dein A auftauchen. Verbinde ich mich mit dem, so kennt B halt die Adresse von A, gibt die mir und ich verbinde mich direkt mit Deinem A.
B vermittelt hier also nur und hostet nicht alle Spiele!

Die Alternative ist der dezentrale Ansatz. Dabei gibt es einfach keinen bekannten Server, was die Sache deutlich schwieriger macht! Für ein "privates" Netzwerk kannst Du einfach einen Broadcast machen. Dabei sendest Du einfach eine Anfrage an jeden Rechner im Netzwerk. Soweit die Infrastruktur das unterstützt, geht dies über eine spezielle Broadcast-Adresse, z.B. der X.X.X.255. Alternativ kann man hier auch von einem Multicast sprechen, aber ich denke die Funktionalität bleibt eher teueren Switches vorenthalten (hier geht die Anfrage an mehrere Rechner, aber nicht zwangsweise an alle).
Unterstützt der Switch keine Broadcasts, kannst Du natürlich einfach alle möglichen Adresesn durchgehen.
Für große Netze führt das schnell zu einer Menge (unerwünschten) Traffic. Für das sehr große Netz Internet funktioniert der Ansatz natürlich gar nicht (4,2 Mrd. Rechner abfragen wäre aber auch nicht all zu klug). Da hast Du dann keine einfache Möglichkeit. Natürlich gibt es P2P Clients, die dezentral arbeiten, diese nutzen aber ihre Verbreitung aus! Dort versucht man einfach zufällig auf ein paar (recht vielen) Adressen und einem bestimmten Port eine Anfrage. Findet man jmd. der dort antwortet (also auch das Programm verwendet), so tauscht man einfach die schon bekannten anderen Teilnehmer aus. Je mehr Leute also mitmachen, desto größer wird die Liste. Bei Deinem Programm dürfte das schwerer werden, dass Du zufällig jmd. findest, der das Programm auch verwendet, nun ja, eher unwahrscheinlich.
  Mit Zitat antworten Zitat
.chicken

Registriert seit: 5. Dez 2006
459 Beiträge
 
#37

Re: Pokerprojekt realisierung

  Alt 7. Apr 2007, 00:08
Ok, also erstmal ne Frage vorweg!
Hab im Inet was über ein Protokoll gelesen, dass die Kommunikation zwischen Server und Client regelt.
Damit ist doch nichts anderes gemeint, als das auswerten von Textnachrichten, die zwischen Server und Clients hin und hergeschickt werden oder?

Ok, dann zum Stand der Dinge
Hab nun die Kommunikation zwischen Server und Client ziemlich fertig (das nötigste zumindest, hinterher wird das sicher noch erweitert).
Jetzt habe ich aber ein neues Problem.

In meiner Unit "Controller" habe ich die procedures "Call", "Bet", etc.!
Die Unit "Server" hat den "Controller" in der uses Klausel!
Jetzt muss aber der Server die Clients aktualisieren, wenn zB ein Call ausgeführt wird.
Kann das dem Controller aber nicht sagen, weil der Server ja nicht in seinen uses steht!

Gibts da ne Möglichkeit? "Über-Kreuz-uses" sollen (laut dem Forum) ja nicht gut sein (und funktioniern eh nicht!?).
D.h. ich müsste Kommunikation zwischen Server und Controller umstrukturieren und den Server in die uses Klausel des Controllers schreiben, nicht umgekehrt? Oder geht das auch anders?

Danke soweit!

Edit: Ok, hab nun einfach den Controller ganz weggelassen und das ganze Zeugs direkt vom Server machen lassen! Klappt so super, ist natuerlich nurn bissl mehr Code im Server aber egal

Wenn das Projekt fertig ist wirds eh nochmal komplett überarbeitet, wenn mir dann ne Lösung einfällt änder ichs vielleicht nochmal
  Mit Zitat antworten Zitat
Der_Unwissende

Registriert seit: 13. Dez 2003
Ort: Berlin
1.756 Beiträge
 
#38

Re: Pokerprojekt realisierung

  Alt 7. Apr 2007, 15:22
Zitat von .chicken:
Hab im Inet was über ein Protokoll gelesen, dass die Kommunikation zwischen Server und Client regelt.
Damit ist doch nichts anderes gemeint, als das auswerten von Textnachrichten, die zwischen Server und Clients hin und hergeschickt werden oder?
Nun ja, wie soll ich das beantworten? Ich weiß doch nicht über welches Protokoll Du was gelesen hast. An sich geht es jedenfalls mit Sicherheit in die Richtung, stimmt so aber nicht 100%ig.
Um es einfach und kurz zu sagen, ein Protokoll legt nur fest, wie man kommuniziert. Es gibt zig Protokolle, die Du verwenden kannst, die Teilweise sogar auf einander aufbauen. Nimm einfach TCP/IP, dabei handelt es sich keineswegs um ein einziges Protokoll, vielmehr um TCP over IP. So steckst Du die Daten, die Du übertragen möchtest einfach in TCP-Pakete. Diese Pakete wiederum verpackst Du in IP-Pakete (dort stimmt der Begriff Paket nicht mehr ganz) und verschickst sie. IP stellt dabei nur sicher, dass irgendwelche Bytes an den Empfänger mit der angegebenen IP geht. Diese irgendwelchen Bytes werden auf der Empfängerseite dann weiter verwendet. Dort gibt es dann auch die IP Schicht, die diese Daten empfängt und an die darüberliegende Schicht weiterreicht. Für IP waren es nur irgendwelche Bytes, für die darüber liegende TCP Schicht ist es dann aber schon ein TCP-Paket. Das enthält ein paar Informationen (welches Paket um die Reihenfolge sicherzustellen, welche Checksumme um Übertragungsfehler zu erkennen...) und irgendwelche Nutzdaten (wieder nur Bytes). Für die darüber liegende Schicht gibt es z.B. auch wieder ein Protokoll, dass diese Nutzdaten bekommt und weiter verarbeitet.
Deine Anwendung steht dabei auf der obersten Schicht (schau Dir einfach mal das OSI Modell an). Willst Du also Daten verschicken, läufst Du von oben nach unten und packst für jede Schicht (außer der physikalischen Übertragungschicht) einfach weitere Daten außen rum (die für die jeweilige Schicht benötigt werden).
Auf jeder Schicht könntest Du dann von einem Server und einem Clienten sprechen (ziemlich allgemeine Begriffe). Natürlich kannst Du auch in Deiner Anwendung noch viele weitere Protokolle einbauen, die dann auf dem TCP/IP aufbauen. Auch auf jede dieser Schichten könnte dann zutreffen, dass die jeweils einen Client oder Server kennen.
Wichtig ist eigentlich nur, dass für jede Schicht immer Metainformationen (nur für die Schicht wichtig!) und Nutzdaten übertragen werden. Die Nutzdaten interpretiert die Schicht dabei nicht weiter, sondern reicht diese an die nächst höhere Schicht weiter. Ganz oben steht immer etwas, dass nur noch Nutzdaten bekommt und mit denen Arbeitet.
Bei einem Webserver hättest Du auch einen Interpreter, der eine HTML-Seite rendert. Die HTML-Seite wird dabei über das Hyper Text Transport Protocol (HTTP) übertragen. Dieses wird durch TCP-Pakete übertragen. Diese werden über IP übertragen....
Was für Nutzdaten in der obersten Schicht landen ist egal. Es sind einfach Bytes, die beliebig interpretiert werden können. Hast Du ein Datum von 4 Byte, kann das eine Zahl sein (z.B. ein Integer/Cardinal, ein Single, zwei Word, 4 Byte), es könnten Zeichen sein (4 Ascii Zeichen, 4 UTF-8 kodierte Zeichen, 2 UTF-16 kodierte Zeichen), aber auch alles andere, was in 4 Byte kodiert werden kann. Wie Du was überträgst kannst Du einfach in einem Protokoll festlegen (es sind also Nachrichten, aber nicht zwangsläufig Textnachrichten).

Zitat von .chicken:
In meiner Unit "Controller" habe ich die procedures "Call", "Bet", etc.!
Die Unit "Server" hat den "Controller" in der uses Klausel!
Jetzt muss aber der Server die Clients aktualisieren, wenn zB ein Call ausgeführt wird.
Kann das dem Controller aber nicht sagen, weil der Server ja nicht in seinen uses steht!
Was genau macht denn der Controller? "Call" und "Bet" ist etwas allgemein, es gibt verschiedene Dinge, die Du hier unterscheiden musst. Wurde die Aktion gerade ausgelöst (Clientseitig) oder wurde die Benachrichtigung empfangen, dass ein Spieler eine solche Aktion durchgeführt hat (Clientseitig)? Oder wurde dem Server gerade mitgeteilt, dass ein Spieler eine solche Aktion ausgeführt hat?
So muss der eigentliche Auslöser den Server benachrichtigen, was getan wurde.
Der Server wiederum muss alle Clients benachrichtigen.
Bekommen die Clients eine Benachrichtigung vom Server, müssen sie diese darstellen.

Das alles passiert, wenn ein Bet gemacht wurde, allerdings an drei völlig verschiedenen Stellen. Für alles könnte ein Controller in Frage kommen, der eine Methode "bet" hat (der Name "Bet" ist imho hier zu aussagelos).

Zitat von .chicken:
Gibts da ne Möglichkeit? "Über-Kreuz-uses" sollen (laut dem Forum) ja nicht gut sein (und funktioniern eh nicht!?).
Ist (nicht nur laut dem Forum) total schlecht in jeder Hinsicht und sollte immer vermieden werden (die meisten Sprachen verbieten es). In Delphi geht das durchaus, aber ich werde nicht sagen wie (ist sehr einfach, aber da Du es eh nicht verwenden sollst...).
Es gibt immer saubere Alternativen (es geht also immer auch anders)!

Der einfachste Weg ist es immer, dass Du die Units neu aufteilst. Häufig reicht es schon, dass man einen Teil in eine dritte Unit schiebt, auf die die beiden anderen zugreifen können. Diese dritte Unit sieht aber dafür die anderen zwei nicht.
In diesem Fall musst Du nur schauen, was alles passieren kann und wer dazu welche Informationen benötigt.

Betrachte ich die Methode Bet, so würde ich sagen, dass die immer dann aufgerufen wird, wenn jmd. etwas setzt. Da würde es mich dann aber stark wundern, dass der Server diese Methode / Unit kennen muss, denn der Server selbst wird nur benachrichtigt, wenn diese Methode von einem der Spieler aufgerufen wurde (wenn der selber setzt wäre das doch ungewöhlich).
Aber auch den umgekehrten Weg würde ich nicht ganz verstehen, setzt ein Spieler, so würde hier die Methode Bet aufgerufen werden. Diese Methode wird also Clientseitig aufgerufen. Ein Client muss die Server-Unit gar nicht kennen, sondern sendet über einen TCP-Client eine Nachricht an den Server. Hier muss also die Unit Controller nur eine Möglichkeit haben, die Nachricht zu verschicken (oder jmd. zu informieren, was gemacht wurde, so dass dieser jmd. die Nachricht verschickt).
Kommt die Nachricht beim Server an, so muss der alle Clienten darüber Informieren, was eine eigene Methode ist. Dabei muss der Server seine Liste der gemeldeten TCP-Clienten durchgehen und ihnen eine Nachricht zuschicken. Hier ist nur wichtig, dass über TCP (oder welche Protokoll auch immer) eine Nachricht versendet wird.
Empfängt jetzt ein Client eine Nachricht, so muss er eine Ereignisbehandlung durchführen. Auch hier sehe ich nicht, dass ein Zugriff auf den Controller nötig wäre. Wo also siehst Du das Kreuz?

Deutlicher gesagt würde ich folgenden Ablauf sehen/modellieren:
  1. Spieler setzt (Aufruf von "Bet")
  2. Benachrichtigung des Servers (Aufruf von "NotfiyServer")
  3. Empfangen der Nachricht durch den Server (Aufruf von "OnServerReceiveMessage")
  4. Benachritigen aller Clienten/Spieler (Aufruf von "NotifyClients")
  5. Empfang der Nachricht von einem Clienten (Aufruf von "OnClientReceiveMessage")
  6. Anzeigen der Änderungen (Aufruf von "Update...")

Die Namen sind jetzt nicht sonderlich gut gewählt, es soll nur anzeigen, dass hier nirgendwo ein Kreis entsteht, ein Überkreuzen ist also nicht nötig (soweit ich nicht irgendwas übersehe).

Zitat von .chicken:
Edit: Ok, hab nun einfach den Controller ganz weggelassen und das ganze Zeugs direkt vom Server machen lassen! Klappt so super, ist natuerlich nurn bissl mehr Code im Server aber egal
Absolut schlechter Ansatz (entschuldige!). Das mag hier nochmal klappen, aber je größer das Projekt, desto größer auch die Server-Unit. Wenn Du dort dann etwas finden möchtest.... Ich kann da wirklich nur aus meiner Erfahrung sprechen und muss Dir dringend von solchen Ansätzen abraten. Wie gesagt, es geht immer ohne. Wenn Du da im Moment keinen Weg siehst, können wir gerne drüber reden und ich kann Dir hoffentlich einen zeigen.
Gehst Du aber immer den Weg, den Du gerade gegangen bist, dann führt das einfach zu riesigen Units. Die sind sehr viel schlechter wartbar und fehleranfälliger. Möchtest Du eine bestimmte Funktionalität wiederverwenden, so wird Dir schnell die gesamte Unit zu groß sein und man neigt zu copy&paste, bei so großen Units kannst Du dabei schnell mal eine wichtige Abhängigkeit (von etwas anderem in der Unit) übersehen und Du kopierst etwas, dass zwar kompiliert aber totaler Mist ist! Deswegen lieber kleine Units, die eine kleine Aufgabe lösen.

Zitat von .chicken:
Wenn das Projekt fertig ist wirds eh nochmal komplett überarbeitet, wenn mir dann ne Lösung einfällt änder ichs vielleicht nochmal
Auch nichts wozu ich Dir raten kann. Mein Chef sagt das ständig zu mir, machen wir mal schnell einen Prototyp fertig, schön machen kann man immer noch. Hab früher sogar daran geglaubt! Ganz ehrlich, klappt nie! Dafür gibt es immer viel zu viel zu tun. Gilt nicht nur in einer Firma! Auch Dich wird das nächste Projekt (wenn Du eins findest) schnell mehr reizen (gut, im Job kann man es sich nicht so aussuchen). Alles was Du später schön machen/überarbeiten willst, fließt unfertig und/oder fehleranfällig in das Endprodukt, glaub mir (haben sowas schon verkauft ). Es fehlt immer an allem, was nötig ist um es gleich richtig zu machen, aber da muss man sich trotzdem zu zwingen. Egal wieviel länger es dauert es richtig zu machen, die Zeit holst Du immer wieder rein! Bist Du erstmal fertig ist die Motivation es neu/anders zu machen niedrig. Hast Du nicht von Anfang an sauber modelliert, wirst Du schnell merken was ich schon vorhin sagte, es gibt Abhängigkeiten die Du gar nicht siehst. Da tauscht Du dann an einer Stelle etwas aus, startest die Syntaxprüfung und bekommst sofort andere Stellen, die angepasst werden müssen. Passt Du die an, zieht das wieder Änderungen nach sich. Prüfen ob die erste Anpassung überhaupt korrekt war kannst Du nicht, da Du ja nicht compilieren kannst, solange nicht alles angepasst wurde. Dann irgendwann hast Du etliche Stellen geändert, merkst dass das so nicht geht und hast ein Problem... (klar, es gibt Backups, aber die Motivation sinkt rapide!).
Hast Du gleich sauber gearbeitet, stellt das spätere Anpassen (soweit es überhaupt nötig wird) kein Problem dar. Und glaub mir, dass ist kein erfundenes und übertriebenes Worst-Case-Szenario, sondern so ging es mir damals wirklich regelmässig.
Da findet man nicht mal ebend eine Stelle, die man leicht ändern kann! Häufig passiert sowas zudem aus Zeitdruck heraus. Gibt man dem Druck nach, bekommt man vielleicht noch irgendwas zusammen, das läuft, aber der Nachfolgeauftrag ist dann schon nicht mehr wünschenswert! Da sollen dann eben kleine Änderungen vorgenommen werden, irgendwas Neues rein und Du stehst vor irgendeinem Chaos, dass Du irgendwann mal überarbeiten wolltest und weißt nicht wo anfangen. Damit erhöht sich nur der Aufwand, für das, was Du in der gleichen Zeit packen musst...
Deshalb gilt wirklich, mache alles gleich richtig! Da gibt es diese bekannte Rechnung, dass eine Problem/Fehler während der Planung grob einen Dollar kostet (jeweils um behoben zu werden!), während der Implementierung der Funtion kostet der gleiche Fehler schon 10 Dollar, nach Fertigstellung/Zusammensetzen der Software kostet er 100 Dollar und wenn das Produkt ausgeliefert wurde > 1000 Dollar. Die Zahlen sind hier natürlich symbolisch zu verstehen, lieferst Du ein schlechtes Produkt aus, kann es Dich auch alles kosten (Imageschäden kann man nicht mit Geld beziffern).
Trotzdem stimmen die Relationen der Kosten schon ganz gut, man hat echt schnell eine Verzehnfachung des Aufwands (gefühlt noch viel mehr), wenn man etwas vor sich her schiebt. Das gilt auch für Dinge, die man zu einem bestimmten Zeitpunkt noch nicht berücksichtigt. Je früher man etwas mit einbezieht, desto besser!!!!
  Mit Zitat antworten Zitat
.chicken

Registriert seit: 5. Dez 2006
459 Beiträge
 
#39

Re: Pokerprojekt realisierung

  Alt 7. Apr 2007, 20:27
Ok, wahrscheinlich hast du Recht und ihc bin auch shcon ziemlich durcheinander im Projekt. Das liegt einfach daran, dass am Anfang viele Dinge nicht mit bedacht werden und die dann hinterher füchtig eingesetzt werden!
Ich denke ich schriebe die Units nochmal neu und ordentlich!

Zu der Sache mit dem Controller. Also nur der Server kennt den Controller!
Wenn ein Spieler setzt, schickt er eine Nachricht an den Server, zB:
'Bet[600]' ---> 600setzen
Wenn der Server das empfängt, soll er den Controller benachrichtigen, dass er die procedure Bet aufruft!
Dann kann der Controller aber nichtmehr den Server benachrichtigen, wenn er die procedure ausgeführt hat, weil er den Server ja nicht in den Uses hat!

Ich weiss nun wie ich über-kreuz-uses machen kann, aber ich will es garnicht, will mein Projekt ja hinterher ordentlich haben!

Was hälst du denn davon wie ich die Nachrichten schicke und auswerte?
Ich schreib hier ma n paar Zeilen dazu:
Delphi-Quellcode:
SendText('Call'); //wär zB ein einfacher Call
SendText('SGeld(1)[1500]'); //würde zB das Geld von Spieler 1 auf 1500 setzen
Ansatz so richtig oder Verbesserungsvorschlag?

Zur Auswertung hab ich mir ne Funktion geschrieben, der ich einen String und zwei Zeichen geben kann, und die dann den Substring zwischen den beiden Zeichen ausgibt.
Sieht dann zB so aus:
Delphi-Quellcode:
function TMyClient.Klammern(Value, Search1, Search2: String): String; //eben genannte Funktion
begin
  Result := Copy(Value, Pos(Search1, Value) + 1, Pos(Search2, Value) - Pos(Search1, Value) - 1);
end;


procedure TMyClient.Parse_Text(Value: String); //hier wird dann der Text ausgewertet, hoffe das ist einigermassen verständlich!
var
  temp: String;
begin
  temp := Copy(Value, 0, Pos('[', Value) - 1);
  if temp = 'CBetthen //CBet wird geändert
    CBet := StrtoInt(Klammern(Value, '[', ']'));
  if temp = 'Phasethen //Phase wird geändert
    Phase := StrtoInt(Klammern(Value, '[', ']'));
  if temp = 'SBlindthen //SBlind wird geändert
    SBlind := StrtoInt(Klammern(Value, '[', ']'));
  if temp = 'Dealerthen //Dealer wird geändert
    Dealer := StrtoInt(Klammern(Value, '[', ']'));
  if temp = 'AktiverSpthen //AktiverSp wird geändert
    AktiverSp := StrtoInt(Klammern(Value, '[', ']'));
  if temp = 'Potthen //Pot wird geändert
    Pot := StrtoInt(Klammern(Value, '[', ']'));
  if temp = 'ClientNumberthen //ClientNr wird zugewiesen
    ClientNr := StrtoInt(Klammern(Value, '[', ']'));
  if temp = 'Startthen //Spielstatus
    if Klammern(Value, '[', ']') = 'Truethen
      Start := True
    else
      Start := False;
end;
Gibts da eigentlich ne schönere/bessere Möglichkeit als diese tausend if-Abfragen?


Und dann hab ich da noch ein Problem:
Der Server schickt oft soviele Nachrichten nacheinander, dass der Server beim auswerten die Nachrichten durcheinander bringt, wie kann ich das verhindern?


Danke für die Hilfe und hoffe ich hab nix vergessen, aber jetzt muss mein Hund raus
  Mit Zitat antworten Zitat
Benutzerbild von DGL-luke
DGL-luke

Registriert seit: 1. Apr 2005
Ort: Bad Tölz
4.149 Beiträge
 
Delphi 2006 Professional
 
#40

Re: Pokerprojekt realisierung

  Alt 7. Apr 2007, 20:35
Hallo,

ich würde das nicht per Text machen.

Delphi-Quellcode:
type
  TPlayerActionType = (atBet, atCall, atCheck);

  TPlayerAction = packed record
    TimeStamp: TDateTime;
    ActionType: TActionType;
    Current: Cardinal;
  end;
Das geht schneller auszuwerten und ist weniger tippfehleranfällig.
Lukas Erlacher
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 4 von 7   « Erste     234 56     Letzte »    


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 19:52 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