Anfängerfrage: "Dynamisches" Objekt

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
angwedh
User
Beiträge: 20
Registriert: Dienstag 16. März 2010, 08:04

Guten Morgen zusammen
Und schon wieder habe ich eine Frage. Wieder über mein kleines "Lern- und Testprogramm". Ich spiele ab und zu das Pen&Paper-Rollenspiel "Das Schwarze Auge". Das Programm, welches ich so langsam schreibe, verändere, verbessere und dabei Python lerne soll mich als Spielleiter bei der Verwaltung der NPCs helfen und bei den Kampfsituationen die Reihenfolge auflisten.
Dafür habe ich eine Klasse "Character" geschrieben, die alle Eigenschaften eines NPCs beinhaltet. Das Komplexe von DSA ist, dass enorm viele verschiedene Ereignisse diese Eigenschaften veränderen und meistens nur so und so lange. Mit andern Worte, diese Klasse bzw. die Instanzen davon müssen enorm flexibel und dynamisch sein.

Ich habe einen Ansatz gefunden, wie ich dies erreichen könnte, weis aber nicht ob dies die beste Variante ist, weswegen ich diesen Thread eröffnet habe. Ich würde nun die Eigenschaften als Attribute speichern und gleichzeitig ein Dict erstellen, in welchem ich zu jedem Attribut die Mali/Boni eintrage und dann die effektiven Eigenschaften über eine Methode ausgebe. Dann könnte ich wenn das Attribut X sich temporär um -2 verändert ins Dict bei X den Wert um -2 addieren. Die Methode addiert dann einfach das Attribut mit dem Wert im Dict mit dem Schlüssel des Attributes. (Btw. gibt es eine Möglichkeit die Variabelnamen als string auszugeben, so dass ich etwas im Stil von dict["variabelname als string"] = variable habe?)

Gleichzeitig würde ich ein zweites solches Dict anlegen, welches dann die Zeitlänge der Mali/Boni beinhaltet. Dies würde dann nach jeder Runde -1 gezählt wenn der Eintrag nicht schon 0 ist.

Da es vorkommen kann, dass verschiedene Mali/Boni auf das gleiche Attribut wirkt, jedoch nicht gleich lange, würde ich die Werte im Dict zusätzlich in einer Liste speichern.

Wie ihr seht, würde dieser Ansatz wohl gehen, jedoch ist er etwas umständlich. Gibt es da eine elegantere Variante, die sich einem Anfänger wie mir entgeht?

Liebe Grüsse
angwedh
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Vorschlag:
Du modelierst die Charakter als Klasse(hast du ja schon) und stellst 2 Methoden bereit: `add_temporary_mod` und `add_permanent_mod`.
Intern kannst du je ein Dictionary von Listen benutzen.
Fuer die Charakterattribute wuerde ich properties benutzen, die aus den beiden Dictionaries den aktuellen wert berechnen.

Ein Problem ueber das du noch nachdenken musst: Wie wirst du die Modi wieder los. In den beiden Methoden koenntest du ja Metainformationen generieren oder als Argument an sie uebergeben, ich glaube aber, dass deine Datenstruktur dann nicht so einfach bleiben wird.
Pekh
User
Beiträge: 482
Registriert: Donnerstag 22. Mai 2008, 09:09

Aufbauend auf dem oben beschriebenen: Man hat für die temporären Veränderungen zwei Möglichkeiten:

1) Einen Timer mitlaufen lassen, der die Modifizierung nach Ablauf automatisch zurücknimmt.
2) Als "Meta-Information" die Ablaufzeit mit speichern und dann beim nächsten Zugriff prüfen, ob die Modifizierung überhaupt noch Gültigkeit hat. Das ist die einfachere und sparsamere Variante. Da du beim Rollenspielen in der Regel keine "Echtzeit" brauchst, ist sie auch völlig ausreichend. Und sie kommt ohne parallel laufenden Thread aus.
angwedh
User
Beiträge: 20
Registriert: Dienstag 16. März 2010, 08:04

Was die Geschwindigkeit im Antworten ist, seit ihr echt super! Die Antwort wird sicher auch super sein, leider habe ich bis jetz noch nichts von properties gehört, weswegen ich dies zuerst begreiffen muss, bis ich genau verstehe, was ihr da Vorschlägt :P

