HeldenGenerator für "Das Weltenbuch"

Code-Stücke können hier veröffentlicht werden.
Benutzeravatar
gkuhl
User
Beiträge: 600
Registriert: Dienstag 25. November 2008, 18:03
Wohnort: Hong Kong

Guten Abend allerseits,

ich habe in den letzten Wochen damit begonnen Python zu lernen und wollte euch jetzt mal um eure Meinung/Kritik zu meinem Code bitten. Es handelt sich um ein kleinen Ansatz für ein Programm mit dem man einen Helden für das PnP Rollenspiel "Das Weltenbuch" erstellen kann.

Der Code: HeldenGenerator.py, Held.py, GetData.py, TextInput.py, TextOutput.py.
Weitere Dateien: Klischee, StartAttr.


Grüße
Gerrit


Edit: Sowas ärgerliches. Scheinbar ist beim Kopieren ein Unterstrich in HeldenGenerator.py abhanden gekommen. :shock:
Fehler korrigiert.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Ich hab das grad nur kurz überflogen, aber kann das sein, dass du aus der Java-Welt kommst? Durch "private" Attribute, die du durch simple Getter/Setter bearbeitest, verkomplizierst du deinen Code nur unnötig.
Außerdem muss nicht alles eine Klasse sein, Python kennt durchaus Funktionen ;)

Es gibt ein paar Essays die Python und Java vergleichen: Hier zum Beispiel
Benutzeravatar
gkuhl
User
Beiträge: 600
Registriert: Dienstag 25. November 2008, 18:03
Wohnort: Hong Kong

Danke für's drüber schauen. Was Programmierung angeht bin ich eigentlich ziemlicher Neuling, wenn man mal von den beiden Einführungskursen in FORTRAN und C absieht. Mit Java habe ich also noch nichts zu tun gehabt. Zum Python lernen habe ich mir "Object Oriented Programming in Python" von Goldwasser und Letscher ausgeliehen und bisher den ersten Teil von zweien gelesen.

Hab jetzt mal die ganzen Getter/Setter Funktionen und dadurch den Code doch deutlich entschlackt. Wo sollte ich denn deiner Meinung auf Klassen verzichten und stattdessen Funktionen verwenden.

Der Code: HeldenGenerator2.py
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Wenn ich das gerade richtig sehe, dann solltest du nur eine einzige Klasse verwenden, nämlich `Held'.
Bei der objektorientierung versucht man Objekte abzubilden, mit ihren Daten und Fähigkeiten, d.h. in dem Fall:
Benutze die Initialisierung des Helden, keine Extra Klasse. Warum Extra Klassen für input und output? Das kannst du auch gut durch Funktionen erreichen, da du nie wirklich mit den Objekten arbeitest, sondern nur mit deren Methoden -> eigentlich sind es Funktionen in einem extra Namensraum ;)

Die Extra-Dateien kannst du auch in den Anfang deiner Python-Datei schreiben:

Code: Alles auswählen

START_ATTRIBUTES = {"Elf" : (7,6,7,2,5,5)}
Oder wie auch immer du darauf zugreifen willst. Du kannst das natürlich auch in eine extra Datei `config.py' schreiben und das im Code verwenden, das verkompliziert das anpassen etwas, aber wirklich nur wenig, ausserdem sollte es sich ja um quasi Konstanten handeln, wenn ich das richtig sehe.

Auch solltest du Englisch und Deutsch nicht im Quelltext mischen, Kommentare gehn noch, aber sonst sollte man nur Englisch benutzen.

Zu dem Buch: Wow, das ist mal ein Preis oO. Aber ist wohl nicht alles Gold was viel kostet, wenn es dich so einen Code schreiben lässt, weil das doch recht Unpythonisch ist. Schau dir am besten mal das Tutorial an, das verschafft einen guten Überblick.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Habs nur mal ganz kurz angeguckt, aber print_hero() wäre typerischerweise eine Methode von Held; so in der Richtung: Objekt.druck_dich()!
Benutzeravatar
gkuhl
User
Beiträge: 600
Registriert: Dienstag 25. November 2008, 18:03
Wohnort: Hong Kong

