listenproblem

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
acm92
User
Beiträge: 7
Registriert: Samstag 2. November 2013, 20:57

Hallo,
Ich komme beim Programmieren nich weiter :/... es soll ein quartett programmiert werden. bis jetzt habe ich es hinbekommen es für 2 spieler zu programmieren (es gibt hier ja noch den talon und jeder spieler erhält 8 karten), jedoch bekomme ich es irgendwie nicht auf die reihe meinen fehler beim anfang der bedingungen für mehrere spieler richtig hinzubekommen.
ich habe eine liste mit allen karten die bereits gemischt sind ---> mixed_cards
und ich habe eine "große" liste player_cards in die alle listen (also alle Kartenhände der spieler) angelegt werden sollen.
Ich will also je nach eingabe des Spielers so viele listen erstellen.. das hab ich auch soweit glaube ich hinbekommen.
Mein problem ist: wie bekomme ich es hin mit einer schleife, dass mir quasi immer eine karte in eine "kartenhand" also einzelne list ausgeteilt wird
wenn es 4 spieler sind ja gleichmäßig die karten auf liste mit index 0 - 3 aufzuteilen und dann die schleife so lang durchlaufen zu lassen bis in mixed_cards keine Karte bzw. kein Element mehr enthalten ist?

mein bisheriger Code:


Code: Alles auswählen

from random import shuffle

activ_player = 0
player_before = 1
players = 3
player_cards = []
talon = []
index_cards = [31]
cards = ['a1', 'a2', 'a3', 'a4',
         'b1', 'b2', 'b3', 'b4',
         'c1', 'c2', 'c3', 'c4',
         'd1', 'd2', 'd3', 'd4',
         'e1', 'e2', 'e3', 'e4',
         'f1', 'f2', 'f3', 'f4',
         'g1', 'g2', 'g3', 'g4',
         'h1', 'h2', 'h3', 'h4']
mixed_cards = cards.copy()
shuffle(mixed_cards)
next_talon_card = 11

def check_quartet(cards):
    for letter in ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']:
        counter = 0
        # Karten mit "letter" suchen
        for card in cards:
            if letter in card:
                counter += 1
                
        if counter == 4:
            print("Quartett gefunden: " + letter)
            # Karten mit "letter" entfernen/ablegen
            for num in range(1, 5):
                card = letter + str(num)
                cards.remove(card)
        
                
for i, pcards in enumerate(player_cards):
    pcards.sort() #Karten werden nach Zeichen sortiert
    print("Suche nach Quratetts für Spieler %d" % i)
    check_quartet(pcards)
    print(pcards)


if players == 2:
    player_cards.append(mixed_cards[0:10])
    player_cards.append(mixed_cards[10:20])
    talon = mixed_cards[20:32]
    
    while len(player_cards[0] )!= 0 or len(player_cards[1]) != 0:
        print("Spieler", activ_player, "hat die Karten: ")
        print(player_cards[activ_player])
        lookforcard = input("Geben Sie die gesuchte Karte ein:  ")# Hier wird die Karte, die beim Gegenspieler "gesucht" werden soll eingegeben
        if lookforcard in player_cards[player_before]:
            player_cards[activ_player].append(lookforcard)
            player_cards[player_before].remove(lookforcard)
            player_cards[activ_player].sort()
            check_quartet(player_cards[activ_player])
            print("Spieler", activ_player, "hat die Karten: ")
            print(player_cards[activ_player])
            print("Glückwunsch, dein Gegner hat die gewünschte Karte.")
            player_before = (player_before + 1) % 2
            activ_player = (activ_player + 1) % 2
            if len(player_cards[0]) == 0:
                print("Spieler 0 hat gewonnen")
            elif len(player_cards[1]) == 0:
                print ("Spieler 1 hat gewinnen.")
        else:
            print("Leider nichts gefunden. Ziehe eine Karte!")
            player_cards[activ_player].append(talon[next_talon_card])
            del talon[next_talon_card]
            player_cards[activ_player].sort()
            check_quartet(player_cards[activ_player])
            print("Spieler", activ_player, "hat die Karten: ")
            print(player_cards[activ_player])
            player_before = (player_before + 1) % 2
            activ_player = (activ_player + 1) % 2
            next_talon_card= next_talon_card - 1
            if len(player_cards[0]) == 0:
                print("Spieler 0 hat gewonnen")
            elif len(player_cards[1]) == 0:
                print ("Spieler 1 hat gewinnen.")