Danke für die Antworten!
grüsse
Pekh
User
Beiträge: 482
Registriert: Donnerstag 22. Mai 2008, 09:09

Properties sind, kurz gesagt, Methoden, die sich den Anschein von Attributen geben. Du glaubst also, nur eine einfache Zuweisung an ein Attribut vorzunehmen, tatsächlich findet aber ein Methodenaufruf mit einer ganzen Anzahl von Berechnungen statt.

Properties sind ganz praktisch, wenn man im Nachhinein feststellt, daß es mit einer einfachen Zuweisung doch nicht getan ist. Dann kann man ohne die Schnittstelle ändern zu müssen das Verhalten der Klasse bzw. ihrer Exemplare verändern. Manchmal ist es auch einfach nett, wenn eine Eigenschaft schnittstellenmäßig nicht aus dem Rahmen fällt, nur weil sie etwas komplexer ist, als die anderen. Programmierer sind ja immer ganz dankbar, wenn es bei den Bezeichnern von Attributen und Methoden eine erkennbare Systematik gibt, so daß sie nicht jedes Mal nachschauen müssen, wie dieser konkrete Befehl sich denn nun schreibt, sondern "raten" können.
BlackJack

Ein schnell zusammengehackter Vorschlag: http://paste.pocoo.org/show/210961/

Als Modifikator kann man jedes beliebige aufrufbare Objekt angeben, welches den zu verändernden Wert als Argument erwartet und den veränderten Wert zurückgibt. Sollte eine Funktion nicht ausreichen, kann das natürlich auch eine Methode sein, oder ein Objekt, das `__call__()` entsprechend implementiert.

Mein Modell geht davon aus, dass nach jeder Runde die `tick()`-Methode auf dem Charakter aufgerufen wird, um den Zustand zu aktualisieren.
Pekh
User
Beiträge: 482
Registriert: Donnerstag 22. Mai 2008, 09:09

BlackJack hat geschrieben:
Mein Modell geht davon aus, dass nach jeder Runde die `tick()`-Methode auf dem Charakter aufgerufen wird, um den Zustand zu aktualisieren.
"Tick" oder "Kampfrunde" wäre eigentlich eine schöne Klassenvariable. Alle Charaktere "ticken" ja synchron. Evtl. könnte man diese Klassenvariable ja über ein Mixin an alle Klassen weiterreichen, die's interessiert.
angwedh
User
Beiträge: 20
Registriert: Dienstag 16. März 2010, 08:04

Ihr seit einfach super! Habe nun leider Vorlesung und komme erst später wieder zum Programmieren und Beispiel analysieren.

(Ich habe das Gefühl, dass ich nicht der einzige DSA-Spieler hier bin...)
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

BlackJack hat geschrieben:Ein schnell zusammengehackter Vorschlag: http://paste.pocoo.org/show/210961/
Nice, ich hätte das auch so gemacht, nur statt ``Property`` die Klasse ``Modification`` genannt.

@OP: Bist du nicht, auch wenn meine DSA-Zeit nun schon etwas her ist.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
mkesper
User
Beiträge: 919
Registriert: Montag 20. November 2006, 15:48
Wohnort: formerly known as mkallas
Kontaktdaten:

Sind alle diese temporären Modifier so langweilig, dass bei jedem Tick eins abgezogen wird? Ansonsten könnte man da ja noch eine Formel einbauen. :)
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Wenn es gelingt, jede Änderung an einem Attribut durch eine umkehrbare Funktion zu beschreiben (also z.B. increment vs. decrement), würde ich anders vorgehen. Sagen wir z.B., ein Charakter hat die Stärke 16. Nun wird er verzaubert und seine Stärke soll für 3 Runden auf 18 (also um +2) steigen: http://paste.pocoo.org/show/211469/

Gibt es jedoch ein Maximum, d.h. ergänzen sich mehrere Effekte nicht, sondern es gilt nur einer, versagt mein einfaches Verfahren leider.

Stefan

PS: Statt sich mit einem Programm für ein kompliziertes Rollenspiel zu quälen, wie wäre es mit einem einfacheren Rollenspielsystem? Ich erwähne mal Savage Worlds als Alternative ;) Nicht dass es da jetzt einfach wäre, ein Verwaltungsprogramm zu schreiben, aber ich denke, es wäre zumindest einfacher als für DSA...
angwedh
User
Beiträge: 20
Registriert: Dienstag 16. März 2010, 08:04

