Sinnvolle Aufteilung in Klassen

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.
Benutzeravatar
DaMutz
User
Beiträge: 202
Registriert: Freitag 31. Oktober 2008, 17:25

@yipyip: gib mal negative Zahlen ein ;-)
yipyip
User
Beiträge: 418
Registriert: Samstag 12. Juli 2008, 01:18

Dann muss ich eben doch noch nachsitzen. (Sollte ja eigentlich nur ein kleine Skizze werden...)

Code: Alles auswählen

def ask_attributes(attributes, max_points=100):

  available = max_points
  length = len(attributes)
  attr_points = dict.fromkeys(attributes, 0)
  
  for i, attr in enumerate(attributes):
    while True:
      try:
        points = int(raw_input("Attribute %s (max=%d, %d. from %d) -> " %
                               (attr, available, i+1, length)))
        if points < 0:
          print "That's to little!"
          continue
        if available < points:
          print "That's to much!"
        else:
          break
      except ValueError:
        print "Hu?"
 
    attr_points[attr] = points
    available -= points
    
    if not available:
      print 'No more points!'
      break

  return attr_points


my_attributes = ['Smartness', 'Stamina', 'Strength', 'Intelligence', 'Humor']
print ask_attributes(my_attributes)
:wink:
yipyip
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

yipyip hat geschrieben:Dann muss ich eben doch noch nachsitzen.
Wenn du schon dabei bist, dann möchtest du aus dem einen if ein elif machen und das überflüssige continue entfernen ^^
Das Leben ist wie ein Tennisball.
heal.p
User
Beiträge: 30
Registriert: Freitag 3. Dezember 2010, 12:28

Danke euch allen, ich werd mir die Sachen mal anschaun und wer das mal versuchen auf mich anzupassen und ins Script einzubaun. Werde das Script dann wieder posten :D
Xynon1 hat geschrieben: 3. Wieso schreibst du die Abfragen doppelt und dreifach, nutze dafür doch einfach eine Schleife
Mich nimmt jedoch immer noch wunder wie das den Xynon1 gelöst hätte :) Den schliesslich habe ich auf seine Kritik hin mich mit der Schleife versucht.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Ich würde Datenmodell und Programmlogik besser trennen. Vielleicht so:

Code: Alles auswählen

#!/opt/local/bin/python2.7

class Character:
    def __init__(self):
        self.name = "Anonymous"
        self.strength = 0
        self.agility = 0
        self.stamina = 0
        self.intelligence = 0
    
    def compute_secondary_attributes(self):
        self.health = self.stamina * 6 + 100
    
    def points_spent(self):
        return self.strength + self.agility + self.stamina + self.intelligence
    
    def set(self, attribute, value):
        if attribute == "str": self.strength = value
        elif attribute == "agi": self.agility = value
        elif attribute == "sta": self.stamina = value
        elif attribute == "int": self.intelligence = value
        else: raise ValueError
    
    def __str__(self):
        return "%s (strength=%d, agility=%d, stamina=%d, intelligence=%d)" % (
            self.name, self.strength, self.agility, self.stamina, self.intelligence)

def create_character(points_to_spend):
    ch = Character()
    ch.name = raw_input('Name: ')
    while True:
        print "Now distribute %s skill points to attributes." % points_to_spend
        print "You have %s points left." % (points_to_spend - ch.points_spent())
        attribute = raw_input("Which attribute (str/agi/sta/int): ")
        if not attribute:
            return ch
        try:
            ch.set(attribute, int(raw_input("Value: ")))
        except ValueError:
            print "Invalid input. Please try again."

print create_character(25)
Stefan
BlackJack

@sma: Ich finde ja die `set()`-Methode unschön. Man könnte die Attribute auch mit `setattr()` von aussen ändern. Wahrscheinlich hätte ich in der `__init__()` die Werte entgegen genommen und da ein vom Benutzer befülltes Dictionary mit ``**``-Syntax übergeben.
heal.p
User
Beiträge: 30
Registriert: Freitag 3. Dezember 2010, 12:28

