Kartenklasse

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Nocta
User
Beiträge: 290
Registriert: Freitag 22. Juni 2007, 14:13

Hi.
Wie würdet ihr eine Klasse für Karten (Skat) implementieren?
Ich programmiere gerade ein Skat Spiel und frage mich, ob folgendes wirklich so sinnvoll ist (das wesentliche der Klasse):

Code: Alles auswählen

class Card(object):
    values = ('ace', '10', 'king', 'queen', 'jack', '9', '8', '7')
    suits = ('clubs', 'spades', 'hearts', 'diamonds')
    
    def __init__(self, value, suit):
        self.value = value
        self.suit = suit
Ich bin gerade bei dem Problem, dass ich die Karten ja irgendwie sortieren können muss. Und zwar am besten nach verschiedenen Kriterien, da es verschiedene Spielarten gibt, in denen verschiedene Karten Trümpfe sind, weshalb diese auch jeweils anders sortiert werden müssen.
Es geht dabei nicht nur ums Sortieren sondern auch um das Abbilden der Rangfolge, damit das Programm vergleichen kann, welche Karte höher und welche niedriger ist. Ich denke das ist auf diesem Weg ziemlich umständlich.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Um die Karten zu vergleichen würde ich für jede Spielart eine compare-Funktion schreiben, mit der man dann zwei Karten vergeichen kann. Sortieren hätte man damit auch gleich erschlagen.

Aus meinre Sicht würde ich in diesem Fall tatsächlich Funktionen benutzen und den Karten keine x Methoden für jede Spielart zuweisen, da die Reihenfolge in diesem Fall eine extrinsische Eigenschaft ist (abhängig vom aktuellen Spiel).

Mit dem bisherigen "Entwurf" deiner Karten-Klasse kannst du nicht viel falsch machen. Du solltest aber noch über die Spieler und den Tisch nachdenken, das sind die interessanteren Aufgaben.
Das Leben ist wie ein Tennisball.
BlackJack

@Nocta: Ich schliesse mich EyDu an, das was Du beschreibst ist nichts was in die Verantwortlichkeit der Karten fällt, dafür ist auf das konkrete Spiel bezogenes Wissen erforderlich.

Den Spielkarten selber würde ich höchstens das "übliche" Wissen für Vergleiche mitgeben, also dass eine Dame einen höheren Wert hat, als eine 10 und die einen höheren als eine 7, und so weiter. Und die übliche Farbenreihenfolge.
Benutzeravatar
Dill
User
Beiträge: 470
Registriert: Mittwoch 10. Januar 2007, 14:52
Wohnort: Köln

BlackJack hat geschrieben:... dass eine Dame einen höheren Wert hat, als eine 10 und die einen höheren als eine 7, und so weiter. Und die übliche Farbenreihenfolge.
das ist beim skat etwas problematisch. je nach spiel unterschiedlich:

farbenspiel, grand: as > 10 > bilder > luschen (9,8,7); bauern immer trumpf
nullspiele: as > bilder > 10 > luschen, kein trumpf

selbst dieses wissen den karten anzuvertrauen ist problematisch.

wichtiger schritt im design. wenn du zuständigkeiten falsch verteilst handelst du dir später probleme ein. (es gibt natürlich immer mehrere sinnvolle lösungen)
aber hatten wir das thema nicht schonmal?
http://www.kinderpornos.info
Nocta
User
Beiträge: 290
Registriert: Freitag 22. Juni 2007, 14:13

@Dill: Ja das Thema hatten wir schonmal ;)

Also ihr würdet die Karten Klasse so belassen?
Ich hatte auch nicht vor, alles in die Kartenklasse zu packen, ich habe eine klasse 'Tisch', die bisher alle Objekte kennt (Spieler + Karten, Kartenstapel, ...) und auch weiß, was gespielt wird, was wie gesagt die Kartenrangfolge beeinflusst.
Was ich eigentlich meinte ist, dass ich es umständlich finde, auf Basis dieser Kartenklasse - die nur aus 2 Strings besteht - das Sortieren/Vergleichen etc aufzubauen.
Entweder bau ich echt für jede Spielart eine compare-Methode ein und jede Karte weiß, bei welcher Spielart sie welchen Rang hat. Das würde sogar noch funktionieren, da es nicht so viele verschiedene Möglichkeiten gibt (Grand, Null, 4 Farbspiele, evtl. Ramsch). Oder ich mache das irgendwie anders, wofür ihr ja offensichtlich alle seid.
Und ihr habt ja auch recht, die Karte ist eigentlich nicht dafür verantwortlich, was für ein Spiel gespielt wird und ob sie Trumpf ist oder nicht etc.
Aber wie soll ich das dann möglichst elegant machen?
Die Karte sagt dem Programm: Ich bin ein Kreuz Bube. Und wie kann ich dem Programm dann am besten vermitteln, dass der Kreuz Bube in diesem Spiel diesen und jenen Rang hat?
BlackJack

