Klassen, Funktionen - Tipps und Kritik benötigt

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.
Sirius3
User
Beiträge: 18216
Registriert: Sonntag 21. Oktober 2012, 17:20

@CrisBee: jetzt würde ich noch eine __str__-Methode hinzufügen:

Code: Alles auswählen

class Character:
    [...]
    def __str__(self):
        return "%s %s %s %s" % (self.name, self.health, self.strength, self.xp)

print(player)
Benutzeravatar
CrisBee
User
Beiträge: 61
Registriert: Mittwoch 2. Oktober 2013, 10:45
Wohnort: Bielefeld
Kontaktdaten:

Krass...cool! Ich weiß zwar nicht, was die doppelten Unterstriche machen, aber scheinbar sagen sie "mache DAS, wenn mein Objekt ge-print-et wird"! :D Danke! :)
Das Reallife ist nur etwas für Leute, die keine Freunde im Internet haben! :P
Meine Fotografie: http://www.cutefeet.de
BlackJack

@CrisBee: Die Methode __str__() wird aufgerufen wenn `str()` mit so einem Objekt aufgerufen wird. Und das macht ``print`` intern. Es gibt noch mehr solcher ”magischer Methoden”: Special method names.
Benutzeravatar
CrisBee
User
Beiträge: 61
Registriert: Mittwoch 2. Oktober 2013, 10:45
Wohnort: Bielefeld
Kontaktdaten:

Kam erst jetzt wieder zum Quelltext-Posten. Viel getan hat sich noch nicht. Bin mit der Game Klasse nicht zufrieden...der nächste Schritt für mich wäre eigentlich, dass der User interagieren können soll. Sprich ich muss es rundenbasiert gestalten. Eine Funktion turn() für den Spieler, der an der Reihe ist. Dafür dann eine Unterscheidung zwischen menschlich und computergesteuert, damit beim einen ein input kommt und der andere simuliert wird. Traue mich da nicht ran! :D

Code: Alles auswählen

#!/usr/bin/env python

from random import randint

class Game:
    def __init__(self):
        pass

    def game_loop(self, player, enemy):
        status = ""
        round = 1
        while player.health > 0 and enemy.health > 0:
            print("------------------")
            print("|....Round %s....|" % round)
            round += 1
            print("------------------")
            print(player)
            print(enemy)
            
            self.fight(player, enemy)
            if enemy.health <= 0:
                status = "You win!"
                player.xp += enemy.xp
                break
            self.fight(enemy, player)
            if player.health <=0:
                status = "You lose!"
                break
            
        print(player)
        print(enemy)
        print(status)
            
    def fight(self, active, opponent):
        print("%s attacks %s" %(active.name, opponent.name))
        hp = active.attack(opponent)
        print("%s hp removed..." % hp)

class Character:
    def __init__(self, name, health, strength, xp):
        self.name = name
        self.health = health
        self.strength = strength
        self.xp = xp
        
    def __str__(self):
        return "%s %s %s %s" % (self.name, self.health, self.strength, self.xp)
        
    def attack(self, opponent):
        foo = randint((int(self.strength)/2), self.strength)
        opponent.health -= foo
        return foo

class Player(Character):
    pass
     
class Enemy(Character):
    pass

def main():
    player1 = Player("Christopher", 100, 15, 10)
    player2 = Enemy("Dominika", 100, 15, 10)
    game = Game()
    game.game_loop(player1, player2)

if __name__ == "__main__":
    main()
Das Reallife ist nur etwas für Leute, die keine Freunde im Internet haben! :P
Meine Fotografie: http://www.cutefeet.de
Benutzeravatar
snafu
User
Beiträge: 6831
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

`Game()` als Klasse ist vollkommen überflüssig. Das merkt man unter anderem daran, dass du keine `__init__()` benötigst. Übrigens bewirkt das `pass` in der `__init__()` genau so viel als wenn du die Methode gleich weg lässt.

Ich würde `game_loop()` und `fight()` einfach als normale Funktionen schreiben.

