tictactoe(anfänger)

Code-Stücke können hier veröffentlicht werden.
BlackJack

@marlene: Dazu ist ein `dict` dann wohl die falsche Datenstruktur, weil die Elemente eben keine Reihenfolge haben.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

marlene hat geschrieben: Nur der erste soll zufällig gewählt werden, ab da soll das wie bei einer "echten Würfelrunde" nach der Reihe weiter gehen.
Kapiere ich so noch nicht! Was bedeutet "nächster" Spieler? Die Reihenfolge eines Dicts ist ja letztlich zufällig, da sie von den Daten und der Implementierung des Python-Interpreters abhängt. Wenn Du die Reihenfolge von dict.keys() als Referenz nimmst, könnte ich Dir folgen. Aber: Was passiert, wenn man Spieler 3 "erwischt", dann nimmt man vier und dann? Geht es bei 1 weiter? Worin besteht der Vorteil gegenüber einer rein zufällugen Mischung, wie ich sie zuvor vorgeschlagen habe? Was passiert nach einer Runde? Soll in der darauffolgenden exakt die gleiche Reihenfolge eingehalten werden, oder wechselt das wieder?
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
marlene
User
Beiträge: 26
Registriert: Montag 13. September 2010, 12:11

Ich hatte vorher eine Liste in dem die Teilnehmer gespeichert waren z.B players = ["hans“, "uwe“, "peter“]. Aus dieser Liste habe ich per Zufallszahl einen Index gezogen z.B. 1, was dann „uwe“ wäre. Soweit funktioniert das mit dem ‚dict‘ ja auch. Das Spiel würde jetzt so "laufen", uwe fängt an, danach kommt peter und danach hans dann wieder uwe usw. bis einer gewonnen hat. Bei einer Liste hab ich das erreicht einfach durch raufsetzen des Index um 1, beim ‚dict‘ hab ich jetzt aber ein Problem, weil ich nicht weiss wie ich das mit einem ‚dict‘ realisieren kann, oder ob das überhaupt möglich ist so wie ich mir das vorstelle?


Die Anregung dazu kam von Dauerbaustelle:
Was mir bei genauerem Hinsehen noch auffällt: Die von dir gewählte Datenstruktur für das Speichern der Spieler und des Punktestandes ist nicht besonders gut. Was du willst ist ein "Spieler-Punktestand"-Mapping. Schau dir mal Dictionaries an.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Ich glaube du suchst ein OrderedDict: http://docs.python.org/library/collecti ... rderedDict
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Du hast also bei einem "Zug" nur immer einen Spieler bzw. das Objekt dahinter in Benutzung? Dann brauchst Du kein Dictionary, da Du ja das Objekt einfach durch iterieren bekommst und nicht nebenbei (schnellen) Zugriff auf andere Spieler benötigst. Da wäre eine Liste besser geeignet. Darauf wendest Du eben wie oben gezeigt shuffle an und iterierst über die Liste.

Meine Idee oben setzt das ja letztlich auch um, außer, dass im Hintergrund ein Dict die eigentlichen Daten beinhaltet und die Liste nur für das Iterieren und den zufälligen Zugriff angelegt wird.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
marlene
User
Beiträge: 26
Registriert: Montag 13. September 2010, 12:11

@Hyperion: ja ich glaub du hast recht.

Ich habe es jetzt so gemacht.

Code: Alles auswählen

def next_player_index(player, players):
    next_player = list(players.keys())
    index = (next_player.index(player) + 1) %len(next_player)
    return next_player[index]
marlene
User
Beiträge: 26
Registriert: Montag 13. September 2010, 12:11

Ich hab das ganze jetzt verbessert und galube das ich alle Verbesserungen(Anrgungen), verändert oder eingebaut habe.

User Teil:

Code: Alles auswählen

from time import sleep
import logik

def game(players, win_points):
    win = False
    print
    print('Es wird ausgewuerfelt wer anfaengt')
    player = logik.pick_first_player(players)
    print('%s feangt an.') % (player)
    while win is False:
        print
        print('Punktestand: %s ') % (players)
        print
        print('%s ist dran.') % (player)
        raw_input('Enter druecken zum weurfeln.')
        cache_dices = logik.roll_dices()
        for dice in cache_dices:
            sleep(0.8)
            print('wuerfeln....  %s') % (dice)
            if dice == 1:
                print('Sie haben 1 gewuerfelt, und bekommen 0 Punkte.')
                cache_dices = [0]
                break
        players = logik.add_points_to_player(players, player, cache_dices)
        if logik.check_winner(players, win_points):
            print('%s hat gewonnen.') % (player)
            print
            print players
            print
            win = True
        player = logik.next_player_index(player, players)
        
def main():
    while True:
        choice = raw_input("Neues Spiel (yes/no)? ")
        if choice == "no":
            break
        players = {}
        rules = raw_input('Spielregeln anzeigen ja(j) nein(n): ')
        if rules == 'j':
            print("""
            Es wird reihum gewuerfelt. Wer die hoechste Augenzahl
            in der ersten Runde hat darf anfangen.
            Nun darf jeder Spieler viermal wuerfeln.
            Die Augen werden immer addiert, wuerfelt man eine
            Eins wird der gesamte Wurf ungueltig und der naechste ist dran.
                 """)
        players_number = int(raw_input('Spieleranzahl: '))
        for number in range(players_number):
            player = raw_input('Name Spieler: ')
            players[player] = 0
        win_points = int(raw_input('Punkte zum Gewinn angeben: '))
        game(players, win_points)
    
if __name__ == '__main__':
    main()
logik modul:

Code: Alles auswählen

from random import randint
from random import choice

def pick_first_player(players):
    return choice(players.keys())

def roll_dices(count=4):
    return [randint(1, 6) for _ in xrange(count)]

def add_points_to_player(players, player, cache_dices):
    players[player] += sum(cache_dices)
    return players
          
def check_winner(players, win_points):
    for points in players.values():
        if points >= win_points:
            return True

def next_player_index(player, players):
    next_player = list(players.keys())
    index = (next_player.index(player) + 1) %len(next_player)
    return next_player[index]
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

marlene hat geschrieben:@Hyperion: ja ich glaub du hast recht.

Ich habe es jetzt so gemacht.

Code: Alles auswählen

def next_player_index(player, players):
    next_player = list(players.keys())
    index = (next_player.index(player) + 1) %len(next_player)
    return next_player[index]
Hui... das ist jetzt nicht wirklich toll!

Wieso nutzt Du nicht shuffle()? Das hatte ich Dich doch in diesem Post beschrieben: http://www.python-forum.de/viewtopic.ph ... 53#p191553

Du musst Dir dann eben die zufällig gewürfelte Spielerliste merken und der Spiel-Funktion übergeben. Aber das ist imho besser, als in einer Funktion für den nächsten Spieler immer so ein Brimborium zu machen und der neben dem aktuellen Spieler auch noch das gesamte Dict zu übergeben.

Kurze Anmerkung noch:

Code: Alles auswählen

next_player = list(players.keys())
# exakt das gleiche wie
next_player = players.keys()
{}.keys() liefert bereits eine Liste; diese musst Du nicht noch in eine wandeln ;-)

