Seite 1 von 1

Code kürzen?

Verfasst: Dienstag 28. Februar 2023, 06:18
von Wired1.0.
Hallo zusammen, ich bin gerade dabei eine art mini-Game als Übung zu schreiben, und wollte mal nachfragen, ob es Möglichkeiten gibt diesen Code noch weiter zu kürzen. (Ich habe bei ca. 170 Zeilen Code angefangen zu shorten und bin jetzt bei ca 100)
Ein User in einem Discord-Chanel meinte zu mir man könne ihn locker unter die Hälfte der Zeilen Code schreiben aber ich habe absolut keine Ahnung wie ich da jetzt noch was weglassen könnte... Evtl fällt euch ja noch was ein. :)
Ps: Es geht darum, dass der Spieler eine Zahl erraten muss, welche vom Computer vorgegeben wird.

Code: Alles auswählen

import random



def error_message():
    print("Keine gültige Eingabe! Bitte versuche es erneut\n")


def add_player():
    a = input("Bitte Namen des Spielers eingeben:\n")
    return a


class Variables:
    def __init__(self):
        self.players = []
        self.extra_player_count = 0
        self.all_numbers = []
        self.counter = 0
        self.value_player = self.extra_player_count + 2
        self.value_numbers = self.value_player * 10
        self.total_trys = self.value_player * 3
        self.run = True
        self.zahl = 0
        self.value_numbers = self.value_player * 10
        self.pin = random.randint(1, self.value_numbers)

    def false(self):
        self.run = False
        return self.run


user_options = Variables()
 

def player_options():
    while True:
        print("*** Willkommen zum Zahlenrätsel-Spiel! ***\nFür jeden Spieler werden die Zahlen um 10 erweitert.\n")
        print("Spieler 1: "), user_options.players.append(add_player())
        print("Spieler 2: "), user_options.players.append(add_player())
        print(user_options.players)
        add_more_players = input("Möchten Sie noch mehr Spieler hinzufügen?\nY/N:\n")
        try:
            add_more_players = str(add_more_players)
        except ValueError:
            error_message()
        if add_more_players == "y" or add_more_players == "Y":
            while True:
                user_options.extra_player_count = input("Wie viele Spieler möchtest du hinzufügen?(max. 2)\n")
                try:
                    user_options.extra_player_count = int(user_options.extra_player_count)
                except ValueError:
                    error_message()
                    continue
                if user_options.extra_player_count == 1 or user_options.extra_player_count == 2:
                    print("Spieler 3: "), user_options.players.append(add_player())
                    if user_options.extra_player_count == 2:
                        print("Spieler 4: "), user_options.players.append(add_player())
                elif user_options.extra_player_count >= 3:
                    error_message()
        elif add_more_players == "n" or add_more_players == "N":
            break
        else:
            error_message()


def int_game():
    user_options.extra_player_count = len(user_options.players)
    print(user_options.pin)
    print(len(user_options.players))
    if user_options.counter == user_options.total_trys - len(user_options.players):
        print("Achtung! Letzter Versuch für alle Spieler.")
    elif user_options.counter == user_options.total_trys:
        print("Keine Versuche mehr!")
        user_options.false()
    while user_options.run:
        user_options.zahl = input("Spieler " + user_options.players[0] + " Eingabe:\n")
        try:
            user_options.zahl = int(user_options.zahl)
        except ValueError:
            error_message()
            continue
        if user_options.zahl in user_options.all_numbers:
            error_message()
        if user_options.zahl == user_options.pin:
            print("Glückwunsch, Spieler " + user_options.players[0] + " hat gewonnen!")
            user_options.false()
        elif user_options.zahl < user_options.pin:
            print("zu klein")
        elif user_options.zahl > user_options.pin:
             print("zu groß")
        else:
            error_message()
        user_options.all_numbers.append(user_options.zahl)
        user_options.players.append(user_options.players.pop(0))
        user_options.counter += 1


def main():
    player_options()
    while user_options.run:
        int_game()


main()

Re: Code kürzen?

Verfasst: Dienstag 28. Februar 2023, 10:04
von __blackjack__
Vor dem kürzen sollte man es erst einmal ohne globale Variablen schreiben. Das `Variables`-Objekt ist falsch. Nur weil man alle globalen Variablen in ein Objekt steckt und deshalb das ``global`` Schlüsselwort nicht mehr im Programm stehen hat, heisst das ja nicht, das man keine globalen Variablen mehr hat.

