--->Kartenspiel programmieren<----

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.
BlackJack

@Michael Schneider: Der Realität kommt `shuffle()` und `pop()` ohne Index am nächsten, also das was ich vorgeschlagen habe. Nach dem Slicen gibt's die Objekte nicht mehrfach, nur mehr Referenzen darauf. Und natürlich kann man die Slices in der Originalliste auch löschen. Man muss die Realität auch nicht bis ins kleinste Detail nachbilden wenn es einfachere oder zweckmässigere Modellierungen gibt.

@AphrodiTe: `append()` ist eine Methode auf Listen. Hast Du schon das Tutorial in der Python-Dokumentation durchgearbeitet? Das ist für die Grundlagen zu empfehlen.

Und gewöhn Dir bitte die ungarische Notation bei Namen ab. Das ist schrecklich und irreführend wenn man den Typ mal ändern sollte und nicht die Namen anpasst.
Benutzeravatar
Michael Schneider
User
Beiträge: 569
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Brandenburg

Hallo,

von mir aus kann man auch Shuffle verwenden. Aber wenn ich das hier eingebe:

Code: Alles auswählen

shuffle(lKarten)
print len(lKarten)
Bekomme ich nur eine Liste mit 28 Karten, statt 32. Warum?

Ich habe mal noch eine Funktion geschrieben, die zu jedem Stich die gueltige Werteliste der Karten berechnet. Den Index der Karte innerhalb dieser Liste kann man verwenden, um den Rang der Karte innerhalb des Stiches zu ermitteln. Die Liste respektiert neben der Farbe und dem Wert auch die Art des Spiels (Grand, Null, Farbe) und die ausgespielte Karte:

Code: Alles auswählen

from random import randint

#   Initialisierung
lFarbspiel = ["Ass", "10", "Koenig", "Dame", "9", "8", "7"]
lNullspiel = ["Ass", "Koenig", "Dame", "Bube", "10", "9", "8", "7"]
lFarben = ["Kreuz", "Pik", "Herz", "Karo"]

lKarten = [(sFarbe, sWert) for sWert in lFarbspiel for sFarbe in lFarben]


def draw_card(lKarten):
    if not lKarten:
        return ()
    return lKarten.pop(randint(0, len(lKarten)-1))

def create_order_list(tAusgespielt, sSpiel="Grand"):
    """Erzeugt eine Liste, die die Reihenfolge der Kartenwerte darstellt.

    tAusgespielt - erwartet ein Kartentupel aus (Farbe, Wert)
    sSpiel       - die Spielart: "Grand", "Null", "Kreuz", "Pik", "Herz", "Karo"
    """
    lOrder = []
    
    #   die Karte wird zerlegt in Farbe und Wert
    sAusspielFarbe, sAusspielWert = tAusgespielt

    #   Beim Grand gilt die Wertordnung des Farbspiels, Buben sind Trumpf    
    if sSpiel == "Grand":
        #   Trumpf (Buben) einfuegen
        lOrder.extend([(sFarbe, "Bube") for sFarbe in lFarben])
        #   Farbe der ausgespielten Karte einfuegen
        lOrder.extend([(sAusspielFarbe, sWert) for sWert in lFarbspiel])
        #   Sonstige Karten einfuegen
        lOrder.extend([(sFarbe, sWert) for sFarbe in lFarben
                                           for sWert in lFarbspiel
                                               if not sFarbe==sAusspielFarbe])

    #   Beim Nullspiel reihen sich 10 und Bube ein
    elif sSpiel == "Null":
        #   Farbe der ausgespielten Karte einfuegen
        lOrder.extend([(sAusspielFarbe, sWert) for sWert in lNullspiel])
        #   Sonstige Karten einfuegen
        lOrder.extend([(sFarbe, sWert) for sFarbe in lFarben
                                           for sWert in lNullspiel
                                               if not sFarbe==sAusspielFarbe])

    #   Bei Farbspielen ist 10 > Koenig, Buben sind hoechste Trumpf
    elif sSpiel in lFarben:
        #   Buben einfuegen
        lOrder.extend([(sFarbe, "Bube") for sFarbe in lFarben])
        #   Trumpffarbe (= Spielfarbe) einfuegen
        lOrder.extend([(sSpiel, sWert) for sWert in lFarbspiel])
        #   Farbe der ausgespielten Karte einfuegen, wenn sie nicht Trumpf ist
        if not sSpiel == sAusspielFarbe:
            lOrder.extend([(sAusspielFarbe, sWert) for sWert in lFarbspiel])
        #   Sonstige Karten einfuegen
        lOrder.extend([(sFarbe, sWert) for sFarbe in lFarben
                                           for sWert in lFarbspiel
                                               if not sFarbe in (sAusspielFarbe, sSpiel)])

    else:
        print "Spielart '%s' ist nicht bekannt" % sSpiel
    return lOrder        