elif players > 2:
    (x, y ) = divmod(32, players) # x sind die karten , y der rest
    for q in range(x): 
        player_cards([]) # so viele Listen einfügen, wie es spieler gibt
            
        
        for a in range (0, players):
            player_cards[a].append(mixed_cards(x))
            a = a + 1
print (spread_cards.player_cards[0])
Edit(cofi): Code in python-Tags gesetzt.
acm92
User
Beiträge: 7
Registriert: Samstag 2. November 2013, 20:57

der code für 2 spieler funktioniert übrigens einwandfrei :D nur das untere macht probleme
BlackJack

@acm92: Der Code für zwei Spieler ist dann aber überflüssig wenn Du Code für beliebig viele Spieler hast, denn *der* sollte dann auch für zwei funktionieren und den „Sonderfall” damit überflüssig machen.

Versuch nicht die Karten einzeln auszuteilen, sondern immer alle Karten für jeden Mitspieler auf einmal. Machst Du im Fall von zwei Spielern ja auch. Du musst halt nur die Grenzen für's „slicing” berechnen statt absolute Werte in den Quelltext zu schreiben.

Als nächstes solltest Du das Hauptprogramm mal von der Modulebene in eine Funktion verschieben. Das wird sonst nämlich sehr unübersichtlich wenn Du Hauptprogramm und definition von Funktionen vermischst. Von denen kann der Quelltext deutlich mehr vertragen. da wird zu viel in einem grossen Block gemacht. Und zwischen der „Initialisierung” der Variablen am Anfang und deren Verwendung liegt auch zu viel Code. Versuch mal Namen erst dann einzuführen wenn sie tatsächlich benötigt werden, und nicht alle mal auf Vorrat am Anfang. Dann würde zum Beispiel viel eher auffallen das `index_cards` überhaupt gar nicht verwendet wird. Der Wert von `talon` wird auch gar nicht verwendet.

Das Kartendeck hätte man programmatisch erzeugen können statt die alle literal hinzuschreiben.

Eine Kopie von den Karten zu erzeugen macht keinen Sinn da `cards` nie wider benutzt wird. Die `copy()`-Methode auf Listen scheint mir auch *sehr* neu zu sein. Das läuft jedenfalls bei mir unter Python 3.2 nicht. Ein ``list(cards)`` hätte den gleichen Effekt und funktioniert auch mit älteren Python-Versionen.

`next_talon_card` ist überflüssig. Listen haben eine `pop()`-Methode die das letzte Element einer Liste entfernt und als Rückgabewert liefert. Selbst ohne diese Methode hätte man das mit dem Index -1 ohne diese Variable lösen können.

Wenn ich das richtig sehe dann behandelst Du den Fall eines leeren Talons gar nicht‽

Die erste Schleife über die `player_cards` ist sinnfrei weil an der Stelle dieser Name *immer* an die leere Liste gebunden ist, die Schleife also *nie* ausgeführt wird.

Der Name `pcards` an der Stelle zeigt vielleicht ein Problem mit dem Namen `player_cards` auf, denn der müsste eigentlich `players_cards` heissen weil die Liste nicht die Karten *eines* Spielers enthält sondern die Karten *aller* Spieler. `pcards` müsste dann nämlich `player_cards` heissen.

Wie schon gesagt: Die ``if``/``else``-Entscheidung ob es zwei oder mehr Spieler gibt ist nicht sinnvoll weil Code für mehr als zwei Spieler auch mit zwei Spielern funktionieren wird. Der Sonderfall 2 ist kein Sonderfall der extra behandelt werden muss.

