Textadventure - Problem mit lokalen/globalen Variablen

Code-Stücke können hier veröffentlicht werden.
Antworten
liscode
User
Beiträge: 3
Registriert: Mittwoch 23. Dezember 2020, 12:58

Hallo,
Ganz am Anfang von meinem Code habe ich 2 Variablen so definiert:
hpFrau = 10.0
hpMain = 15.0
um sie später in einer Funktion verwenden zu können. Allerdings heißt es sobald ich bei der Funktion angekommen bin immer: local variable referenced before assignment
Ich verstehe jetzt nicht, warum die Funktion nicht auf die beiden bereits definierten Variablen zugreifen kann. Bestimmt ist die Lösung ganz leicht, aber ich übersehe da wohl einfach etwas... Könnte mir da jemand weiterhelfen?
Vielen Dank,
Lisa

Code: Alles auswählen

 
 def angriffMain():
  while hpMain > 9:
    print("Jetzt bist du dran! Du hast zwei Angriffe zur Auswahl: 'faustschlag' und 'treten'.")
    command = pick_command(["treten", "faustschlag"])
    if command == "treten":
      hpFrau = hpFrau - tretschaden
      print("Sehr gut! Du verpasst deiner Gegnerin einen ordentlichen Tritt! Sie hat noch " + str(hpFrau) + " Leben")
    elif command == "faustschlag":
      hpFrau = hpFrau - faustschaden
      print("Sehr gut! Du hast landest einen heftigen Schlag! Sie hat noch " + str(hpFrau) + " Leben.")
    print("Sie greift wieder an!")
    ausweichen()
  print("Du wirst langsam erschöpft... Aber was ist das? Du siehst in einer Ecke der Hütte etwas schimmern! Könnte das das legendäre Schwert sein? Drücke Enter um danach zu greifen!")
  command = input()
  ("Du greifst dir das Schwert und erledigst das Biest mit einem schwungvollen Hieb! Nachdem du wieder zu Atem gekommen bist, betrachtest du die Waffe. Du hältst tatsächlich Excalibur in Händen!")
  hpFrau = 0
Benutzeravatar
sparrow
User
Beiträge: 4183
Registriert: Freitag 17. April 2009, 10:28

Die Lösung ist: Benutze keine gloablen Variablen.

Funktionen bekommen alle Variablen, die sie zum Arbeiten brauchen, als Parameter und geben ein Ergebnis mit "return" zurück.

Eingerückt wird in Python nach Konvention mit 4 Leerzeichen.
Benutzeravatar
__blackjack__
User
Beiträge: 13067
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@liscode: Zusätzliche Anmerkungen zum Quelltext:

Eingerückt wird mit vier Leerzeichen pro Ebene.

Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (MixedCase).

Es wiederholen sich Texte die "faustschlag" im Quelltext. Das ist fehleranfällig bei Änderungen, weil man immer alle Stellen an denen die Texte vorkommen gleichartig ändern muss.

Auch Code sollte sich möglichst nicht an verschiedenen Stellen wiederholen. Gemeinsamkeiten die am Anfang oder am Ende aller Zweige eines ``if``-Kostrukts stehen, sollten nur *einmal* vor beziehungsweise nach diesem Konstrukt stehen.

Wenn man eine ``if``/``elif``-Kaskade hat, ohne ein ``else``, sollte man sich Gedanken um das ``else`` machen und falls der Fall nie eintreten kann, das auch entsprechend absichern, dass es nicht unbemerkt durchrutscht falls der Fall dann doch mal eintritt.

Das mit der Sprache sollte einheitlich sein. Entweder Englisch oder Deutsch, nicht ein wilder Mix, teilweise sogar *innerhalb* von Namen. Keine kryptischen Abkürzungen. Wenn die Frau bei Hewlett-Packard arbeitet, dann sollte man das nicht aus dem "hp" erraten müssen.

Texte und Werte mit ``+`` und `str()` zusammenstückeln ist eher BASIC denn Python. In Python gibt es dafür Zeichenkettenformatierung mit der `format()`-Methode und f-Zeichenkettenliterale.

Am Ende hast Du wohl ein `print()` vergessen, denn da steht einfach nur eine literale Zeichenkette in der vorletzen Zeile.

Zwischenstand (ungetestet):

Code: Alles auswählen

def fight_woman(player_hitpoints, woman_hitpoints):
    while player_hitpoints > 9:
        #
        # TODO Wiederholung der Angriffsarten als/in Texten beseitigen.
        #
        print(
            "Jetzt bist du dran! Du hast zwei Angriffe zur Auswahl:"
            " 'faustschlag' und 'treten'."
        )
        command = pick_command(["treten", "faustschlag"])
        if command == "treten":
            damage = KICK_DAMAGE
            text = "Du verpasst deiner Gegnerin einen ordentlichen Tritt!"
        elif command == "faustschlag":
            damage = FIST_DAMAGE
            text = "Du landest einen heftigen Schlag!"
        else:
            assert False, f"unerwartetes Kommando {command!r}"

        woman_hitpoints -= damage
        print(f"Sehr gut! {text}")
        print(f"Sie hat noch {woman_hitpoints} Leben.")

        print("Sie greift wieder an!")
        dodge_enemy()

    print(
        "Du wirst langsam erschöpft..."
        " Aber was ist das?"
        " Du siehst in einer Ecke der Hütte etwas schimmern!"
        " Könnte das das legendäre Schwert sein?"
        " Drücke Enter um danach zu greifen!"
    )
    input()
    print(
        "Du greifst dir das Schwert"
        " und erledigst das Biest mit einem schwungvollen Hieb!"
        " Nachdem du wieder zu Atem gekommen bist, betrachtest du die Waffe."
        " Du hältst tatsächlich Excalibur in Händen!"
    )
    return player_hitpoints, 0
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
liscode
User
Beiträge: 3
Registriert: Mittwoch 23. Dezember 2020, 12:58