#   erzeugt 3 Kartensets a 10 Karten ('Spieler 1', 'Spieler 2', 'Spieler 3') und den Skat
dKartenSets = {}
for iSpieler in xrange(1, 4):
    dKartenSets["Spieler %i" % iSpieler] = [draw_card(lKarten) for i in xrange(10)]
dKartenSets["Skat"] = lKarten

################################################################################
#   Auswertung/Test
print "Deine Hand"
for tKarte in sorted(dKartenSets["Spieler 1"]):
    print "gezogene Karte: %s %s" % tKarte

#   einen Stich zusammenstellen und fuer verschiedene Spiele gegenueberstellen
t1, t2, t3 = ("Karo", "Dame"), ("Karo", "10"), ("Kreuz", "Ass")
lStich = [t1, t2, t3]

print "="*60
print "Karten des Stichs:", lStich
print "%s %s wird ausgespielt" % t1
for sSpiel in ("Grand", "Null", "Karo", "Kreuz", "Pik"):
    print "\nbeim %s:" % sSpiel
    lKartenWert = create_order_list(tAusgespielt=t1, sSpiel=sSpiel)
    print sorted(lStich, key=lKartenWert.index)
Geht aber bestimmt auch einfacher und besser für Anfänger geeignet.

@BlackJack, hast wieder mal recht. Ich dachte Du wärst kategorisch gegens Poppen. ;-)

Grüße,
Michael
Diese Nachricht zersört sich in 5 Sekunden selbst ...
merlin_emrys
User
Beiträge: 110
Registriert: Freitag 3. März 2006, 09:47

Michael Schneider hat geschrieben:Aber wenn ich das hier eingebe:

Code: Alles auswählen

shuffle(lKarten)
print len(lKarten)
Bekomme ich nur eine Liste mit 28 Karten, statt 32. Warum?
Das kann ich nicht reproduzieren; bei mir sind es nach dem shufflen noch immer 32 Karten... Welche fehlen denn? (Bein Pokern würde ich ja zuerst gezielt nachsehen, ob noch alle Asse dasind, aber ich nehme an, das ist beim Skat nicht so relevant...? Andernfalls würde ich mit der KI mal über Mogeln beim Kartenspiel reden wollen :-D ...)
Benutzeravatar
Rebecca
User
Beiträge: 1662
Registriert: Freitag 3. Februar 2006, 12:28
Wohnort: DN, Heimat: HB
Kontaktdaten:

Michael Schneider hat geschrieben:Deine Abneigung gegenüber Poppen kann ich nicht nachvollziehen.
Ich auch nicht. :wink:

SCNR
Offizielles Python-Tutorial (Deutsche Version)

Urheberrecht, Datenschutz, Informationsfreiheit: Piratenpartei
BlackJack

Ich wurde ja auch falsch verstanden. Ich bin nur gegen wildes, zufälliges poppen, anstelle eines effizienten poppens immer schön der Reihe nach, von hinten. :-D
Benutzeravatar
mkesper
User
Beiträge: 919
Registriert: Montag 20. November 2006, 15:48
Wohnort: formerly known as mkallas
Kontaktdaten:

BlackJack hat geschrieben:Und gewöhn Dir bitte die ungarische Notation bei Namen ab. Das ist schrecklich und irreführend wenn man den Typ mal ändern sollte und nicht die Namen anpasst.
Kommt dieser Unsinn etwa vom Lehrer? Dann sollte ihn schleunigst mal jemand ans Forum oder zumindest an PEP0008 verweisen. :)
AphrodiTe hat geschrieben:Wir haben neulich in der schule mit python angefangen.
AphrodiTe
User
Beiträge: 22
Registriert: Dienstag 18. September 2007, 12:48
Wohnort: Göttingen
Kontaktdaten:

kann ich mit

Code: Alles auswählen

x=["a","b","c"]
if a in x:
    print "a ist in der liste"
fragen ob was in der liste ist??
Die Aussage eines Satzes ist reziprok zur Anzahl der kumulierenden Satzzeichen.
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

Probier' es doch einfach aus, aber um einem Mißverständnis vorzubeugen, das aus Deinem Snippet glänzt:

Code: Alles auswählen

>>> l = ['a', 'b', 'c']
>>> a in l
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
>>> 'a' in l
True
>>> x = 'a'
>>> x in l
True
Gruß,
Christian
AphrodiTe
User
Beiträge: 22
Registriert: Dienstag 18. September 2007, 12:48
Wohnort: Göttingen
Kontaktdaten:

Tut mir leid dass ich es nciht raffe :D aber iwie will es nciht in meinen kopf rein.
ich ahbe eine liste in der 10 karten drinne stehen.
und dann will ich fragen welche karte der benutzer spielen möchte und überprüfen ob die karte in der liste vorhanden ist.

Code: Alles auswählen

karten=["herz 7",...."karo 8"]
x=raw_input("Welche Karte willst du spielen?")
und was kommt dann?
if x in karten = true ???

vielen dank
kai
Die Aussage eines Satzes ist reziprok zur Anzahl der kumulierenden Satzzeichen.
merlin_emrys
User
Beiträge: 110
Registriert: Freitag 3. März 2006, 09:47

Man könnte es so machen, aber das Problem ist in meinen Augen die Tippfehleranfälligkeit. Python ist da ziemlich "pinibel". Ich würde dem Nutzer daher nur eine Auswahl von 1-10 stellen:

Code: Alles auswählen

# -*- coding: cp1252 -*-
karten = ['herz 7', 'karo 9', 'pik dame']
print "Welche Karte möchtest Du spielen? Bitte gibt ein:"
for karte_nummer in range(1,len(karten)+1):
    print "%i für %s" % (karte_nummer, str(karten[karte_nummer-1]))
Kartennummer = raw_input("Bitte nur die Nummer eingeben: ")
Edit:
"zu_legende_Karte" war oben nicht gut eingesetzt. Es ist
zu_legende_Karte = karten[Kartennummer-1]

Der Term -1 ist wieder nur ästhetischen Kriterien geschuldet - ich bin es gewöhnt, Karten von "1" an zu zählen, eine "Karte 0" finde ich einfach irritierend.
AphrodiTe
User
Beiträge: 22
Registriert: Dienstag 18. September 2007, 12:48
Wohnort: Göttingen
Kontaktdaten:

Vielen dank merlin emrys
und danach setzte ich einfach ein append() befehl ein um die karte aus der eigenen hand zu löschen.
danach wollte ich mit einem split() die karte splitten in wert und farbe.damit der computer bedienen kann und damit man am ende karten vergleichen kann.

melde mich dann eh ncohmal :D

kai
Die Aussage eines Satzes ist reziprok zur Anzahl der kumulierenden Satzzeichen.
merlin_emrys
User
Beiträge: 110
Registriert: Freitag 3. März 2006, 09:47

Noch ein Nachtrag:

"raw_input()" ist immer ein bisschen riskant, wie ich hier im Forum gelernt habe. Daher folgender Vorschlag:

Code: Alles auswählen

# -*- coding: cp1252 -*-
karten = ['herz 7', 'karo 9', 'pik dame']
print "Welche Karte möchtest Du spielen? Bitte gibt ein:"
for karte_nummer in range(1,len(karten)+1):
    print "%i für %s" % (karte_nummer, str(karten[karte_nummer-1]))