sma hat geschrieben:Ich würde Datenmodell und Programmlogik besser trennen. Vielleicht so:

Code: Alles auswählen

#!/opt/local/bin/python2.7

class Character:
    def __init__(self):
        self.name = "Anonymous"
        self.strength = 0
        self.agility = 0
        self.stamina = 0
        self.intelligence = 0
    
    def compute_secondary_attributes(self):
        self.health = self.stamina * 6 + 100
    
    def points_spent(self):
        return self.strength + self.agility + self.stamina + self.intelligence
    
    def set(self, attribute, value):
        if attribute == "str": self.strength = value
        elif attribute == "agi": self.agility = value
        elif attribute == "sta": self.stamina = value
        elif attribute == "int": self.intelligence = value
        else: raise ValueError
    
    def __str__(self):
        return "%s (strength=%d, agility=%d, stamina=%d, intelligence=%d)" % (
            self.name, self.strength, self.agility, self.stamina, self.intelligence)

def create_character(points_to_spend):
    ch = Character()
    ch.name = raw_input('Name: ')
    while True:
        print "Now distribute %s skill points to attributes." % points_to_spend
        print "You have %s points left." % (points_to_spend - ch.points_spent())
        attribute = raw_input("Which attribute (str/agi/sta/int): ")
        if not attribute:
            return ch
        try:
            ch.set(attribute, int(raw_input("Value: ")))
        except ValueError:
            print "Invalid input. Please try again."

print create_character(25)
Stefan
Mit class habe ich noch nicht so gearbeitet. Verstehe es auch noch nicht ganz. Aber danke für deine Idee, deinen Ansatz. Werde ich mir auch mal anschaun.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

heal.p hat geschrieben:Mich nimmt jedoch immer noch wunder wie das den Xynon1 gelöst hätte :) Den schliesslich habe ich auf seine Kritik hin mich mit der Schleife versucht.
Nach deinem gestrigen Ansatz hätte ich es etwa so gehabt, allerdings ist ein Character Objekt wesentlich schöner.

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: cp1252 -*-
from collections import defaultdict

def set_skill(name, skillpoints):
    print("\nDir stehen {0} Skillpunkte zur Verfügung.".format(skillpoints))
    question = "Wieviele Punkte sollen in {0} investiert werden? ".format(name)
    while True:
        try:
            points = int(raw_input(question))                         
            if 0 <= points <= skillpoints:
                return points           
            else:
                print "Zuwenig Skillpunkte verfügbar."
                         
        except ValueError:
            print "Deine Eingabe ist ungültig."

if __name__ == "__main__":
    skillpoints = 25
    alternate_name = "Namenloser"
    attributes = defaultdict.fromkeys(["Stärke", "Beweglichkeit", "Ausdauer",
                                       "Intelligenz"], 0)

    name = raw_input("Welchen Namen soll der Charakter tragen? ")
    if name == "":
        name = alternate_name
        
    print("Willkommen {0}, du kannst nun folgende Fertigkeiten trainieren:" \
          "\n{1}".format(name, "\n".join(attributes)))
    while skillpoints > 0:
        for attribute_name in attributes:
            points = set_skill(attribute_name, skillpoints)
            attributes[attribute_name] += points
            skillpoints -= points
            if skillpoints == 0:
                break
        
    weapon = None
    hp = 100 + (attributes["Ausdauer"] * 6)
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
heal.p
User
Beiträge: 30
Registriert: Freitag 3. Dezember 2010, 12:28

Xynon1 hat geschrieben:
heal.p hat geschrieben:Mich nimmt jedoch immer noch wunder wie das den Xynon1 gelöst hätte :) Den schliesslich habe ich auf seine Kritik hin mich mit der Schleife versucht.
Nach deinem gestrigen Ansatz hätte ich es etwa so gehabt, allerdings ist ein Character Objekt wesentlich schöner.
Mhh. Was ich immernoch nicht ganz begriffen habe ist was