sparrow hat geschrieben: Mittwoch 23. Dezember 2020, 13:34 Die Lösung ist: Benutze keine gloablen Variablen.

Funktionen bekommen alle Variablen, die sie zum Arbeiten brauchen, als Parameter und geben ein Ergebnis mit "return" zurück.

Eingerückt wird in Python nach Konvention mit 4 Leerzeichen.
Danke erstmal für die Antwort! Ich habe tatsächlich auch schon versucht, die Variablen direkt oben in der Funktion zu definieren. Bei erneutem Aufruf der Funktion wurde der Wert der Variable dann allerdings wieder auf diesen Wert gesetzt.
Also: def function blabla
hitpoints_main = 8
dann läuft die funktion durch, die hitpoints abzieht, aber wenn sie wieder gecallt wird, wird ja wieder hitpoints_main = 8 zuerst ausgeführt.
Also dafür bräuchte ich noch eine Lösung.
liscode
User
Beiträge: 3
Registriert: Mittwoch 23. Dezember 2020, 12:58

__blackjack__ hat geschrieben: Mittwoch 23. Dezember 2020, 15:19 @liscode: Zusätzliche Anmerkungen zum Quelltext:

Eingerückt wird mit vier Leerzeichen pro Ebene.

Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (MixedCase).

Es wiederholen sich Texte die "faustschlag" im Quelltext. Das ist fehleranfällig bei Änderungen, weil man immer alle Stellen an denen die Texte vorkommen gleichartig ändern muss.

Auch Code sollte sich möglichst nicht an verschiedenen Stellen wiederholen. Gemeinsamkeiten die am Anfang oder am Ende aller Zweige eines ``if``-Kostrukts stehen, sollten nur *einmal* vor beziehungsweise nach diesem Konstrukt stehen.

Wenn man eine ``if``/``elif``-Kaskade hat, ohne ein ``else``, sollte man sich Gedanken um das ``else`` machen und falls der Fall nie eintreten kann, das auch entsprechend absichern, dass es nicht unbemerkt durchrutscht falls der Fall dann doch mal eintritt.

Das mit der Sprache sollte einheitlich sein. Entweder Englisch oder Deutsch, nicht ein wilder Mix, teilweise sogar *innerhalb* von Namen. Keine kryptischen Abkürzungen. Wenn die Frau bei Hewlett-Packard arbeitet, dann sollte man das nicht aus dem "hp" erraten müssen.

Texte und Werte mit ``+`` und `str()` zusammenstückeln ist eher BASIC denn Python. In Python gibt es dafür Zeichenkettenformatierung mit der `format()`-Methode und f-Zeichenkettenliterale.

Am Ende hast Du wohl ein `print()` vergessen, denn da steht einfach nur eine literale Zeichenkette in der vorletzen Zeile.

Zwischenstand (ungetestet):

Code: Alles auswählen

def fight_woman(player_hitpoints, woman_hitpoints):
    while player_hitpoints > 9:
        #
        # TODO Wiederholung der Angriffsarten als/in Texten beseitigen.
        #
        print(
            "Jetzt bist du dran! Du hast zwei Angriffe zur Auswahl:"
            " 'faustschlag' und 'treten'."
        )
        command = pick_command(["treten", "faustschlag"])
        if command == "treten":
            damage = KICK_DAMAGE
            text = "Du verpasst deiner Gegnerin einen ordentlichen Tritt!"
        elif command == "faustschlag":
            damage = FIST_DAMAGE
            text = "Du landest einen heftigen Schlag!"
        else:
            assert False, f"unerwartetes Kommando {command!r}"

        woman_hitpoints -= damage
        print(f"Sehr gut! {text}")
        print(f"Sie hat noch {woman_hitpoints} Leben.")

        print("Sie greift wieder an!")
        dodge_enemy()

    print(
        "Du wirst langsam erschöpft..."
        " Aber was ist das?"
        " Du siehst in einer Ecke der Hütte etwas schimmern!"
        " Könnte das das legendäre Schwert sein?"
        " Drücke Enter um danach zu greifen!"
    )
    input()
    print(
        "Du greifst dir das Schwert"
        " und erledigst das Biest mit einem schwungvollen Hieb!"
        " Nachdem du wieder zu Atem gekommen bist, betrachtest du die Waffe."
        " Du hältst tatsächlich Excalibur in Händen!"
    )
    return player_hitpoints, 0
Vielen Dank auch für diese Tips und den überarbeiteten Code. Ich gehe grade echt noch relativ diletantisch an die Sache ran und orientiere mich an einem einzigen Einführungskurs, in dem zum Beispiel eben auch mit "+" und so Text zusammen gefügt wurde. Also sind diese ganzen Anfängerratschläge sehr hilfreich für mich :)
Benutzeravatar
__blackjack__
User
Beiträge: 13067
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@liscode: Die Lösung ist die Variablen nicht in der Funktion zu definieren sondern als Argument(e) zu übergeben und den (eventuell) geänderten Wert als Rückgabewert wieder an den Aufrufer zurück zu geben. Also das was sparrow ja schon genannt wurde und in meiner Funktion gemacht wird.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Antworten