Da stecken auch Attribute drin, die dort überhaupt nicht drin stecken müssten, selbst wenn man mit globalen Variablen arbeiten würde.

Man erstellt keine Tupel mit denen nichts gemacht wird, nur um zwei Ausdrücke in eine Zeile schreiben zu können. Falls das Deine Idee von Code kürzen ist, dann ist das eine sehr schlechte Idee. Code kürzen macht Sinn wenn er dadurch einfacher und lesbarer und verständlicher wird, nicht wenn es dadurch missverständlich wird. Wenn eine Zeile mit ``print`` beginnt und einer schliessenden Klammer endet, wird jeder Leser sehr überrascht sein, dass da irgendwo ein Komma in der Zeile ist, das den `print()`-Aufruf von einem ganz anderen Teilausdruck trennt, der gar nichts mit der Ausgabe zu tun hat.

Was gibt `input()` zurück? Warum denkst Du das müsste man in eine Zeichenkette umwandeln? Und in welchen Fall kann dabei ein `ValueError` auftreten?

Wenn man in einer ``while``-Schleife *vor* der Schleife etwas macht was in der Schleifenbedingung verwendet wird, und *in* der Schleife dann noch mal genau das gleiche macht, dann schreibt man besser eine ”Endlosschleife” die an der entsprechenden Stelle in der Schleife mit ``break`` abgebrochen wird, wenn die Abbruchbedingung eingetreten ist. Dann braucht man keinen Code doppelt zu schreiben.

Bei der Ja/Nein-Abfrage könnte man die Antwort entweder in Gross- oder in Kleinbuchstaben umwandeln, und könnte sich den Vergleich mit Gross- *und* Kleinbuchstaben ersparen.

An einen Namen/ein Attribut sollten nur Werte vom gleichen (Duck-)Typ gebunden werden. Nicht wie bei `extra_player_count` mal Zeichenketten und mal Zahlen.

Dort gibt es auch Prüfungen zu Eingaben und es wird auch eine Fehlermeldung ausgegeben, aber dann wird einfach so weitergemacht als wäre die Eingabe gar nicht falsch gewesen.

`extra_player_count` ist innerhalb des Spielverlaufs dann auch ein komischer bis falscher Name, denn da ist nichts extra — das wird am Anfang von `int_game()` immer auf die Anzahl der Spieler gesetzt. Was auch nicht so wirklich Sinn macht, denn es ist redundant zur Länge der Liste der Spieler.

Namen sollten keine kryptischen Abkürzungen enthalten. Was soll `int_game()` eigentlich bedeuten?

Funktions- und Methoden sind üblicherweise nach der Tätigkeit benannt, die sie durchführen, damit der Leser weiss was sie tun und man sie leichter von eher passiven Werten unterscheiden kann. Ausser `main()` sind alle Funktionen und Methoden nicht gut benannt.

`player_options` wäre ein guter Name für Spieleroptionen, nicht für eine Funktion die diese erfragt/erstellt. Die Funktion `player_options()` erstellt eine globale Variable `user_options` vom Typ `Variables`. Das diese drei Namen zusammengehören ist nicht leicht ersichtlich ohne den Code dazu zu lesen.

Der Name `add_player()` beschreibt zwar eine Tätigkeit — die Funktion macht das aber gar nicht. Die fügt keinen Spieler hinzu.

Man muss auch nicht jedes kleine Zwischenergebnis an einen Namen binden.

Methoden geben üblicherweise ein Ergebnis zurück *oder* verändern den Zustand des Objekts. Das ein Teilzustand geändert *und* zurückgegeben wird, ist eher selten sinnvoll, insbesondere dann wenn dieser Teilzustand öffentlich ist, und auch einfach nach der Änderung abgefragt werden könnte. Der Rückgabewert von der `false()`-Methode (wirklich schlechter Name) wird auch überhaupt gar nicht verwendet im Programm.

Von ``continue``, vor allem relativ weit vom Anfang einer Schleife, würde ich abraten. Es macht Code nur selten verständlicher einen unbedingten Sprung den man nicht an der Einrückung erkennen kann, zu verwenden. Es wird dadurch auch schwieriger Code hinzuzufügen der am Ende von *jedem* Schleifendurchlauf ausgeführt wird und das herausziehen von Code aus der Schleife in eine eigene Funktion oder Methode macht Probleme. ``try``/``except`` kennt auch einen ``else``-Zweig.