Zwei Codes in einen Code zusammenfassen

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
annelie123
User
Beiträge: 1
Registriert: Montag 8. Dezember 2025, 12:49

Hallo zusammen,

wir brauchen Hilfe bei unserem Code. Wir wollen einmal den Code für einen Taschenrechner und den Code für ein Tic-Tac-Toe zusammenfassen und haben dies auch bereits versucht, was leider nicht funktioniert hat. Wir wissen schon ungefähr wo der Fehler liegt, sind uns aber nicht sicher wie wir ihn beheben können. Vielen Dank schonmal :)

Grüße

```
z=Taschenrechner
x=TicTacToe
print("Wähle eine der beiden Optionen:")
wahl=input("Taschenrechner 'z' oder TicTacToe 'x':")
while wahl not in ["z", "x"]:
wahl=input("Bitte 'z' für Taschenrechner oder 'x' für TicTacToe eingeben: ")

if i in range(z):

def Taschenrechner():
return

def addieren(a,b): # Angeben von Rechenzeichen, für leichteren Überblick
return a+b

def subtrahieren(a,b):
return a-b

def multiplizieren(a,b):
return a*b

def dividieren(a,b):
# Division durch 0 verhindern
if b==0:
return "Fehler: Division durch Null ist nicht erlaubt!"
return a / b

def zahl(text):
while True:
eingabe=input(text)
try:
return float(eingabe) # in Zahl umwandeln
except ValueError:
print("Bitte gib eine gültige Zahl ein!")

h=zahl("Gebe eine Zahl ein: ")
j=zahl("Gebe eine andere Zahl ein: ") # 1. und 2. Zahl für die Rechnung
operation=input("Gebe ein Rechenzeichen ein (+, -, *, /): ") # für die Rechnung

if operation=="+":
ergebnis=addieren(h,j)
elif operation=="-":
ergebnis=subtrahieren(h,j)
elif operation=="*":
ergebnis=multiplizieren(h,j)
elif operation=="/":
ergebnis=dividieren(h,j)
else:
ergebnis="?"

print("Das Ergebnis lautet:", ergebnis) # Ausgabe vom Ergebnis

if i in range(x):

def TicTacToe():
return # Angabe der Zahlencombos die im Tic-Tac-Toe gewinnen, basierend auf dem erstellten Spielfeld s.u
winning_combos=(
(0, 1, 2), (3, 4, 5), (6, 7, 8),
(0, 3, 6), (1, 4, 7), (2, 5, 8),
(0, 4, 8), (2, 4, 6))

def play(player):

print("\n", " | ".join(grid[:3]))
print("---+---+---")
print("", " | ".join(grid[3:6])) # Spielfeld für das Spiel
print("---+---+---")
print("", " | ".join(grid[6:]))

# Wiederholung vom Code
while True:
try:
cell = int(input(f"Gib eine Zahl für {player} ein: "))
if str(cell) not in grid: # Zum Eingeben von "X" und "O" im Spielfeld über hinterlegte Zahlen beim Aufbau
raise ValueError
grid[cell-1] = player
break
except ValueError:
print("Gib eine Zahl von einer freien Zelle ein.")

for combo in winning_combos:
if all(grid[cell]==player for cell in combo):
return combo # Damit Spiel beendet wird nach einem Gewinn und man nicht weitere Eingaben tätigen kann
return None

player1="X"
player2="O"
player=player1
grid=list("123456789") # Für die Eingabe in das oben erstellte Spielfeld

for i in range(9):
won=play(player)
if won:
print(f"Spieler {player} hat gewonnen!") # neun Züge bis zum Unentschieden, weil dann keine weiteren Züge möglich sind
break
player=player1 if player==player2 else player2
else:
print("Unentschieden")
```
Benutzeravatar
ThomasL
User
Beiträge: 1385
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Hallo annelie,

bitte benutze zum posten von Code den vollständigen Editor und dort den Button </> über dem Eingabefenster,
denn so ist der Code nicht lesbar da die Einrückungen fehlen.
Wäre schön wenn du/(ihr?) den Code nochmal posten würdet.
"Wir wissen schon ungefähr wo der Fehler liegt,"
Und dann beschreibe doch mal, wo ihr glaubt zu wissen wo der Fehler liegt und
wir versuchen dann euch auf den richtigen Weg zu bringen.
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Sirius3
User
Beiträge: 18332
Registriert: Sonntag 21. Oktober 2012, 17:20