Du kannst anschließend itertools.cycle() benutzen, um nacheinander alle Spieler-Keys durchzugehen. Anhand des Keys kannst Du dann über das players-Dictionary an den Punktestand kommen.

Alternativ könnte Deine Spieler-Struktur auch so aussehen:

Code: Alles auswählen

players = [
    ["Chris", 0],
    ["Marlene", 35],
    ...
]
Das Dict ist zwar eine nette Idee, aber hier ginge es imho auch so. ok, so kann es uneindeutige Spielernamen geben; aber dafür hat man ja den Index der Liste als eindeutigen Identifier. Vorteil hier: Du kannst direkt über der Liste "shufflen" und ersparst Dir damit die player_keys Liste aus meinem Alternativvorschlag.

Deine Hauptschleife sähe dann so aus:

Code: Alles auswählen

for player in cycle(players):
    print "Spieler {0} ist ander Reihe.".format(player[0])
    print "Punkte: {0}".format(player[1])
Ist Dir der Indexzugriff zu unschön, dann kann man auch noch den Zugriff über itemgetter realisieren:

Code: Alles auswählen

# auf Modulebene
from operator import itemgetter

name, points = itemgetter(0), itemgetter(1)
# und dann später
    print "Name: {0}, Punkte: {1}".format(name(player), points(player))