while True: 
    try: 
        Kartennummer=int(raw_input("Nur die Nummer von 1 - %i bitte: " % len(karten) )) 
    except ValueError: 
        print "Bitte gibt nur eine Nummer im angegebenen Bereich ein!" 
    if Kartennummer in range(1,len(karten)+1):
        break    
Zur Erklärung:
while True leitet eine Endlosschleife ein, die nur verlassen wird, wenn das Probramm einem "break" begegnen. Das tut es in diesem Fall erstmal nur, wenn es schafft, aus dem raw_input()-Ergebnis eine Zahl zu machen, denn das ist die Aufgabe von int(). Wenn das nicht hinhaut, wird die Eingabe nicht weiter behandelt - das heißt, auch wenn jemand da Python-Code eingibt, macht das Programm korrekt weiter, indem es sich einfach weigert, mit dieser Eingabe irgendetwas zu machen.
Und dann sorgt die if-Anweisung dafür, daß nicht eine Zahl genommen wird, die außerhalb der Kartenmenge liegt. Erst, wenn alles okay zu sein scheint, wird die Schleife verlassen und das Programm läuft weiter.
BlackJack

Beide male ist das `range()` ungünstig.

Im ersten Fall ist direktes iterieren über die Karten in Verbindung mit `enumerate()` idiomatischer. Selbst mit `xrange()` würde man beim Angeben der Grenzen 0 und ``len(karten)``, wobei die erste dann wegfallen kann, nur an einer Stelle die Korrektur im 1 machen müssen.

Beim zweiten `range()` wird nur für eine Bereichsüberprüfung eine Liste mit Zahlen erzeugt und in der dann linear gesucht. Das geht auch effizienter/schöner:

Code: Alles auswählen

def main():
    karten = ['herz 7', 'karo 9', 'pik dame']
    
    for i, karte in enumerate(karten):
        print '%d für %s' % (i + 1, karte)
    
    while True:
        try:
            nummer = int(raw_input('Nummer von 1 - %d bitte:' % len(karten)))
            karte = karten[nummer - 1]
            break
        except (ValueError, IndexError):
            print 'Bitte nur eine Nummer im angegebenen Bereich!'
    
    print 'Gewaehlt:', karte
Das ganze liesse sich auch in eine Funktion verpacken, die den Anwender aus einer Liste von Objekten eines auswählen lässt, und wäre damit wiederverwendbar.

Die Modellierung einer Karte als Zeichenkette in der zwei mehr oder weniger unabhängige Informationen, Farbe und Bild/Wert, zusammengefügt sind, ist äusserst ungünstig.
Benutzeravatar
Michael Schneider
User
Beiträge: 569
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Brandenburg

BlackJack hat geschrieben:Nach dem Slicen gibt's die Objekte nicht mehrfach, nur mehr Referenzen darauf.
Natürlich Referenzen. "Gibt es mehrfach" meinte ich in dem Sinne, wie es z.B. Baupläne eines Hauses im Kopf und gleichzeitig auf Papier geben kann. Sonst hätte ich geschrieben, dass neue Objekte erzeugt werden.

Gruß,
Michael
Diese Nachricht zersört sich in 5 Sekunden selbst ...
AphrodiTe
User
Beiträge: 22
Registriert: Dienstag 18. September 2007, 12:48
Wohnort: Göttingen
Kontaktdaten:

vielen dank,
soll ich die befehle append() und del() in die wile-schleife mit einbauen oder eher anch der schleife schreiben?
wollten die karte die man gelegt hat aus der liste jetzt löschen mit del()
und eine neue liste erstellen mit appand()

vielen dank
kai
Die Aussage eines Satzes ist reziprok zur Anzahl der kumulierenden Satzzeichen.
merlin_emrys
User
Beiträge: 110
Registriert: Freitag 3. März 2006, 09:47

AphrodiTe hat geschrieben:vielen dank,
soll ich die befehle append() und del() in die wile-schleife mit einbauen oder eher anch der schleife schreiben?
Es geht beides. Ich würde es eher nach der Schleife machen, aber ich kann nicht genau erklären, warum eigentlich.
AphrodiTe
User
Beiträge: 22
Registriert: Dienstag 18. September 2007, 12:48
Wohnort: Göttingen
Kontaktdaten:

ja ich ahbe es jertzt anch der Schleife eingebaut..

Code: Alles auswählen

del Deine_Karten[nummer-1]
print Deine_Karten
das funktioniert super.
nur wenn ich angeben will dass er in eine neue liste die karte reinschreiben soll macht er es nciht.
habe mir das gedacht:

Code: Alles auswählen

stich.append(Deine_Karten[nummer-1])
stich ist die neue liste die ich vorher schon erstellt ahbe

kai
Die Aussage eines Satzes ist reziprok zur Anzahl der kumulierenden Satzzeichen.
merlin_emrys
User
Beiträge: 110
Registriert: Freitag 3. März 2006, 09:47

Was kommt denn für eine Fehlermeldung?
Ich habe die beiden Befehle jetzt mal in meine letzte Schleifenversion eingebaut (habe keine Lust, sie umzutexten... :-( ), und da scheint es zu funktionieren:

Code: Alles auswählen

# -*- coding: cp1252 -*-
karten = ['herz 7', 'karo 9', 'pik dame']
stich = []
print "Welche Karte möchtest Du spielen? Bitte gibt ein:"
for karte_nummer in range(1,len(karten)+1):
    print "%i für %s" % (karte_nummer, str(karten[karte_nummer-1]))
while True: 
    try: 
        Kartennummer=int(raw_input("Nur die Nummer von 1 - %i bitte: " % len(karten) )) 
    except ValueError: 
        print "Bitte gibt nur eine Nummer im angegebenen Bereich ein!" 
    if Kartennummer in range(1,len(karten)+1):
        print "Gewählt wurde: ", karten[Kartennummer-1]
        stich.append(karten[Kartennummer-1])
        del karten[Kartennummer-1]
        break    
print stich
print karten
Dann bekomme ich:

Code: Alles auswählen

>>> 
Welche Karte möchtest Du spielen? Bitte gibt ein:
1 für herz 7
2 für karo 9
3 für pik dame
Nur die Nummer von 1 - 3 bitte: 2
Gewählt wurde:  karo 9
['karo 9']
['herz 7', 'pik dame']
Edit:
Noch eine Frage an BlackJack: Du hast geschrieben, meine zweite range()-Anwendung sei ungünstig. Ich habe jetzt doch mal meinen Code umgetextet, weil ich mir ein bestimmtes Phänomen nicht erklären konnte. Aber wenn ich die range()-Funktion weglasse, bricht das Programm bei einer zu hohen Zahleneingabe mit einer Fehlermeldung ab, was ich als eher störend empfinde. Jetzt bin ich verwirrt... Wie könnte man falsche Zahleneingaben noch "abfangen"?

(Das erwähnte Phänomen ist leider nicht reproduzierbar: Als ich bei ein paar Testläufen nur die Eingabetaste gedrückt habe, wurde immer zunächst die Meldung "Bitte gibt nur ...." angezeigt und dann der Auswahltext wieder angezeigt, aber sofort (d.h. ohne weitere Eingabe von mir) die Karte 'pik dame' ausgewählt. Jetzt passiert es nicht mehr... Weiß irgendwer, was da los war? Ich verwende zum Testen python 2.4 mit IDLE.)
Zuletzt geändert von merlin_emrys am Mittwoch 19. September 2007, 18:40, insgesamt 2-mal geändert.
schlangenbeschwörer
User
Beiträge: 419
Registriert: Sonntag 3. September 2006, 15:11
Wohnort: in den weiten von NRW
Kontaktdaten:

Was passiert denn? Gibts ne Fehlermeldung?
AphrodiTe
User
Beiträge: 22
Registriert: Dienstag 18. September 2007, 12:48
Wohnort: Göttingen
Kontaktdaten:

hi merlin emrys,
das prob hatte ich auch als ich es ohne die def main(): kopiert habe...alle tabs müssen stimmen...
hab es dann ncoh hinbekommen...


hoffe es geht danach
kai
Die Aussage eines Satzes ist reziprok zur Anzahl der kumulierenden Satzzeichen.
Antworten