Guten tach zusammen
Ich habe nun den Code analysiert und denke dass ich ihn in etwa verstehe, will diese Technik noch besser verstehen, weswegen ich wohl noch ein paar mal schreibe;-) Ich finde diese Lösung genia!
Was ich noch nicht ganz verstehe ist, wieso in de Klasse Character über den Key im dict den Wert der Eigenschaft erreichbar ist im Stil des Beispiels:
hero.strength.effective_value
und nicht durch
hero.properties[strength].effective_value
Noch den Code auf den ich mich beziehe:

Code: Alles auswählen

s e l f . p r o p e r t i e s = { ' s t r e n g t h ' : P r o p e r t y ( 1 0 )
Nun noch ein paar weitere Fragen:
Es gibt ja noch Boni und Mali, die nicht nach einer gewissen Zeit verschwinden wie Rüstungsbehinderung, Wunden oder Talente. Würdet ihr nun da noch eine zweite Modifikatorliste erstellen, in der man etwas mühsamer die Funktionen löschen muss wenn die, z.B. Wunde geheilt wird?

Es gibt ja auch Ereignisse, die mehr als nur einen Wert verãndert, auch wieder z.B. Wunden, Ich hätte hier nun Funktionen definiert in denen weitere Funktionen auf die einzelnen Eigenschaften losgehen, oder wie würdet ihr dies pythonlike lösen?

Da ich eh eine Klasse Fight habe in der dann die jeweiligen Charakterobjekte gespeichert sind und die Runden, Iniphasen überwacht, kann diese tick-methode von diesem fightobjekt ausgelöst werden...
@stefan: muss den code zuerst wieder analysieren, das geht bei mir etwas länger. Wieso dsa, ich habe etwas ähnliches schon für pathfinder angefange aber gemerkt, dass dort ein solches programm nich benötigt wird, da kämpfe viel einfacher sind, da habe ich mich für dsa entschieden, was sicher nicht einfach ist, aber es geht mir vor allem um das Lernen von Python...
Grüsse
angwedh
BlackJack

Die Frage verstehe ich nicht so recht!? Du kannst natürlich auch ``hero.properties['strength'].effective_value`` verwenden. Oder war die Frage warum man auch ``hero.strength.effektive_value`` schreiben kann? Wenn ein Attribut nicht auf einem Objekt gefunden wird, dann wird die Funktion `__getattr__()` mit dem Namen des Attributs aufgerufen.
angwedh
User
Beiträge: 20
Registriert: Dienstag 16. März 2010, 08:04

guten morgen
Dies war tatsächlich eine meiner Fragen, war etwas umständlich geschrieben. Ich habe die __getattr__() übersehen, tut mir Leid!


Liebe Grüsse
angwedh
When you have eliminated the impossible, whatever remains, however improbable, must be the truth. [Arthur Conan Doyle]
>>> print(angwedh)
'raw recruit'
>>>
angwedh
User
Beiträge: 20
Registriert: Dienstag 16. März 2010, 08:04

Hallo Zusammen,
Habe nochmals überlegt, was es für Modifikatortypen gibt:
- Solche die nach jeder Runde ab-/zunehmen
- Solche, die erst nach einem Ereigniss wieder verschwinden
- Und übergreiffend, solche, die nur bis ein Maximum gehen, sprich sich nicht addieren.

Der erste Typ habt ihr mir ja bereits gelöst, dies funktioniert auch. Beim zweiten beisse ich mir bereits wieder die Zähne aus. Ich habe nun noch eine Liste erstellt, synonym zu der modificators - Liste, die die "nicht-so-schnell-verschwindenden" Modifikatoren speichert. Der Punkt, der bei mir noch nicht gelöst ist, ist, wie finde
ich die Funktion, die gelöscht werden sollte?

Die Variante mit dem Maximum wird dann mein letztes Problem sein, dass ich noch nicht genau gelöst habe, bzw. noch gar nicht angegangen bin.

grüsse
angwedh
When you have eliminated the impossible, whatever remains, however improbable, must be the truth. [Arthur Conan Doyle]
>>> print(angwedh)
'raw recruit'
>>>
BlackJack

@angwedh: Du müsstest die Modifikatoren die von Ereignissen abhängen halt nicht in einer Liste speichern, sondern zum Beispiel in einem Dictionary, das ein Ereignis auf die Funktion abbildet.
Antworten