Am Anfang und am Ende der ``while``-Schleife testet Du im Grunde auf die selbe Bedingung. Da würde ich eine Endlosschleife (``while True:``) draus machen die mit ``break`` verlassen wird, wenn ein Spieler gewonnen hat. Der Test *darauf* gehört an den Anfang der Schleife denn wenn die Spielkarten aufgehen kann es im Extremfall passieren das ein Spieler schon nach dem Austeilen *nur* Quartette bekommen hat. Es kann sogar passieren, dass das mehr als einen Spieler betrifft, also sollte man aufpassen, dass man auch mit mehr als einem Spieler mit 0 Karten klar kommt.

Der Code enthält einiges an kopiertem Quelltext. Zum Beispiel die Ausgabe was der aktive Spieler an Karten hält, der Test ob/wer gewonnen hat, und das weitersetzen des `activ_player`-Wertes. Die letzten beiden Sachen gehören nicht in das ``if``/``else`` sondern danach. Für die Ausgabe der Spielerhand kann man eine Funktion schreiben.

Da die Karten der Spieler immer sortiert sind, könntest Du Dir mal `bisect.insort()` anschauen. Die Funktion fügt ein Element in eine sortiere Liste an der richtigen Stelle ein, so dass sie danach immer noch sortiert ist. Das ist effizienter als eine Liste zu sortieren bei der nur ein einzelnes Element nicht an der richtigen Stelle ist.

`player_before` ist überflüssig, denn das hat immer den Wert von `activ_player` - 1, ausser wenn `activ_player` gleich Null ist. Aber selbst dann funktioniert ``activ_player - 1`` korrekt als Index in eine Liste, denn Index -1 ist das letzte Element der Liste.

`check_quartet()` ist ziemlich ineffizient und macht deutlich mehr als man bei dem Funktionsnamen erwarten würde, nämlich einfach nur einen Test ob oder wieviele Quartette vorhanden sind. Jedenfall nicht das auch Ausgaben getätigt werden und `cards` verändert wird. Zur Effizienz: Rechne mal aus wie oft die `cards`-Liste immer wieder von vorne durchlaufen wird. Bedenke dabei auch das `remove()` die Liste auch von vorne nach dem Element durchsucht bis das passende gefunden wurde. Und dann überlege mal wie man den Umstand das die Liste *sortiert* ist, ausnutzen kann um das effizienter zu programmieren.

Englisch: Weder `mixed_cards` noch `spread_cards` erscheinen mir passend. Denn weder das „mixed” noch das „spread” meinen gemischt und verteilt im Sinne von Karten mischen oder verteilen. „Mixed” ist eher das vermischen von *verschiedenen* Dingen, also zum Beispiel Quartettkarten vermischt mit einem Skat-Blatt oder verschiedene Quartett-Spiele vermischt. „Spread” sagt man zum Beispiel im Zusammenhang mit Brotaufstrich der auf dem Brot verteilt wird. Dabei geht es also nicht um das verteilen von hart abgegrenzten Objekten sondern eher um das auftragen/verschmieren von etwas.
acm92
User
Beiträge: 7
Registriert: Samstag 2. November 2013, 20:57

@BlackJack
mein Problem ist nur, dass es ja für 2 spieler diesen Talon gibt und nicht für mehrere spieler
und bei mehreren spielern habe ich das problem wie ich die restkarten aufteile es sind ja 32 karten

(x, y ) = divmod(32, players) # x sind die karten , y der rest

durch das hier rechne ich ja aus wieviele karten jeder bekommen soll und wieviele übrig bleiben
die sollen dann noch auf irgendwelche spieler aufgeteilt werden egal welche hauptsache dann nur eine davon an spieler
es ist dann nicht schlimm wenn mehrere spieler 1 karte mehr habe wie die anderen
bei mir hakt es momentan einfach an der umsetzung
hätte vill erst das für mehrere spieler schreiben sollen anstatt das für 2
kann mich da nichtmehr so gut reindenken
naja vill wird das ja heute noch was :D
vielen dank für die ausführliche antwort :)
acm92
User
Beiträge: 7
Registriert: Samstag 2. November 2013, 20:57