Als weitere Alternative ginge auch das hier:

Code: Alles auswählen

players = [
    {"name": "Chris", "points": 0},
    {"name": "Marlene", "points": 34},
    ...
]
Also eine Liste von Dicts. Vorteil hier: Du kannst die Liste schön shufflen, hast beim Zugriff auf die Elemente eines Spielers dann aber wieder schönere "Namen". Also man sieht sofort, dass Du an den Namen heran willst, oder die Punkte (Ähnlich wie die Methode über die itemgetter).

Als letzte Anmerkung: Mir gefällt die Auslagerung von Code in dieses logik-modul nicht! Zum einen steckt viel Spiellogik ja auch in der game()-Funktion, zum anderen ist das alles so wenig Code, dass man da kein eigenes Modul zu benötigt. Und generisch genug, als dass man ihn wiederverwenden könnte ist er imho auch nicht. Also würde ich das bei einem Modul belassen.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Dauerbaustelle
User
Beiträge: 996
Registriert: Mittwoch 9. Januar 2008, 13:48

@Hyperion: Sowohl Dictionary als auch separates Modul waren meine Idee. Die Diskussion muss also gegen mich gerichtet sein ;-)

Ad Dictionary: Ich denke schon, dass da ein Dict her sollte, weil sie hat eben ein Mapping in eine Richtung (Spieler->Punktestand). Wenn es da jetzt Probleme mit dem Shuffeln gibt, könnte man einfach die ``.keys()`` nehmen und die dann eben randomisieren (vorausgesetzt es kommen im Laufe des Spieles keine weiteren Spieler dazu).

Modul: Das habe ich empfohlen zu Lernzwecken. Pragmatisch gesehen macht es natürlich bei so wenig Code keinen Sinn, das auszulagern. Alledings hatte sie Schwierigkeiten, Benutzerinteraktion und Spiellogik zu trennen, und da ist ein Modul doch ein ganz gutes "Werkzeug", eben weil man gezwungen wird, das Ganze schön zu trennen.

Anstatt den imo hässlichen itemgettern würde ich dann lieber ein ``collections.namedtuple`` nehmen (oder gleiche eine Klasse, wenn man die Elemente ändern möchte).
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Dauerbaustelle hat geschrieben:@Hyperion: Sowohl Dictionary als auch separates Modul waren meine Idee. Die Diskussion muss also gegen mich gerichtet sein ;-)
Hehe... naja "gegen" klingt jetzt imho negativ! :-)
Dauerbaustelle hat geschrieben: Ad Dictionary: Ich denke schon, dass da ein Dict her sollte, weil sie hat eben ein Mapping in eine Richtung (Spieler->Punktestand). Wenn es da jetzt Probleme mit dem Shuffeln gibt, könnte man einfach die ``.keys()`` nehmen und die dann eben randomisieren (vorausgesetzt es kommen im Laufe des Spieles keine weiteren Spieler dazu).
Das war dann ja auch mein erster Vorschlag. Allerdings sehe ich hier den Einsatz von Mappings eher begrenzt. Richtig wertvoll werden diese imho erst dann, wenn man öfter ein Objekt über einen Key finden muss. Dieses "finden" ist hier ja ziemlich unnötig, weil man über eine Spielerdatenstruktur iteriert und damit das Objekt direkt vorliegen hat. Insofern kann man hier auch auf eine Liste von Listen oder Dicts zurückgreifen und spart sich damit beim randomisieren die separate Liste von Keys. Aber ok, geht damit ja auch :-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Antworten