Oder du schreibst es so um, dass `player` und `enemy` bereits in der `__init__()` übergeben werden und machst dann die beiden besagten Methoden parameterlos. Sie würden stattdessen dann auf `self.player` und `self.enemy` zugreifen. Dann hätte die Klasse einen Sinn.
Benutzeravatar
CrisBee
User
Beiträge: 61
Registriert: Mittwoch 2. Oktober 2013, 10:45
Wohnort: Bielefeld
Kontaktdaten:

Mir wurde kürzlich halt noch gesagt, dass so eine Game Klasse Sinn machen würde, da dort der Loop reinkommt. Wo soll ich den game_loop() denn sonst platzieren?
Eine __init__ ist der Klasse Game schnell hinzugefügt bzw. eine "Aufgabe" für den Konstruktor! :P
Das Reallife ist nur etwas für Leute, die keine Freunde im Internet haben! :P
Meine Fotografie: http://www.cutefeet.de
Benutzeravatar
snafu
User
Beiträge: 6831
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

CrisBee hat geschrieben:Mir wurde kürzlich halt noch gesagt, dass so eine Game Klasse Sinn machen würde, da dort der Loop reinkommt.
Das halte ich für eine sehr fragwürdige Begründung.
CrisBee hat geschrieben:Wo soll ich den game_loop() denn sonst platzieren?
Auf Modulebene als Funktion wäre wohl die naheliegendste Möglichkeit. :)
CrisBee hat geschrieben:Eine __init__ ist der Klasse Game schnell hinzugefügt bzw. eine "Aufgabe" für den Konstruktor! :P
Irgendwas in den Konstruktor schreiben, nur damit er Inhalt hat, oder wie...?

Aber ich hatte ja noch etwas dazu editiert (letzter Absatz), was beschreibt wie du die Klasse mit Instanzattributen versehen kannst.
Benutzeravatar
CrisBee
User
Beiträge: 61
Registriert: Mittwoch 2. Oktober 2013, 10:45
Wohnort: Bielefeld
Kontaktdaten:

Hm...so gehen die Meinungen wieder auseinander. Ich hatte es mit der Zeit so verstanden, dass Funktionen auf Modulebene nicht sooo erwünscht sind. Habe es wahrscheinlich falsch verstanden.
Deinen Edit hatte ich nicht gesehen, sorry. Habe es jetzt gelesen. Klingt nicht schlecht, werde das auf jeden Fall mal ausprobieren, nur um es mal gemacht zu haben. So lernt man wieder was neues!^^

Danke @snafu!
Das Reallife ist nur etwas für Leute, die keine Freunde im Internet haben! :P
Meine Fotografie: http://www.cutefeet.de
Benutzeravatar
MagBen
User
Beiträge: 799
Registriert: Freitag 6. Juni 2014, 05:56
Wohnort: Bremen
Kontaktdaten:

Schau Dir mal Deine main-Funktion an, Du erzeugst die Player vor dem Game. Meiner Meinung nach sind die Player Teil des Games. Die Endlosschleife könnte z.B. immer auf Konsolen-Input warten, der Benutzer gibt da Buchstabenkürzel ein, was er machen möchte und die Klasse Game macht das dann in der Endlosschleife, gibt dem Benutzer den aktuellen Status aus und wartet auf den nächsten Input.
a fool with a tool is still a fool, www.magben.de, YouTube
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Ich persönlich sehe in der Vererbung auch noch ein (unnötiges!) Problem. Was unterscheidet denn den ``Player`` von einem ``Enemy``? (Aktuell ja durch nichts, wie man anhand des Codes sieht!)

Letztlich geht es Dir dabei ja nicht um Typen (also unterschiedliche Klasssen), sondern unterschiedliches Verhalten. Und das steht in der "hat ein"-Beziehung und damit Komposition und nicht in einer "ist ein"-Beziehung. Ob eine Entität nun ein "Gegner" ist, kommt doch schlicht auf den Standpunkt an ;-) Daher empfinde ich einen Typen dieses Namens in diesem Kontext eher fragwürdig.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
CrisBee
User
Beiträge: 61
Registriert: Mittwoch 2. Oktober 2013, 10:45
Wohnort: Bielefeld
Kontaktdaten:

Mir ging es bei der Unterscheidung darum, dass später der Player ein menschlicher Spieler ist und der Enemy ein computergesteuerter. Außerdem sollte ein Spieler keine XP abgeben, ein Enemy aber schon.
Das Reallife ist nur etwas für Leute, die keine Freunde im Internet haben! :P
Meine Fotografie: http://www.cutefeet.de
Benutzeravatar
sparrow
User
Beiträge: 4503
Registriert: Freitag 17. April 2009, 10:28

Aber der Spieler hat XP, die erhöht werden, wenn er ein Monster killt, oder? ;)
Benutzeravatar
CrisBee
User
Beiträge: 61
Registriert: Mittwoch 2. Oktober 2013, 10:45
Wohnort: Bielefeld
Kontaktdaten:

Hmpf...wohl wahr... XD Ach Menno! :P

Eigentlich fing das ja alles an um ein bisschen mit Vererbung rumzudameln! *g* Ich überdenke das nochmal und modelliere es dann soweit wie ich kann eigenständig wieder um. Vielen lieben Dank für eure geduldige Hilfe! :)
Das Reallife ist nur etwas für Leute, die keine Freunde im Internet haben! :P
Meine Fotografie: http://www.cutefeet.de
Benutzeravatar
sparrow
User
Beiträge: 4503
Registriert: Freitag 17. April 2009, 10:28

Ich bin noch immer für den Net-Hack-Klon. :)
BlackJack

@CrisBee: Ich denke sowohl die `Game`-Klasse in der gezeigten als auch das erben ohne die Datentypen dann tatsächlich zu spezialisieren haben gezeigt das man nichts auf ”Vorrat” machen sollte das man tatsächlich noch gar nicht benötigt. Das macht nur den Code komplexer ohne tatsächlich irgendetwas zu bringen.

@MagBen: Bestandteile (Spieler) vor dem Objekt das aus denen zusammengesetzt wird (Spiel) zu erzeugen und die dann zu übergeben hat allerdings den Vorteil das man sowohl zum automatisierten Testen als auch im realen Programm leichter Variationen übergeben kann. Also Mock-Objekte oder Computerspieler mit einer speziellen KI. Man könnte auch einfach verschiedene KIs gegeneinander spielen lassen.
Benutzeravatar
MagBen
User
Beiträge: 799
Registriert: Freitag 6. Juni 2014, 05:56
Wohnort: Bremen
Kontaktdaten:

BlackJack hat geschrieben:Bestandteile (Spieler) vor dem Objekt das aus denen zusammengesetzt wird (Spiel) zu erzeugen und die dann zu übergeben hat allerdings den Vorteil das man sowohl zum automatisierten Testen als auch im realen Programm leichter Variationen übergeben kann. Also Mock-Objekte oder Computerspieler mit einer speziellen KI. Man könnte auch einfach verschiedene KIs gegeneinander spielen lassen.
Wenn es aber erst vom Benutzer-Input abhängt, wie der Charakter aussieht, welche und wieviele Gegenspieler es gibt, die Gegenspieler erst nach und nach entstehen und zum Game noch Gänge, Abzweigungen und Gegenstände hinzukommen, soll all das dann auch übergeben werden?
a fool with a tool is still a fool, www.magben.de, YouTube
BlackJack

@MagBen: Jain, dann nicht an die `__init__()` sondern später setzen. Ich gehe dabei davon aus das `Game` Geschäftslogik ist und keinerlei direkte Benutzerinteraktion enthält.
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

sparrow hat geschrieben:Aber der Spieler hat XP, die erhöht werden, wenn er ein Monster killt, oder? ;)
Gibt auch Spiele wo NPC Gegner auch XP gewinnen oder zumindest ein Level aufsteigen können wie z.B. Shadow of Mordor.

An der Game Klasse würde ich mich gar nicht stören. Der gezeigte Code stellt ja nur ein Snapshot dar und muss im Kontext eines Entwicklungsprozesses gesehen werden. So wie das Spiel komplexer wird, dürfte auch die Game Klasse schnell an Komplexität und State gewinnen und sich somit rechtfertigen.
Antworten