und wie könnte ich zb durch die eingabe des users genau so viele listen erstellen lassen wie es user gibt?
acm92
User
Beiträge: 7
Registriert: Samstag 2. November 2013, 20:57

so nun bin ich vom denken her weitergekommen
aber das programm macht natürlich nicht ganz was was ich will :D
irgendwie verteilt es mir wenn ich zb 4 spieler eingebe
nur karten auf die ersten 3 listen die 4. wird ausgelassen
sieht jemand den fehler?

mein jetziger stand:

Code: Alles auswählen

from random import shuffle

cards = ['a1', 'a2', 'a3', 'a4',
'b1', 'b2', 'b3', 'b4',
'c1', 'c2', 'c3', 'c4',
'd1', 'd2', 'd3', 'd4',
'e1', 'e2', 'e3', 'e4',
'f1', 'f2', 'f3', 'f4',
'g1', 'g2', 'g3', 'g4',
'h1', 'h2', 'h3', 'h4']
shuffle(cards)

all_players = [ ] # Liste mit allen Kartenhänden der Spieler

players = int(input("Geben Sie die gewünschte Spieleranzahl ein: "))

for i in range(players):
    all_players.append([ ])

(x,y) = divmod(32, players)

a = 0 # in welcher liste einer Spielerhand befinden wir uns gerade
w = 0 # startpunkt in cards (ab welchem element sollen die karten "genommen" werden)
k = x-1 # endpunkt in cards (bis zu welchem elemment "

while len(cards) > 0:
    all_players[a].append(cards[w:k]) # letztes element der liste cards wird an all_players übergeben
    a = a+1
    w = w + x #x-wert dazuaddieren also die Kartenanzahl
    k = k + x #y-wert                  "
    if a == players-1:
        break
    
        
print("alle spieler:",all_players)
print("karten allg", cards)

in der SHELL siehts so aus:
Geben Sie die gewünschte Spieleranzahl ein: 4

alle spieler: [[['d4', 'h1', 'f1', 'a4', 'e2', 'b2', 'd2']], [['d3', 'h4', 'f2', 'd1', 'h3', 'c2', 'a2']], [['e4', 'g4', 'e1', 'b1', 'g3', 'g1', 'a1']], []]

karten allg ['d4', 'h1', 'f1', 'a4', 'e2', 'b2', 'd2', 'h2', 'd3', 'h4', 'f2', 'd1', 'h3', 'c2', 'a2', 'f4', 'e4', 'g4', 'e1', 'b1', 'g3', 'g1', 'a1', 'b4', 'c3', 'e3', 'c4', 'g2', 'f3', 'c1', 'b3', 'a3']
Zuletzt geändert von Anonymous am Samstag 23. November 2013, 14:34, insgesamt 2-mal geändert.
Grund: Code-Tags an die richtige Stelle verschoben.
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

ja ich seh den Fehler! Und noch ein paar andere.
Die hart kodierete 32 in divmod ist wohl die Anzahl der Karten, also schreib das auch so.
Die Bedingung der while-Schleife wird nie falsch, weil sie die Länge von cards nicht ändert.
append macht nicht das was Du willst.
Da Du die while-Schleife nicht sinnvoll benutzt, kannst Du auch gleich eine for-Schleife nehmen, um
die Player durchzugehen, statt umständlich einen Index hochzuzählen. (Da steckt auch Dein Fehler)
Es gehen ein paar Karten verloren.
BlackJack

@acm92: Lass diesen ganzen einbuchstabigen Indexkram weg. Man kann in Python Indexvariablen und Zugriffe sehr oft komplett vermeiden, und sollte das auch tun.

Code: Alles auswählen

    players = [[] for _ in range(player_count)]
    player_cycle = itertools.cycle(players)
    while cards:
        next(player_cycle).append(cards.pop())
Antworten