list index out of range

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
DRAXX
User
Beiträge: 9
Registriert: Freitag 28. August 2020, 06:50

Hallo,
Ich habe diesen Battleship Code geschrieben:

Code: Alles auswählen

from random import *

#raster erstellen
board = []
for i in range(3):
    board.append(["0","0","0","0","0"])

def boardAusdrucken(board):
     for row in board:
         print("".join(row))

#Punkesystem definieren
Punkte = 0

#Position des Schiffes definieren

def random_reihe(board):
    return randint(0, len(board)-1)

def random_kolone(board):
    return randint(0, len(board[0])-1)

schiff_reihe = random_reihe(board)
schiff_kolone = random_kolone(board)


#Das Spiel wird gestartet und das Board wird gedruckt
print("Lass uns Battleship spielen!")
NameSpieler = (input("Wie heisst du?: "))
print("Also, los gehts ",NameSpieler, "!")
print(boardAusdrucken(board))


#user wird zum raten gefragt
for turn in range(3):
    rate_reihe = int(input("Rate die Reihe (0-4): "))
    rate_kolone = int(input("Rate die Kolone (0-3): "))

#Wenn Spieler das richtige Feld getroffen hat
    if schiff_reihe == rate_reihe and schiff_kolone == schiff_kolone:
      print("Glückwunsch, du hast das Battleship gesenkt! ")
      print("Du hast", Punkte +1, "Punkte")
      restart = input("Willst du nochmal spielen ?: ")
      if restart == "ja" or "Ja":
          print(boardAusdrucken(board))
      else:
          print("Du hattest", Punkte, "Punkte")
          print("Game Over")
# den spieler warnen falls er ausserhalb des Spielfeldes geraten hat
    else:
        if (rate_reihe < 0 or rate_reihe > 5 ) or (rate_kolone < 0 or rate_kolone > 3):
            print("Oops, das ist leider nicht im Spielfeld.")
# warnen falls gleich geraten wurde wie vorher
        elif(board[rate_kolone][rate_reihe] == "X"):
            print("Da hast du schonmal geraten.")
#Wenn die Rate falsch ist, dann das Feld mit X markieren
        else:
            print("Du hast nicht getrofen!")
            board[rate_kolone][rate_reihe] = "X"

#Turn und board nochmals hier ausdrucken
        print("Turn ",  str(turn + 1 ), "von 3.")
        print(boardAusdrucken(board))

           
#Wenn der Spieler es 3 mal versucht hat und nicht getroffen hat, das Spiel beenden

if turn == 4:
    print("Du hattest", Punkte, "Punkte")
    print("Game Over")
    
Wenn ich jedoch z.B. Rate die Reihe: 3 und Rate die Kolone: 3 eingebe, dann bekomme ich diese Fehlermeldung:
Traceback (most recent call last):
File, line 54, in <module>
elif(board[rate_kolone][rate_reihe] == "X"):
IndexError: list index out of range

Könnte ich da Hilfe bekommen ?
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du legst ja auch nur 3 “Kolonen” an. Womit der Index maximal bis 2 gehen darf.
Sirius3
User
Beiträge: 18266
Registriert: Sonntag 21. Oktober 2012, 17:20

*-Importe sind nicht so toll, weil man nicht kontrollieren kann, was da alles in den eigenen Namensraum eingbunden wird, aus random brauchst Du nur randint, also importiere das auch nur.
Variablennamen und Funktionen schreibt man nach Konvention komplett klein. Eingerückt wird immer mit 4 Leerzeichen pro Ebene, nicht mal 2 und mal 4. Kommentare werden auch immer so weit eingerückt, wie es der umgebende Block vorgibt.
All das erhöht die Lesbarkeit, und in gut lesbarem Code findet man sich schneller zurecht, findet also auch schneller Fehler.
Du mischst Funktionsdefinitionen mit Wertzuweisungen an Variablen. Das macht das finden von Funktionen schwierig, bzw. das Finden, wo welche Variable eingeführt wird. Daher sollte eigentlich alles in Funktionen stehen; das verhindert auch, dass man versehentlich globale Variablen benutzt.
In Zeile 29 ist ein Klammernpaar zu viel.
Zeile 30 und andere: Benutze Formatstrings, das macht das Lesen von Ausgaben einfacher, weil weniger Kommas das Lesen verwirren.
boardAusdrucken liefert None zurück, das mit print auszugeben, macht keinen Sinn.
Zeile 44: ein typischer Fehler, wenn man die logische Operation or mit einem Umgangssprachlichen oder verwechselt. Logisch bedeutet
`restart == "ja" or "Ja"` tatsächlich `(restart == "ja") or bool("Ja"")`, also ist der erste Ausdruck wahr oder der zweite. Der zweite ist immer wahr, da ein nicht-leerer String wahr ist. Aber egal ob Du ja oder nein eingibst, das Spiel geht weiter, als ob nichts wäre.
In Zeile 51 hast Du hart kodierte Längen statt sie über len zu ermitteln, wie z.B. in random_reihe.
Zeile 54: wieder zu viele Klammern.
`turn` kann niemals 4 werden. `Punkte` wird nirgends erhöht, bleibt also immer bei 0 Punkten.