Als erstes solltet Ihr ein Programm ordentlich schreiben.
Einrückungen sind wichtig in Python. Es gibt etliche Stellen im Programm an denen die Einrückungen nicht stimmen.
Weder `Taschenrechner` noch `TicTacToe` sind in den ersten beiden Zeilen definiert, und auch die Definition der Funktionen später ist nicht sinnvoll, da die Funktionen nichts machen.
Zudem sind die Variablennamen `x` und `z` schlecht, weil nicht sprechend.
`i` wird nirgends definiert und `x` oder `z` sind keine ganzen Zahlen, so dass der Aufruf von `range` nicht funktionieren kann.
Programmieren funktioniert nicht durch Raten.

Funktionen werden auf oberster Ebene definiert, nicht in if-Blöcken.
Ein ordentliches Programm besteht aus einem Hauptprogramm, das selbst eine Funktion ist.
Wenn man also eine Funktion `main_calculator` und eine Funktion `main_tictactoe` hat, dann ist es auch kein Problem beide Programme in einem zu kombinieren, weil man nur unterscheiden muß, welche von beiden `main`-Funktionen aufgerufen wird.
Das hat auch den positiven Nebeneffekt, dass man keine globalen Variablen hat, sondern z.B. grid auch als Argument an `play` übergibt.
Benutzeravatar
__blackjack__
User
Beiträge: 14250
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@annelie123: Anmerkungen zum Taschenrechnerteil:

Ergänzend zu Namen: Bei `h` und `j` ist auch nicht wirklich klar warum die so heissen. Wenn man generische Namen braucht, würde man eher bei `a` anfangen und mit `b` weiter machen. Wie bei den Funktionen, die dann die vier Rechenoperationen letztlich umsetzen. Da heissen die Argument ja `a` und `b`.

Funktionen werden üblicherweise nach Tätigkeiten benannt. Damit der Leser weiss was sie machen, und sie leichter von eher passiven Werten unterscheidbar sind. `zahl` wäre ein guter Name für allgemeine Zahl, wenn man keinen treffenderen Namen dafür hat, aber es ist kein guter Name für eine Funktion. Die Funktion würde besser `zahl_erfragen()` oder ähnlich heissen, damit man weiss was die tut.

Im `operator`-Modul gibt es Funktionen für die Operatoren. `addieren()`, `subtrahieren()`, und `multiplizieren()` muss man sich also gar nicht selbst schreiben, die gibt es schon. Wenn man die Sonderbehandlung in `dividieren()` nicht macht, gibt es auch da schon eine Funktion im `operator` für. Die Division durch 0 kann man auch durch die Behandlung der Entsprechenden Ausnahme lösen.

Bei den beiden Operanden wird solange nach einer Zahl gefragt, bis der Benutzer tatsächlich eine Zahl eingegeben hat. Bei der Operation wird stattdessen einfach ein "?" ausgegeben wenn der Benutzer etwas anderes als eines der Rechenzeichen eingegeben hat. Da wäre es benutzerfreundlicher auch solange die Frage zu wiederholen bis der Benutzer eine gültige Eingabe gemacht hat. Dann muss man bei einem Tippfehler an der Stelle nicht die beiden Operanden noch mal eingeben.

Es ist nicht gut Daten mehrfach zu wiederholen. Die Rechenzeichen stehen zwei mal im Programm. Da kann man sich vertippen und Fehler machen, beim schreiben des Programms, als auch bei späteren Änderungen/Erweiterungen. Da die Funktionen für die Operationen alle die gleiche Signatur haben, dass heisst alle zwei Operanden als Argumente haben und das Ergebnis der Operation als Rückgabewert, könnte man sich ein Wörterbuch erstellen, wo das Rechenzeichen auf die dazugehörige Funktion abgebildet wird. Dann lässt sich der Code so schreiben, dass die Rechenzeichen nur einmal im Quelltext, in diesem Wörterbuch stehen müssen.

Kommentare sollten dem Leser einen Mehrwert liefern. Faustregel: Man kommentiert nicht *was* der Code macht, denn das steht da ja bereits als Code, sondern warum er das so macht. Sofern das nicht offensichtlich ist. Offensichtlich ist in der Regel was in der Dokumentation der Sprache und der verwendeten Bibliotheken und Module steht. Zu kommentieren, dass ``print("Das Ergebnis lautet:", ergebnis)`` das Ergebnis ausgibt, ist beispielsweise komplett überflüssig.

Taschenrechner (ungetestet):

Code: Alles auswählen