cofi hat geschrieben:Wenn ich das gerade richtig sehe, dann solltest du nur eine einzige Klasse verwenden, nämlich `Held'.
Bei der objektorientierung versucht man Objekte abzubilden, mit ihren Daten und Fähigkeiten, d.h. in dem Fall:
Benutze die Initialisierung des Helden, keine Extra Klasse. Warum Extra Klassen für input und output? Das kannst du auch gut durch Funktionen erreichen, da du nie wirklich mit den Objekten arbeitest, sondern nur mit deren Methoden -> eigentlich sind es Funktionen in einem extra Namensraum ;)
Naja, hatte eigentlich das Buch verwendet, weil ich gehofft habe, damit objektorientiertes programmieren zu lernen. Hab mich bei meinem Programm an einem Beispiel aus dem Buch orientiert. Dort ging es um die Programmierung von Mastermind. Dabei wurde auch alles in extra Klassen ausgelagert u.a. Klassen für Input und Output um diese später durch GUI zu ersetzen zu können.
Die Extra-Dateien kannst du auch in den Anfang deiner Python-Datei schreiben:

Code: Alles auswählen

START_ATTRIBUTES = {"Elf" : (7,6,7,2,5,5)}
Oder wie auch immer du darauf zugreifen willst. Du kannst das natürlich auch in eine extra Datei `config.py' schreiben
Da es im original derzeit 15 Rassen und 55 Klischees gibt, werde ich mal versuchen mir eine 'config.py' zu basteln.
Auch solltest du Englisch und Deutsch nicht im Quelltext mischen, Kommentare gehn noch, aber sonst sollte man nur Englisch benutzen.
Da es sich um ein deutsches RPG handelt, hatte ich mich dazu entschieden, die Begriffe aus des Regeln (Held, Name, Rasse, Klischee, Hintergrund, Flags, Attribut, Fertigkeit und Ausrüstung) zu verwenden und ansonsten auf die Englisch zurückzugreifen.
Zu dem Buch: Wow, das ist mal ein Preis oO. Aber ist wohl nicht alles Gold was viel kostet, wenn es dich so einen Code schreiben lässt, weil das doch recht Unpythonisch ist.

Naja, habs mir ja nicht gekauft. Werde mir mal das Tutorial anschauen und schauen ob der Code dort pythonischer ist. :)
Hyperion hat geschrieben:Habs nur mal ganz kurz angeguckt, aber print_hero() wäre typerischerweise eine Methode von Held; so in der Richtung: Objekt.druck_dich()!
Hab's mal als "__str__" Methode eingebaut:

Code: Alles auswählen

def __str__(self):
    '''Gibt den Helden mit "print self" in der Konsole aus.'''
    return  '\n' + self.name.upper() + '\n' \
            '-----------------------------------------------' + '\n' + \
            'Rasse:               ' + self.rasse + '\n' + \
            'Klischee:            ' + self.klischee + '\n' + \
            'Klischeefertigkeit:  ' + self.klischee_fertigkeit + '\n' + \
            'Klischeeausrüstung:  ' + self.klischee_ausruestung + '\n' + \
            '-----------------------------------------------' + '\n' + \
            'Startattribute:' + '\n' + \
            'Geist:    ' + self.attribut[0] + \
            '          Sozial:   ' + self.attribut[3] + '\n' + \
            'Körper:   ' + self.attribut[1] + \
            '          Wille:    ' + self.attribut[4] + '\n' + \
            'Geschick: ' + self.attribut[2] + \
            '          Sinne:    ' + self.attribut[5] + '\n' + \
            '-----------------------------------------------\n'
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