Code: Alles auswählen

if __name__ == "__main__":
macht :?
Jedoch versteh ich deinen Ansatz am besten. Die Vorschläge von sma und yipyip verwirren mich noch zusehr. Bin noch nicht so fortgeschritten in Python. :wink:
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Prüft lediglich ob das Modul, naja nicht importiert wurde, also das aktuelle ist.
Also der Text darunter wird nur aufgerufen wenn du den Script direkt ausführst,
wenn du das Modul von wo anders importierst wird alles darunter ignoriert.
Zuletzt geändert von Xynon1 am Donnerstag 6. Januar 2011, 13:37, insgesamt 1-mal geändert.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
BlackJack

@heal.p: `__name__` wird von Python an den Namen des Moduls gebunden, also der Dateiname ohne `.py` am Ende. Mit einer Ausnahme: Das Modul was man als Programm gestartet hat, bekommt den Namen '__main__' -- egal wie die Datei heisst. Wenn Du das Modul also als Programm startest, wird der ``if``-Zweig ausgeführt. Wenn man das Modul dagegen in einer Python-Shell oder einem anderen Modul importiert, dann wird der ``if``-Zweig nicht ausgeführt, weil `__name__` dann ja nicht '__main__' ist.
heal.p
User
Beiträge: 30
Registriert: Freitag 3. Dezember 2010, 12:28

Xynon1 hat geschrieben:Prüft lediglich ob das Modul, naja nicht importiert wurde, also das aktuelle ist.
Also der Text darunter wird nur aufgerufen wenn du den Script direkt ausführst,
wenn du das Modul von wo anders importierst wird alles darunter ignoriert.
Und was habe ich davon für einen Nutzen? Das ich die Funktion nicht einfach so starten kann?
Edit: Oke dank BlackJack wurde es mir noch klarer was es macht, jedoch ist mir immer noch nicht ganz klar, was es für einen Nutzen haben soll.

Würde soetwas Sinn machen?

Code: Alles auswählen

hp = 100 + (attributes["Ausdauer"] * 6)
stre = attributes["Stärke"]
agi = attributes["Beweglichkeit"]
stam = attributes["Ausdauer"]
intel = attributes["Intelligenz"]
Damit ich die Attribute wieder über dir Kürzel ansteuern kann? :/
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

heal.p hat geschrieben:Und was habe ich davon für einen Nutzen? Das ich die Funktion nicht einfach so starten kann?
Wenn du nicht mit Modulen arbeitest macht es für dich keinen Unterschied.

Du könntest es auch so machen:

Code: Alles auswählen

...
attribute_names = ["Stärke", "Beweglichkeit", "Ausdauer", "Intelligenz"]
attributes = defaultdict.fromkeys(attribute_names, 0)
stre, agi, stam, intel = [attributes[name] for name in attribute_names]
...
Aber so würdest du eine doppelte Verwaltung der Attribute haben, also auch nicht schön, denn wenn du "stre" änderst, ändert sich nicht die Dictionary und umgekehrt auch nicht.
Wie viele Attribute siehst du eigentlich vor ?
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
heal.p
User
Beiträge: 30
Registriert: Freitag 3. Dezember 2010, 12:28

Xynon1 hat geschrieben:
heal.p hat geschrieben:Und was habe ich davon für einen Nutzen? Das ich die Funktion nicht einfach so starten kann?
Wenn du nicht mit Modulen arbeitest macht es für dich keinen Unterschied.

Aber so würdest du eine doppelte Verwaltung der Attribute haben, also auch nicht schön, denn wenn du "stre" änderst, ändert sich nicht die Dictionary.
Wie viele Attribute siehst du eigentlich vor ?
Ööhm, mit Modulen arbeiten wäre wohl besser? Sollte ich mich wohl mal drüber infomieren.