#!/usr/bin/env python3
from operator import (
    add as addieren,
    mul as multiplizieren,
    sub as subtrahieren,
    truediv as dividieren,
)

OPERATOR_ZU_OPERATION = {
    "+": addieren,
    "-": subtrahieren,
    "*": multiplizieren,
    "/": dividieren,
}


def zahl_erfragen(eingabeaufforderungstext):
    while True:
        try:
            return float(input(eingabeaufforderungstext))
        except ValueError:
            print("Bitte gib eine gültige Zahl ein!")


def operation_erfragen(operator_zu_operation):
    operatoren_text = ", ".join(operator_zu_operation.keys())
    eingabeaufforderungstext = (
        f"Gebe ein Rechenzeichen ein ({operatoren_text}): "
    )
    while True:
        try:
            return operator_zu_operation[input(eingabeaufforderungstext)]
        except KeyError:
            print("Bitte gib ein gültiges Rechenzeichen ein!")


def main():
    a = zahl_erfragen("Gebe den ersten Operanden ein: ")
    b = zahl_erfragen("Gebe den zweiten Operanden ein: ")
    operation = operation_erfragen(OPERATOR_ZU_OPERATION)
    try:
        ergebnis = operation(a, b)
    except ZeroDivisionError:
        print("Fehler: Division durch Null ist nicht erlaubt!")
    else:
        print("Das Ergebnis lautet:", ergebnis)


if __name__ == "__main__":
    main()
Anmerkungen zum Tic-Tac-Toe:

Konstantennamen werden per Konvention KOMPLETT_GROSS geschrieben.

Wenn man einen Namen hat, den man aus syntaktischen Gründen braucht, dessen Wert aber keine Rolle spielt, dann verwendet man per Konvention den Namen `_`. Dann weiss der Leser, dass er diesen Namen nicht weiter beachten muss, und dass es Absicht ist, dass der Wert nicht verwendet wird. Das betrifft hier `i`.

Statt die 9 als literale Zahl für die Anzahl Schleifendurchläufe in den Quelltext zu schreiben, könnte man hier die Länge von `grid()` ermitteln. Dann kann man das beispielsweise von Tic-Tac-Toe zu „Vier gewinnt“ erweitern, ohne die Zeile noch einmal ändern zu müssen.

Der Rückgabewert von `play()` könnte einfacher sein. Statt `None` oder der Indexwerte von Gewinnerfeldern, könnte man auch nur False und True zurückgeben, denn der Aufrufer macht mit den Indexwerten nichts.

Das hin und her wandeln der Eingabe für eine Zelle zwischen ganzer Zahl und Zeichenkette und das lineare suchen nach der Zahl in `grid`, obwohl die Zahl ja nur an einer Stelle in `grid()` stehen kann, die aus der Zahl selbst ganz einfach errechenbar ist (-1), ist unnötig umständlich und damit schwerer verständlich als es sein müsste.

Zwischenstand (ungetestet):

Code: Alles auswählen

#!/usr/bin/env python3

WINNING_COMBOS = [
    # Waagerecht.
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],
    # Senkrecht.
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],
    # Diagonal.
    [0, 4, 8],
    [2, 4, 6],
]
PLAYER_1 = "X"
PLAYER_2 = "O"


def play(grid, player):
    print()
    print(" " + " | ".join(grid[:3]))
    print("---+---+---")
    print(" " + " | ".join(grid[3:6]))
    print("---+---+---")
    print(" " + " | ".join(grid[6:]))
    while True:
        try:
            i = int(input(f"Gib eine Zahl für {player} ein: ")) - 1
        except ValueError:
            pass
        else:
            if 0 <= i < len(grid) and grid[i] not in {PLAYER_1, PLAYER_2}:
                grid[i] = player
                break

        print("Gib eine Zahl von einer freien Zelle ein!")

    return any(
        all(grid[i] == player for i in combo) for combo in WINNING_COMBOS
    )


def main():
    grid = list(map(str, range(1, 10)))
    player = PLAYER_1
    #
    # In jedem Schleifendurchlauf wird ein Feld belegt.  Wenn alle Felder belegt
    # sind, ist das Spiel unentschieden.
    #
    for _ in range(len(grid)):
        if play(grid, player):
            print(f"Spieler {player} hat gewonnen!")
            break
        player = PLAYER_1 if player == PLAYER_2 else PLAYER_2
    else:
        print("Unentschieden")


if __name__ == "__main__":
    main()
“All tribal myths are true, for a given value of 'true'.” — Terry Pratchett, The Last Continent
Antworten