Seite 1 von 1

Kartenklasse

Verfasst: Sonntag 24. Mai 2009, 10:07
von Nocta
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.

Verfasst: Sonntag 24. Mai 2009, 10:52
von EyDu
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.

Verfasst: Sonntag 24. Mai 2009, 11:07
von 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.

Verfasst: Sonntag 24. Mai 2009, 11:52
von Dill
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?

Verfasst: Sonntag 24. Mai 2009, 12:14
von Nocta
@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?

Verfasst: Sonntag 24. Mai 2009, 12:41
von 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.

Verfasst: Sonntag 24. Mai 2009, 12:42
von Dill
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


Verfasst: Sonntag 24. Mai 2009, 12:58
von Nocta
@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 :)

Verfasst: Sonntag 24. Mai 2009, 13:10
von Dill
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?

Verfasst: Sonntag 24. Mai 2009, 14:06
von BlackVivi
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/

Verfasst: Sonntag 24. Mai 2009, 14:14
von Dill
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.

Verfasst: Sonntag 24. Mai 2009, 17:06
von Nagila Hawa
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.

Verfasst: Sonntag 24. Mai 2009, 17:23
von Dill
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.