So könnte das aussehen:

Code: Alles auswählen

from random import randrange

def board_ausdrucken(board):
     for row in board:
         print("".join(row))

def random_reihe(board):
    return randrange(len(board))

def random_kolone(board):
    return randrange(len(board[0]))


def main():
    # Raster erstellen
    board = []
    for _ in range(3):
        board.append(["0","0","0","0","0"])

    # Position des Schiffes definieren
    schiff_reihe = random_reihe(board)
    schiff_kolone = random_kolone(board)

    # Punkesystem definieren
    punkte = 0

    # Das Spiel wird gestartet und das Board wird gedruckt
    print("Lass uns Battleship spielen!")
    name_spieler = input("Wie heisst du?: ")
    print(f"Also, los gehts {name_spieler}!")
    board_ausdrucken(board)

    # User wird zum Raten gefragt
    for turn in range(1, 4):
        rate_reihe = int(input(f"Rate die Reihe (0-{len(board[0])-1}): "))
        rate_kolone = int(input(f"Rate die Kolone (0-{len(board)-1}): "))

        # Wenn Spieler das richtige Feld getroffen hat
        if schiff_reihe == rate_reihe and schiff_kolone == schiff_kolone:
            print("Glückwunsch, du hast das Battleship gesenkt! ")
            print(f"Du hast {punkte + 1} Punkte")
            restart = input("Willst du nochmal spielen ?: ")
            if restart.lower() == "ja":
                board_ausdrucken(board)
            else:
                print("Du hattest {punkte} Punkte")
                print("Game Over")
        else:
            if not (0 <= rate_reihe < len(board[0]) and 0 <= rate_kolone < len(board)):
                # den Spieler warnen falls er ausserhalb des Spielfeldes geraten hat
                print("Oops, das ist leider nicht im Spielfeld.")
            elif board[rate_kolone][rate_reihe] == "X":
                # warnen falls gleich geraten wurde wie vorher
                print("Da hast du schonmal geraten.")
            else:
                # Wenn die Rate falsch ist, dann das Feld mit X markieren
                print("Du hast nicht getrofen!")
                board[rate_kolone][rate_reihe] = "X"
            # Turn und board nochmals hier ausdrucken
            print(f"Turn {turn} von 3.")
            board_ausdrucken(board)
           
    # Wenn der Spieler es 3 mal versucht hat und nicht getroffen hat, das Spiel beenden
    if turn == 4:
        print(f"Du hattest {punkte} Punkte")
        print("Game Over")

if __name__ == '__main__':
    main()
Die ganzen logischen Fehler sind noch drin, weil ich weiß ja nicht, ob sie vielleicht Absicht sind.
DRAXX
User
Beiträge: 9
Registriert: Freitag 28. August 2020, 06:50

__deets__ hat geschrieben: Freitag 28. August 2020, 07:30 Du legst ja auch nur 3 “Kolonen” an. Womit der Index maximal bis 2 gehen darf.
Ja, habs kürzlich nach dem Schreiben dieser Frage gemerkt, danke.
DRAXX
User
Beiträge: 9
Registriert: Freitag 28. August 2020, 06:50