gkuhl hat geschrieben:Naja, hatte eigentlich das Buch verwendet, weil ich gehofft habe, damit objektorientiertes programmieren zu lernen. Hab mich bei meinem Programm an einem Beispiel aus dem Buch orientiert. Dort ging es um die Programmierung von Mastermind. Dabei wurde auch alles in extra Klassen ausgelagert u.a. Klassen für Input und Output um diese später durch GUI zu ersetzen zu können.
Also das was du vom Buch erzählst macht es nicht gerade empfehlenswert. Teilung zwischen GUI und Lokig würde man sowieso anders machen. Am einfachsten ist es die Logik in einem Modul zu implementieren und die UI in einem anderen Modul. Dabei müssen Klassen gar nicht verwendet werden, insbesondere für eine einfache Textausgabe ist das völlig unnötig.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
lunar

Hyperion hat geschrieben:Habs nur mal ganz kurz angeguckt, aber print_hero() wäre typerischerweise eine Methode von Held; so in der Richtung: Objekt.druck_dich()!
Eher nicht. Ein Objekt der Logik-Schicht hat keine Ahnung vom Darstellungsmedium und kann sich deswegen auch nicht "drucken". Dafür ist dann die entsprechende Ansicht in der Präsentationsschicht verantwortlich.
Benutzeravatar
gkuhl
User
Beiträge: 600
Registriert: Dienstag 25. November 2008, 18:03
Wohnort: Hong Kong

So, hab jetzt mal eure Tipps in den Code einfließen lassen. Hat den Code doch erheblich verbessert und vor allem deutlich kürzer gemacht: Hier der Code.

Danke für die vielen Tipps
Gerrit
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Ich seh da jetzt allerdings noch einen größeren Haken: Du benutzt die Initialisierung nicht für eine echte Inititialisierung, sondern passt die Werte im Nachhinein an. Ich weiss jetzt nicht wie bindend die gewählten Klischees sind, aber zumindest Name, Rasse und damit zusammenhängend die Startattribute sollten sich doch nicht mehr ändern nachdem der Held erzeugt wurde - geht natürlich trotzdem - also kannst du das auch in die Initialisierung mit rein nehmen.

Zum Buch: Die Trennung von Logik und GUI ist wichtig und gut, aber Klassen? Brauchst du hier nicht wirklich und ich würde deine __str__ methode in eine Funktion abändern, die dann auf einer übergebenen `Held'-Instanz arbeitet(ohne deinen Code anderweitig anzupassen):

Code: Alles auswählen

def print_hero(hero):
    line = '-' * 42 + '\n'
    tab = ' ' * 10
    return  '\n' + self.name.upper() + '\n' + line + \
    'Rasse:               ' + hero.rasse + '\n' + \
    'Klischee:            ' + hero.klischee + '\n' + \
    'Klischeefertigkeit:  ' + hero.klischee_fertigkeit + '\n' + \
    'Klischeeausrüstung:  ' + hero.klischee_ausruestung + '\n' + \
    line + 'Startattribute:\n' \
    'Geist:    ' + str(hero.attribut[0]) + tab  + \
    'Sozial:   ' + str(hero.attribut[3]) + '\n' + \
    'Körper:   ' + str(hero.attribut[1]) + tab  + \
    'Wille:    ' + str(hero.attribut[4]) + '\n' + \
    'Geschick: ' + str(hero.attribut[2]) + tab  + \
    'Sinne:    ' + str(hero.attribut[5]) + '\n' + line
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

gkuhl hat geschrieben:r das PnP Rollenspiel "Das Weltenbuch" erstellen kann.
Hi, ich bin ein alter PnP Rollenspieler, seit einiger Zeit aber im Ruhestand :(
Das Weltenbuch kenne ich allerdings noch nicht. Hab es mal überflogen und es macht einen recht spaßigen Eindruck. Spielst du das schon länger?
Benutzeravatar
gkuhl
User
Beiträge: 600
Registriert: Dienstag 25. November 2008, 18:03
Wohnort: Hong Kong

@burli: Länger ja, aber leider nicht im Sinne von oft. Wir versuchen zur Zeit seit etwa einem Jahr zu spielen, haben bisher aber nur einen einzigen Spielabend geschafft. Da ich zur Zeit im Ausland bin, wird das vor nächstes Jahr wohl auch wieder nichts werden. :cry:

@cofi: Meinst du damit in etwa so etwas?

Code: Alles auswählen

if __name__ == '__main__':
    name = query_name()
    race = query_race()
    stereotype = query_stereotype(race)
    attribute = START_ATTRIBUTES[race]
    hero = Hero(name, race, stereotype, attribute)
    print print_hero(hero)
Ich hab mittlerweile übrigens nach sinnvollen englischen Übersetzungen geschaut. Man kann sich ja leider nie 120% sicher sein. :wink:
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Ja das meine ich - zumindest wenn __init__ entsprechend ausschaut ;)

Zu print_hero nochwas: Du kannst auch Triple Quotes nehmen (""" """), die tolerieren Zeilenumbrüche im Quelltest, so könntest du dir viele `\' und `\n' sparen. Ausserdem kannst du String-Formating benutzen und Zahlen musst du nicht explizit in einen String konvertieren. Wie das geht, erzähl ich jetzt aber nicht *g*
Benutzeravatar
gkuhl
User
Beiträge: 600
Registriert: Dienstag 25. November 2008, 18:03
Wohnort: Hong Kong

