| |||||||
Du magst keine Werbung? Wir auch nicht!
Einfach registrieren und die Werbung ist weg. Diese Nachricht sehen nur nicht registrierte Nutzer.
![]() |
| | LinkBack | Themen-Optionen | Ansicht |
| | #1 (permalink) |
| Nagelneuer User Registriert seit: Dec 2005
Beiträge: 924
|
Dieser Thread ist aus rendner[i]s Idee entstanden, ein Memoryspiel in OOP zu implementieren. Da ich gerade ein Buch über objektorientiertes Design lese, wollte ich hier gerne mal versuchen, die Methoden und Ideen aus dem Buch auf das konkrete Problem Memory anzuwenden. Ich bin gespannt, was dabei rauskommt. Wenn jemand Erfahrung im OODesign hat, ist er herzlich eingeladen, seinen Senf dazuzugeben. Die anderen natürlich auch. Zuerst muss man mal klären, was das überhaupt ist: Memory. Ich sehe eine Menge von Karten . Die Karten haben alle die gleiche Rückseite. Auf der Vorderseite ist ein Motiv. Jedes Motiv kommt genau zweimal im Spiel vor, die Karten bilden also Paare. 1. Die Karten werden gemischt und dann so auf dem Tisch ausgebreitet, dass nur die Rückseite sichtbar ist. Das Ziel eines Spielers ist es nun, soviele Paare wie möglich zu finden. 2. Der erste Spieler dreht zwei Karten um, so dass ihr Motiv sichtbar wird. Die Position der Karten auf dem Tisch bleibt unverändert. 2a. Sind die Karten verschieden, dreht der Spieler die Karten wieder um. Die Position bleibt dabei wiederum unverändert. Jetzt ist der nächste Spieler an der Reihe (zurück zu Schritt 2). 2b. Sind die Karten gleich, nimmt der Spieler die beiden Karten an sich und legt sie auf seinen Stapel. Die anderen Karten bleiben an ihrem Platz liegen. Die Positonen der beiden herausgenommenen Karten bleiben im weiteren Verlauf des Spiels leer. 3a. Gibt es noch weitere Karten auf dem Tisch, ist der Spieler nochmal dran (zurück zu Schritt 2) 3b. Hat der Spieler das letzte Kartenpaar entnommen, ist das Spiel beendet. 4. Die Stapel der Spieler werden nebeneinander gelegt. Wer den höchsten Stapel hat, hat das Spiel gewonnen.
__________________ The fact that you've got "Replica" written on the side of your gun and the fact that I've got "Desert Eagle written on the side of mine ... :D Geändert von hazy fantazy (11-03-2006 um 15:57 Uhr) |
| | |
| | #2 (permalink) |
| Nagelneuer User Registriert seit: Dec 2005
Beiträge: 924
|
OK, dann suchen wir uns mal die Nomen und Verben raus. 1. Spieler, Spiel, Karte, Tisch, Paar, Position, Vorderseite, Rückseite, Stapel 2. mischen, umdrehen, aufdecken, entnehmen, vergleichen
__________________ The fact that you've got "Replica" written on the side of your gun and the fact that I've got "Desert Eagle written on the side of mine ... :D |
| | |
| | #3 (permalink) |
| Nagelneuer User Registriert seit: Dec 2005
Beiträge: 924
|
Dann versuchen wir mal die Beziehungen zwischen den Nomen festzuhalten. Ein Spiel besteht aus x Karten Auf dem Tisch liegen x Karten Ein Stapel besteht aus x Karten Ein Spieler hat einen Stapel Eine Karte hat eine Position, Vorderseite und Rückseite Ein Paar besteht aus zwei Karten mit gleicher Vorderseite
__________________ The fact that you've got "Replica" written on the side of your gun and the fact that I've got "Desert Eagle written on the side of mine ... :D |
| | |
| | #4 (permalink) |
| Nagelneuer User Registriert seit: Dec 2005
Beiträge: 924
|
Und dann der erste Usecase: Die Karten werden gemischt und verdeckt auf dem Tisch ausgebreitet. Wer macht hier was? Das Spiel erfordert, dass ein Spieler alle Karten aufnimmt, mischt und sie dann auf dem Tisch ausbreitet. Sind die Spieler Teil des Spiels? Haben wir vorhin vergessen. Der Tisch auch? Spiel -> starteSpiel() -> Spieler Spieler -> mischen() -> Alle Karten (Collection?) Spieler -> legeKarte(karte) -> Tisch (für jede Karte einzeln, Iterator?) Der Spieler ist hier irgendwie merkwürdig. Wenn Spieler und Karten im Spiel enthalten sind, dann sollen sie auch nicht miteinander kommunizieren, weil sie im gleichen Scope liegen. aber wie kriege ich sonst die Nachricht mischen an den Mann gebracht? Vielleicht wäre ein neues Objekt Spielrunde besser? Eine Spielrunde enthält die Karten, die Spieler und den Tisch. Spiel -> new(spieler,karten) -> Spielrunde Spielrunde -> mischen() -> Alle Karten (Collection?) Spielrunde -> legeKarte(karte) -> Tisch (für jede Karte einzeln, Iterator?) Tisch -> stellDichDar( position) -> Karte Sieht besser aus, weil so die Messages nur von oben nach unten fliessen und nicht zwischen gleichrangigen Objekten, wie oben.
__________________ The fact that you've got "Replica" written on the side of your gun and the fact that I've got "Desert Eagle written on the side of mine ... :D Geändert von hazy fantazy (11-03-2006 um 16:05 Uhr) |
| | |
| | #5 (permalink) |
| Nagelneuer User Registriert seit: Dec 2005
Beiträge: 924
|
Die Karten liegen jetzt auf dem Tisch und der erste Spieler dreht jetzt 2 Karten um. Spieler -> umdrehen() -> Karte Das Problem hatten wir ja schonmal, der Spieler soll nicht mit der Karte kommunizieren, weil beide im gleichen Scope sind. Stattdessen muss die Spielrunde irgendwie informiert werden, dass der Spieler eine Karte umdrehen will. Weil der Spieler auch keine Nachrichten an die Spielrunde schicken kann, muss die Spielrunde den Spieler pollen. Also Spielrunde pollt Spieler, bis er eine neue Position festgelegt hat. (Man könnte es vielleicht als Mausklick interpretieren?) Spielrunde -> getPosition() -> Spieler Spielrunde -> angeklickt( position) -> Tisch Tisch -> aufdecken() -> Karte Spielrunde -> getAnzahlAufgedeckteKarten() -> Tisch Das geht solange, bis die Anzahl aufgedeckter Karten 2 ist. Anschliessend werden die Karten verglichen. Zeigen sie das gleiche Motiv, bekommt der Spieler sie. Ist das Motiv verschieden, werden sie wieder zurückgedreht. Es ist jetzt die Frage, wo die Logik hinkommt, in die Spielrunde oder in den Tisch? Die Spielrunde wäre naheliegend, mal sehen: Spielrunde -> sindMotiveGleich()-> Tisch Tisch -> istMotivGleich( Karte 2) -> Karte 1 Sieht nicht schlecht aus. Wenn es der Tisch machen würde, müsste ich aber nicht immer abfragen, ob die Anzahl aufgedeckter Karten 2 ist. Stattdessen würde ich nur noch fragen, ob der Spielzug abgeschlossen ist und mir dann das Ergebnis holen. Spielrunde -> getPosition() -> Spieler Spielrunde -> angeklickt( position) -> Tisch Tisch -> aufdecken() -> Karte Wenn zwei Karten aufgedeckt sind: Spielrunde -> istSpielzugVollständig() -> Tisch Wenn ja: Spielrunde -> getErgebnisDesLetztenSpielzugs() -> Tisch Tisch istMotivGleich( Karte 2) -> Karte 1 Wenn die Karten gleich waren Tisch -> entferneKarten() -> Tisch liefere positives Ergebnis mit den Karten als Inhalt Wenn die Karten nicht gleich waren Tisch -> verdecken -> Karte 1 Tisch -> verdecken -> Karte 2 liefere negative Ergebnis Ok, etwas unübersichtlich. Im Zusammenhang sieht das so aus: Spielrunde -> getPosition() -> Spieler Spielrunde -> angeklickt( position) -> Tisch Tisch -> aufdecken() -> Karte A: Spielrunde -> getAnzahlAufgedeckteKarten() -> Tisch Spielrunde: if anzahl == 2 Spielrunde -> sindMotiveGleich()-> Tisch Tisch -> istMotivGleich( Karte 2) -> Karte 1 Spielrunde: if true Spieler -> gebeKarten( Tisch.getAufgedeckteKarten()) Spielrunde: Weiter mit Pollen Spielrunde: if false Spielrunde -> verdeckeKarten() -> Tisch Tisch -> verdecke() -> Karte 1 Tisch -> verdecke() -> Karte 2 Spielrunde -> aktiviereNächstenSpieler() -> Spielrunde Spielrunde: weiter mit Pollen B: Spielrunde -> istSpielzugVollständig() -> Tisch Spielrunde -> getErgebnisDesLetztenSpielzugs() -> Tisch Tisch istMotivGleich( Karte 2) -> Karte 1 Tisch: if true Tisch -> entferneKarten() -> Tisch liefere positives Ergebnis mit den Karten als Inhalt Tisch: if false Tisch -> verdecken -> Karte 1 Tisch -> verdecken -> Karte 2 liefere negative Ergebnis Spielrunde: if ergebnis positiv Spieler -> gebeKarten( ergebnis.getKarten()) Spielrunde: Weiter mit Pollen Spielrunde: if false Spielrunde -> aktiviereNächstenSpieler() -> Spielrunde Spielrunde: weiter mit Pollen B ist (wahrscheinlich) besser, weil dort die Spielrunde nicht als Gottklasse für den Tisch fungiert. Bleiben wir erstmal bei B.
__________________ The fact that you've got "Replica" written on the side of your gun and the fact that I've got "Desert Eagle written on the side of mine ... :D Geändert von hazy fantazy (11-03-2006 um 20:40 Uhr) |
| | |
| | #6 (permalink) |
| Nagelneuer User Registriert seit: Dec 2005
Beiträge: 924
|
Jetzt sind wir ja schon fast fertig. Die letzte Frage ist: Wie wird das Spiel beendet? Wenn das Ergebnis positiv war, fragen wir den Tisch, ob er noch weitere Karten hat, und wenn nicht, beenden wir das Spiel. Spielrunde: if ergebnis negativ Spielrunde -> aktiviereNächstenSpieler() -> Spielrunde Spielrunde: weiter mit Pollen Spielrunde: if ergebnis positiv Spieler -> gebeKarten( ergebnis.getKarten()) Spielrunde -> gibEsNochKarten() -> Tisch if ja Spielrunde: Weiter mit Pollen if nein //spiel beenden
__________________ The fact that you've got "Replica" written on the side of your gun and the fact that I've got "Desert Eagle written on the side of mine ... :D Geändert von hazy fantazy (11-03-2006 um 20:50 Uhr) |
| | |
| | #7 (permalink) |
| Nagelneuer User Registriert seit: Dec 2005
Beiträge: 924
|
Hier ist jetzt mal der ganze Entwurf soweit wie ich den habe: Spiel -> new(spieler,karten) -> Spielrunde Spielrunde -> mischen() -> karten Spielrunde -> zeigeKarten( karten) -> Tisch Tisch -> zeigDich( position) -> Karte (für alle Karten) Repeat Repeat Spielrunde -> getPosition() -> Spieler Spielrunde -> angeklickt( position) -> Tisch Tisch -> aufdecken() -> Karte Until Spielrunde -> istSpielzugVollständig() -> Tisch Spielrunde -> getErgebnisDesLetztenSpielzugs() -> Tisch Tisch istMotivGleich( Karte 2) -> Karte 1 Tisch: if true Tisch -> entferneKarten() -> Tisch liefere positives Ergebnis mit den Karten als Inhalt Tisch: if false Tisch -> verdecken -> Karte 1 Tisch -> verdecken -> Karte 2 liefere negatives Ergebnis Spielrunde: if ergebnis positiv Spieler -> gebeKarten( ergebnis.getKarten()) Spielrunde: Weiter mit Pollen Spielrunde: if false Spielrunde -> aktiviereNächstenSpieler() -> Spielrunde Spielrunde: weiter mit Pollen Spielrunde: if ergebnis negativ Spielrunde -> aktiviereNächstenSpieler() -> Spielrunde Spielrunde: weiter mit Pollen Spielrunde: if ergebnis positiv Spieler -> gebeKarten( ergebnis.getKarten()) Until ! Spielrunde -> gibEsNochKarten() -> Tisch Dass der Spieler den Klick liefert, ist ja eigentlich Unsinn. In einer Implementation( in Flash) würde das die Karte tun. Was würde sich dadurch ändern?
__________________ The fact that you've got "Replica" written on the side of your gun and the fact that I've got "Desert Eagle written on the side of mine ... :D |
| | |
| | #8 (permalink) |
| Nagelneuer User Registriert seit: Dec 2005
Beiträge: 924
|
Spiel -> new(spieler,karten) -> Spielrunde Spielrunde -> mischen() -> karten Spielrunde -> zeigeKarten( karten) -> Tisch Spielrunde -> aktiviereErstenSpieler() -> Spielrunde Spielrunde -> setAktivenSpieler( Spielrunde -> getNext() -> spieler) Repeat Repeat Until Spielrunde -> istSpielzugVollständig() -> Tisch (Tisch handelt klicken und umdrehen intern) Spielrunde -> getErgebnisDesLetztenSpielzugs() -> Tisch (Tisch handelt löschen oder zurückdrehen intern) Spielrunde: if ergebnis negativ Spielrunde -> aktiviereNächstenSpieler() -> Spielrunde Spielrunde: weiter mit Pollen Spielrunde: if ergebnis positiv Spielrunde -> gebeKarten( ergebnis.getKarten()) -> Spieler Until ! Spielrunde -> gibtEsNochKarten() -> Tisch So sieht das schon besser aus. Ist die Frage, ob gibtEsNochKarten die richtige Frage ist. Könnte man auch istSpielBeendet nennen. mfg. h
__________________ The fact that you've got "Replica" written on the side of your gun and the fact that I've got "Desert Eagle written on the side of mine ... :D |
| | |
| | #9 (permalink) |
| Nagelneuer User Registriert seit: Dec 2005
Beiträge: 924
|
Also die Karten sind ja nicht wirklich interessant für den Spieler, das können wir auch durch Punkte ersetzen. Und das Polling muss auch nicht sein, wie ich jetzt gerade gelesen habe. Ein Callback ist auch erlaubt, auch wenn er weniger typsicher ist. Spiel -> new(spieler,karten) -> Spielrunde Spielrunde -> mischen() -> karten Spielrunde -> zeigeKarten( karten) -> Tisch Spielrunde -> aktiviereErstenSpieler() -> Spielrunde Spielrunde -> setAktivenSpieler( Spielrunde -> getNext() -> spieler) on spielzugIstVollständig von Tisch Spielrunde -> getErgebnisDesLetztenSpielzugs() -> Tisch (Tisch handelt löschen oder zurückdrehen intern) Spielrunde: if ergebnis negativ Spielrunde -> aktiviereNächstenSpieler() -> Spielrunde Spielrunde: if ergebnis positiv Spielrunde -> gebePunkte(2) -> Spieler Spielrunde -> gibtEsNochKarten() -> Tisch if false spiel beenden mfg. h
__________________ The fact that you've got "Replica" written on the side of your gun and the fact that I've got "Desert Eagle written on the side of mine ... :D |
| | |
| | #10 (permalink) |
| Nagelneuer User Registriert seit: Dec 2005
Beiträge: 924
|
Die Karten brauche ich ausserhalb des Tisches gar nicht. Die ganze Zuweisung der Karten von aussen macht wenig Sinn. Selbst wenn ich verschiedene Sets von Karten mit unterschiedlichen Motiven benutzen wollte, würde das nur die UI betreffen. Das Kartenobjekt selbst ist davon nicht betroffen. Deshalb verschiebe ich mal die ganze Kartengeschichte in den Tisch. setAktivenSpieler gehört auch nicht ins Interface von Spielrunde, also weg damit. Spiel -> new(spieler) -> Spielrunde Spielrunde -> neuesSpiel() -> Tisch Spielrunde -> aktiviereErstenSpieler() -> Spielrunde on spielzugIstVollständig von Tisch Spielrunde -> getErgebnisDesLetztenSpielzugs() -> Tisch (Tisch handelt löschen oder zurückdrehen intern) Spielrunde: if ergebnis negativ Spielrunde -> aktiviereNächstenSpieler() -> Spielrunde Spielrunde: if ergebnis positiv Spielrunde -> addierePunkte(2) -> Spieler Spielrunde -> istSpielBeendet() -> Tisch if false spiel beenden Auffällig ist, dass wir jetzt mit Memory gar nichts mehr zu tun haben. Das Spielrunde Objekt ist einfach ein abstraktes Objekt, das die Abfolge von Spielzügen koordiniert. Eigentlich schoen, dass ich da durch die relativ stumpfe Anwendung von ein paar Regeln hingekommen bin.
__________________ The fact that you've got "Replica" written on the side of your gun and the fact that I've got "Desert Eagle written on the side of mine ... :D Geändert von hazy fantazy (12-03-2006 um 11:28 Uhr) |
| | |
| | #11 (permalink) |
| helpQLODhelp Registriert seit: Feb 2002 Ort: Köln
Beiträge: 8.505
|
Jetzt fehlt nur noch der Tisch mfg. r
__________________ Ralf Bokelberg™ - Flex & Flash Consulting |
| | |
| | #12 (permalink) |
| Nagelneuer User Registriert seit: Dec 2005
Beiträge: 924
|
Yep, eins nach dem anderen Der Tisch könnte vielleicht so aussehen: Spielrunde -> neuesSpiel()-> Tisch Tisch -> erzeugeKarten() -> Tisch Tisch -> mischen() -> Karten Tisch -> darstellen(position) -> Karte (für jede Karte) Interaktion: Klick auf Karte Karte -> aufdecken() -> Karte Event: karteAufgedeckt -> Tisch Tisch -> zweiKartenAufgedeckt() -> Tisch Event: istSpielzugVollstaendig -> Spielrunde Spielrunde -> getErgebnisDesLetztenSpielzugs() -> Tisch Tisch -> istMotivGleich( Karte2) -> Karte1 if true Tisch -> entferneKarte(Karte1) -> Karten Tisch -> entferneKarte(Karte2) -> Karten return PositivesErgebnis() if false Tisch -> verdecken() -> Karte1 Tisch -> verdecken() -> Karte2 return NegativesErgebnis() Spielrunde -> istSpielBeendet() -> Tisch Tisch -> getAnzahl() -> Karten return Anzahl > 0 Anstatt Callbacks habe ich jetzt Events eingesetzt. Das finde ich irgendwie passender. mfg. h
__________________ The fact that you've got "Replica" written on the side of your gun and the fact that I've got "Desert Eagle written on the side of mine ... :D |
| | |
| | #13 (permalink) |
| Nagelneuer User Registriert seit: Dec 2005
Beiträge: 924
|
Und hier ist jetzt mal eine Implementation des ganzen. Durch die ganze Vorarbeit ging das ziemlich locker von der Hand. Die Erzeugung der GUI ist ein bißchen dirty. Das kann man bei Bedarf sicher hübscher machen, z.B. mit einer Factory für die Karten.
__________________ The fact that you've got "Replica" written on the side of your gun and the fact that I've got "Desert Eagle written on the side of mine ... :D |
| | |
| | #14 (permalink) |
| voidboy Registriert seit: Sep 2004 Ort: München
Beiträge: 5.588
|
Man das ist ja ein Ding, ich häng immer noch an der Überlegung wer die Karten bei mir anordnet und wer die Events verwaltet. Ich sollte mir doch mal ein Buch was dieses Thema abgreift zulegen... Werd mir das mal zu Gemüte führen und etwas sacken lassen und wenn ich Zeit habe setze ich mich mal wieder inspiriert an meins. |
| | |
| | #15 (permalink) |
| Nagelneuer User Registriert seit: Dec 2005
Beiträge: 924
|
Hallo rendner[i], lass dich davon nicht irritieren. Das sollte ja nur ein Versuch sein. Je nach Anforderung kann da bei dir was ganz anderes herauskommen. Ich für meinen Teil fand es auf jeden Fall interessant mal so vorzugehen. Und ich bin mit dem Ergebnis ganz zufrieden. Deshalb habe ich mir gleich das nächste Buch über OOD bestellt mfg. h
__________________ The fact that you've got "Replica" written on the side of your gun and the fact that I've got "Desert Eagle written on the side of mine ... :D |
| | |
![]() |
| Lesezeichen |
| Themen-Optionen | |
| Ansicht | |
| |