Attribute sehe ich eigentlich bis jetzt folgende vor: Stärke, Beweglichkeit, Ausdauer, Intelligenz, Leben, Schaden und evt Abgewehrter Schaden.
Die Attribute Leben, Schaden und Abgewehrter Schaden sollen jenachdem wieviele Punkte ich auf Stärke, Beweglichkeit, Ausdauer und Intelligenz habe skalieren. Da ich jetzt mal ne Lösung habe und diese auch verstehe, versuche ich mich jetzt mal dran gegen einen Gegner zu kämpfen. Bzw die Funktionen Schaden zu machen zu schreiben usw.

Edit: Vll später noch Erfahrung und Level.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Wenn du diesen Ansatz wirklich weiter ausbauen willst solltest du noch etwas Zeit in OOP investieren.
Was brauchst du denn bei einem Kampf ?
1. Ein Charakter
2. Ein Gegner

Wie willst du einen Kampf berechnen ?
1. Anhand der Attribute
2. Etwas Zufall

Schlußfolgerung, dein Gegner braucht auch Attribute.
Willst du nun wirklich überall einzelne Dictionaries rumschwirren lassen mit Attibuten und hp, (max_hp), ...

Denk über eine Characterklasse nach, denn eine Instanz von dieser, kann sowohl dein Hero als auch jeder Gegner sein, damit sparst du dir viel Arbeit und man kann einen Überblick behalten.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
BlackJack

Auch wenn man erst einmal mit nur einem Modul arbeitet, kann das ``if __name__ ...`` Sinn machen. Man kann das dann importieren, ohne dass es als Programm ausgeführt wird, und einzelne Funktionen testen, zum Beispiel um einen Fehler zu suchen. Automatisierte Tests sind auch möglich.
heal.p
User
Beiträge: 30
Registriert: Freitag 3. Dezember 2010, 12:28

Xynon1 hat geschrieben:Wenn du diesen Ansatz wirklich weiter ausbauen willst solltest du noch etwas Zeit in OOP investieren.
Was brauchst du denn bei einem Kampf ?
1. Ein Charakter
2. Ein Gegner

Wie willst du einen Kampf berechnen ?
1. Anhand der Attribute
2. Etwas Zufall

Schlußfolgerung, dein Gegner braucht auch Attribute.
Willst du nun wirklich überall einzelne Dictionaries rumschwirren lassen mit Attibuten und hp, (max_hp), ...

Denk über eine Characterklasse nach, denn eine Instanz von dieser, kann sowohl dein Hero als auch jeder Gegner sein, damit sparst du dir viel Arbeit und man kann einen Überblick behalten.
Mhh. Ich werd mich mal ins Thema einlesen und versuchen zum zusetzen. Ist der Code von sma OOP gerecht geschrieben, oder ist das nochmal was ganz anderes? Den seinen Code verstehe ich nur zum Teil.
Hast du eventuell noch eine gute Seite wo mir erklärt wird wie ich das mit den Klassen aufbaun muss, bzw richtig verwende?
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Ein gutes Tutorial ist immer das offizielle http://docs.python.org/tutorial/classes ... ss-objects
Ansonsten würde ich noch dringend vom Python GalileoComputing Openbook abraten.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
heal.p
User
Beiträge: 30
Registriert: Freitag 3. Dezember 2010, 12:28

Xynon1 hat geschrieben:Ein gutes Tutorial ist immer das offizielle http://docs.python.org/tutorial/classes ... ss-objects
Ansonsten würde ich noch dringend vom Python GalileoComputing Openbook abraten.
Das offizielle gabs doch auch auf Deutsch? Denke das würde mir beim Verstehen leichterfallen.
Was ist den beim GalileoComputing Openbook nicht gut?
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

1. Yupp, hier: http://tutorial.pocoo.org/classes.html
2. Sieh dir mal BlackJack Website an, darauf findest du einige Punkte
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Antworten