cofi hat geschrieben:Du kannst auch Triple Quotes nehmen (""" """)
Danke, daran hab ich jetzt gar nicht gedacht.

Hier nochmal der neuste Code:
- HeldenGenerator2.py
- Config.py

Eine Sache noch in dem Zusammenhang. Gibts eine Möglichkeit, dass man trotzdem zwischen den Triple Quotes einrücken kann, ohne dass dies in den String übernommen wird? Negative Leerzeichen zum Beispiel...?
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Wenn ich dich jetzt richtig verstehe, willst du führende Leerzeichen entfernen?

Code: Alles auswählen

import textwrap
textwrap.dedent(text)
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

siehe [wiki=Lange_Zeilen_im_Sourcecode#LangeStrings]diesen wiki-eintrag[/wiki]
Benutzeravatar
gkuhl
User
Beiträge: 600
Registriert: Dienstag 25. November 2008, 18:03
Wohnort: Hong Kong

Danke, funktioniert :D
pheder
User
Beiträge: 11
Registriert: Dienstag 14. Oktober 2008, 15:56
Kontaktdaten:

Ich glaub ich muss auch mal mitmischen, wenns auch nur ne ganz unwichtige Sache ist:

Code: Alles auswählen

i = 0
print ''
for race in STEREOTYPES.keys():
    i += 1
    print str(i) + ': ' + race
kannst du auch ersetzen durch:

Code: Alles auswählen

i = 0
print ''
for race in STEREOTYPES:
    i += 1
    print str(i) + ': ' + race
Eine Iteration über ein Dictionary liefert immer die Keys.

Was mich trotzdem noch stört ist dieses "i=0" und "i+=1", ich komm vom Gedanken nicht weg, dass man das vermeiden könnte... Aber das wird wohl auch nur eine Wunschvorstellung sein :cry:
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Klar geht das besser ;)

Code: Alles auswählen

for i, race in enumerate(STEREOTYPES):
    print i+1 " : " + race
wenn mans denn bei der Nummerierung lassen will, statt bei 0 anzufangen.
yipyip
User
Beiträge: 418
Registriert: Samstag 12. Juli 2008, 01:18

Das ist keine Wunschvorstellung, sondern nennt sich
'enumerate()'

Code: Alles auswählen

In [49]: for i, k in enumerate(['hexe', 'Gnom', 'Beamter']):
   ....:     print '%s: %s' % (i, k)
   ....:     
   ....:     
0: hexe
1: Gnom
2: Beamter

:wink:
yipyip
Antworten