@Dill: Ich bin dabei nur von Karten ausgegangen, die man eventuell wiederverwenden will, nicht von einem speziellen Spiel.

Allgemeinen Karten würde ich diese Sortierreihenfolge mitgeben, denn die ist ziemlich gebräuchlich. Viele Spiele können mit diesen Regeln arbeiten oder zumindest darauf aufbauen, also zum Beispiel eine eigene Sortierreihenfolge definieren. Beispielsweise wenn eine bestimmte, dynamisch festgelegte, Farbe mehr Wert ist als die anderen, kann man in einer Sortierfunktion für dieses spezielle Spiel vorranging nach Trumpf und nicht Trumpf sortieren, innerhalb dieser Gruppen, aber auf die "natürliche" Reihenfolge der Karten zurückgreifen. Beispiel (ungetestet):

Code: Alles auswählen

def sort_with_trump(trump_suite, cards):
    cards.sort(key=lambda c: (c.suite == trump_suite, c))
@Nocta: Man könnte zusätzlich zu den beiden Zeichenketten den Karten noch ein Tupel mit zwei Zahlen für Farbe und Wert geben. Daran kann man dann zumindest die "natürlichen" Werte der Karten untereinander leicht vergleichen.

Eine Zuordnung Karte nach Rang für ein konkretes Spiel, klingt nach einem Dictionary. Der Rang müsste dann auch ein mit anderen Rängen vergleichbares Objekt sein, dann kann man zum Beispiel Karten mit ``cards.sort(key=card2rank.get)`` sortieren.
Benutzeravatar
Dill
User
Beiträge: 470
Registriert: Mittwoch 10. Januar 2007, 14:52
Wohnort: Köln

ja, über die strings zu vergleichen ist natürlich weniger schön.
mir fällt jetzt aber auch keine wirklich schöne lösung ein.

aber ein vorschlag, wie wärs damit:

Code: Alles auswählen

#die verschiedenen spiele halten tupel mit der kartenstaerke

Nullspiel.kartenstaerke = ("ass", "koenig",..., "10", "9",...)
Grandspiel.kartenstaerke = ("ass", "10", "koenig", ...)
Farbenspiel.kartenstaerke = s.o.

>>>Nullspiel.kartenstaerke.index("10") < Nullspiel.kartenstaerke.index("koenig")

False

>>>Farbenspiel.kartenstaerke.index("10") < Farbenspiel.kartenstaerke.index("koenig") 

True

http://www.kinderpornos.info
Nocta
User
Beiträge: 290
Registriert: Freitag 22. Juni 2007, 14:13

@BlackJack: Die natürliche Reihenfolge (jedenfalls für Skat die natürliche Reihenfolge) habe ich indirekt schon mit den beiden Klassenvariablen defininiert, ich könnte da zB per values.index() auch an den Zahlenwert rankommen. Aber schöner wäre es, diese Zahlenwerte nochmal extra zu speichern, das stimmt.
Eine Zuordnung Karte nach Rang für ein konkretes Spiel, klingt nach einem Dictionary. Der Rang müsste dann auch ein mit anderen Rängen vergleichbares Objekt sein, dann kann man zum Beispiel Karten mit ``cards.sort(key=card2rank.get)`` sortieren.
Sorry, aber ich kann da keinen klaren (für mich verständlichen) Lösungsvorschlag rauslesen :)