Sirius3 hat geschrieben: Freitag 28. August 2020, 07:57 *-Importe sind nicht so toll, weil man nicht kontrollieren kann, was da alles in den eigenen Namensraum eingbunden wird, aus random brauchst Du nur randint, also importiere das auch nur.
Variablennamen und Funktionen schreibt man nach Konvention komplett klein. Eingerückt wird immer mit 4 Leerzeichen pro Ebene, nicht mal 2 und mal 4. Kommentare werden auch immer so weit eingerückt, wie es der umgebende Block vorgibt.
All das erhöht die Lesbarkeit, und in gut lesbarem Code findet man sich schneller zurecht, findet also auch schneller Fehler.
Du mischst Funktionsdefinitionen mit Wertzuweisungen an Variablen. Das macht das finden von Funktionen schwierig, bzw. das Finden, wo welche Variable eingeführt wird. Daher sollte eigentlich alles in Funktionen stehen; das verhindert auch, dass man versehentlich globale Variablen benutzt.
In Zeile 29 ist ein Klammernpaar zu viel.
Zeile 30 und andere: Benutze Formatstrings, das macht das Lesen von Ausgaben einfacher, weil weniger Kommas das Lesen verwirren.
boardAusdrucken liefert None zurück, das mit print auszugeben, macht keinen Sinn.
Zeile 44: ein typischer Fehler, wenn man die logische Operation or mit einem Umgangssprachlichen oder verwechselt. Logisch bedeutet
`restart == "ja" or "Ja"` tatsächlich `(restart == "ja") or bool("Ja"")`, also ist der erste Ausdruck wahr oder der zweite. Der zweite ist immer wahr, da ein nicht-leerer String wahr ist. Aber egal ob Du ja oder nein eingibst, das Spiel geht weiter, als ob nichts wäre.
In Zeile 51 hast Du hart kodierte Längen statt sie über len zu ermitteln, wie z.B. in random_reihe.
Zeile 54: wieder zu viele Klammern.
`turn` kann niemals 4 werden. `Punkte` wird nirgends erhöht, bleibt also immer bei 0 Punkten.

So könnte das aussehen:

Code: Alles auswählen

from random import randrange

def board_ausdrucken(board):
     for row in board:
         print("".join(row))

def random_reihe(board):
    return randrange(len(board))

def random_kolone(board):
    return randrange(len(board[0]))


def main():
    # Raster erstellen
    board = []
    for _ in range(3):
        board.append(["0","0","0","0","0"])

    # Position des Schiffes definieren
    schiff_reihe = random_reihe(board)
    schiff_kolone = random_kolone(board)

    # Punkesystem definieren
    punkte = 0

    # Das Spiel wird gestartet und das Board wird gedruckt
    print("Lass uns Battleship spielen!")
    name_spieler = input("Wie heisst du?: ")
    print(f"Also, los gehts {name_spieler}!")
    board_ausdrucken(board)

    # User wird zum Raten gefragt
    for turn in range(1, 4):
        rate_reihe = int(input(f"Rate die Reihe (0-{len(board[0])-1}): "))
        rate_kolone = int(input(f"Rate die Kolone (0-{len(board)-1}): "))

        # Wenn Spieler das richtige Feld getroffen hat
        if schiff_reihe == rate_reihe and schiff_kolone == schiff_kolone:
            print("Glückwunsch, du hast das Battleship gesenkt! ")
            print(f"Du hast {punkte + 1} Punkte")
            restart = input("Willst du nochmal spielen ?: ")
            if restart.lower() == "ja":
                board_ausdrucken(board)
            else:
                print("Du hattest {punkte} Punkte")
                print("Game Over")
        else:
            if not (0 <= rate_reihe < len(board[0]) and 0 <= rate_kolone < len(board)):
                # den Spieler warnen falls er ausserhalb des Spielfeldes geraten hat
                print("Oops, das ist leider nicht im Spielfeld.")
            elif board[rate_kolone][rate_reihe] == "X":
                # warnen falls gleich geraten wurde wie vorher
                print("Da hast du schonmal geraten.")
            else:
                # Wenn die Rate falsch ist, dann das Feld mit X markieren
                print("Du hast nicht getrofen!")
                board[rate_kolone][rate_reihe] = "X"
            # Turn und board nochmals hier ausdrucken
            print(f"Turn {turn} von 3.")
            board_ausdrucken(board)
           
    # Wenn der Spieler es 3 mal versucht hat und nicht getroffen hat, das Spiel beenden
    if turn == 4:
        print(f"Du hattest {punkte} Punkte")
        print("Game Over")

if __name__ == '__main__':
    main()
Die ganzen logischen Fehler sind noch drin, weil ich weiß ja nicht, ob sie vielleicht Absicht sind.

Danke für deine sehr detailierte Antwort. Ich werde definitiv noch daran arbeiten.
Sirius3
User
Beiträge: 18266
Registriert: Sonntag 21. Oktober 2012, 17:20

Du mußt nicht immer den gesamten Beitrag zitieren, der steht ja gleich drüber.
DRAXX
User
Beiträge: 9
Registriert: Freitag 28. August 2020, 06:50

Sorry und wüsstest wie man machen kann, dass man nach jeder richtigen Rate einen Punkt bekommt und nicht, dass es immer auf 1 bleibt ?
Sirius3
User
Beiträge: 18266
Registriert: Sonntag 21. Oktober 2012, 17:20

Das ganze Spiel funktioniert bisher nur einmal. Willst du mehr Runden spielen brauchst du eine Schleife fast den ganzen Code in main. Versuche dich mal händisch den Ablauf deines Programms nachvollziehen.
Antworten