@Dill: Die Idee hatte ich auch schon, ich hätte die 6 Compare Funktionen wohl mit einer Liste/Tupel und dem index() (wie oben beschrieben) geschrieben. Das kommt mir aber ziemlich umständlich vor. Oder kann man damit auch auf leichtem Wege sortieren? Am liebsten wäre mir nämlich eine Lösung, die Karten sortiert und dadurch auch logischerweise gleichzeitig eine Rangfolge abbildet. Vielleicht kann mir das BlackJack (oder gerne auch jemand anders) nochmal genauer erklären :)
Benutzeravatar
Dill
User
Beiträge: 470
Registriert: Mittwoch 10. Januar 2007, 14:52
Wohnort: Köln

was für 6 compare funktionen meinst du?

du musst doch nur schauen welche karte den 3er stoss gewinnt..
dieser stoss ist eine liste mit 3 karten-instanzen. diese musst du doch nur anhand des merkmals stärke sortieren.

dazu bräuchtest du einen getter get_ stärke der über eine assoziation mit dem aktuell gespielten spiel auf das stärke tupel zugreift.

Code: Alles auswählen


class karte:
    
    get_staerke(self):
        return self.aktuelles_spiel.kartenstaerke.index(self.value)
        #trumpf noch nicht bedacht. über suite und aktuelles spiel zb noch nen trump-offset draufaddieren!
naja, schön ist das nicht. aber hier bestehen eben abhängigkeiten, die sich irgendwie im code niederschlagen.
gibt aber sicher auch ne schönere lösung.

edit: du musst für sort glaub ich __compare__ implementieren?
http://www.kinderpornos.info
Benutzeravatar
BlackVivi
User
Beiträge: 762
Registriert: Samstag 9. Dezember 2006, 14:29
Kontaktdaten:

http://paste.pocoo.org/show/118855/

So würd ich's machen. Wobei man die Exceptions + Nachschauen ob die Karte auch wirklich Bestandteil ist weglassen kann.

Man könnte sogar types und symbols überschreiben und so eine eigene Reihenfolge oder ein eigenes Kartenspiel erstellen.

(Ich persönlich würd die Exceptions und die Abfrage sogar weglassen. Aber naja...)

Edit: Hab die __cmp__ nochmal leichter geschrieben =/ Doofe 4 Zeiler.

http://paste.pocoo.org/show/118915/
Zuletzt geändert von BlackVivi am Sonntag 24. Mai 2009, 20:24, insgesamt 1-mal geändert.
Benutzeravatar
Dill
User
Beiträge: 470
Registriert: Mittwoch 10. Januar 2007, 14:52
Wohnort: Köln

ja, so in etwa hab ich mir das auch vorgestellt.

wobei __cmp__ über self.tisch.aktuelles_spiel.types an die aktuelle reihenfolge rankommt.

oben habe ich self.aktuelles_spiel geschrieben. das ist aber unsinn. das spiel ändert sich ja. also die karten sollten eher nicht mit jedem spiel geändert werden sondern direkt mit tisch assoziiert sein. die assoziation läuft idealerweise auch nicht über eine karteninstanz, sondern über die klasse.wobei ich hier mit meinem python am ende bin wie man das am geschicktesten implementiert.
http://www.kinderpornos.info
Nagila Hawa
User
Beiträge: 16
Registriert: Montag 9. Juni 2008, 18:20
Kontaktdaten:

Moin!

Ich würde die Klasse (oder den Typ "Values") allgemein halten. Das heißt noch mit den Werten 6 bis 1 und Joker. Aussortieren kannst du dann im jeweiligen Spiel. Je nachdem, ob das in Python möglich ist, kannst du von diesem Obertyp je nach Spiel natürlich auch spezielle Typen ableiten (Values_Skat, Values_Poker...) damit nur die Karten verwendet werden, die es auch gibt.

Das Problem mit den unterschiedlichen Wertigkeiten pro Spiel oder gar Spielsituation (Skat) würde ich einfach über die Indizes lösen, die du je Spiel dann anpasst. Entweder du kannst die Indizes direkt anpassen, oder du nutzt beispielsweise eine Liste in der du die "Values" nach Wertigkeit sortiert ablegst.
Benutzeravatar
Dill
User
Beiträge: 470
Registriert: Mittwoch 10. Januar 2007, 14:52
Wohnort: Köln

das ist ja jetzt schon möglich.

Karte kennt nur die farbe und den wert.
und kann sich mit einer anderen karte vergleichen und nutz dazu ein vom spiel abhängiges tupel in dem die werte in der jeweiligen wertigkeit abgespeichert sind.
http://www.kinderpornos.info
Antworten