List Index out of range bei A* Wege finden.

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
Bananasplit
User
Beiträge: 10
Registriert: Sonntag 11. Februar 2018, 10:18

Ich schreibe gerade ein Programm welches ein Bild einscannt und den Weg zwischen zwei Punkten finden. Dazu habe ich jetzt auch schon den Code. Da sind aber noch ein paar Fehler drin wo ich keine Ahnung habe wie ich sie zu beheben habe. Hier erstmal der Code:

Code: Alles auswählen

import numpy as np
from PIL import Image
import sys
import AAStar
import heapq
sys.setrecursionlimit(sys.maxsize)
weiss = (255,255,255)
schwarz = (0,0,0)
grun = (0,48,0)
rot = (48,0,0)
grau1 = (207,207,207)
grau2 = (43,43,43)
grau3 = (27,27,27)
grau4 = (23,23,23)
liste = []
walls = []
c1 = 0
c2 = 0
rechlist = []
rotlist = []
start = []
reachable = False
s = 0
r=0
nmap = []
bigwalls = []
func1 = 1
func2 = 1
func3 = 1
func4 = 1
index =1

Bild = Image.open('quax.png')
quaxerg = Bild.copy
w, h = Bild.size
Bildk = Bild.resize((int(w*0.5), int(h*0.5)),Image.BICUBIC)
Bildk.save('b.png')
w = w * 0.5
h = h * 0.5

h = int(h)
w = int(w)


nmap = np.array([
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [1,1,1,1,1,1,0,1,1,1,1,1,0,1],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [1,0,1,1,1,1,1,1,1,1,1,1,1,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [1,1,1,1,1,1,0,1,1,1,1,1,0,1],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [1,0,1,1,1,1,1,1,1,0,1,1,1,1],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [1,1,1,1,1,1,1,1,1,1,1,1,0,1],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0]])

class AStar():
    def __init__(self, grid, x, y, goal_x, goal_y)    :
        self.grid = grid
        self.initial_x = x 
        self.initial_y = y 
        self.x = self.initial_x  
        self.y = self.initial_y  
        self.goal_x = goal_x  
        self.goal_y = goal_y 
        self.neighbors = []
        self.neighbor()
    def neighbor(self):
        print ('Ich bin dort!')
        if ((self.x == self.goal_x) and (self.y == self.goal_y)) == True:
            print('your done')
            return 'your done'
        self.grid[self.x][self.y] == 1
        if self.x > 0: 
            if self.grid[self.x-1] [self.y] == 0:
                self.neighbors.append([self.x - 1, self.y])  
        if self.x < self.grid.shape[0] - 1:
            if self.grid[self.x+1][self.y] == 0: 
                self.neighbors.append([self.x+1,self.y]) 
        if self.y > 0:
            if self.grid[self.x][self.y - 1] == 0:
                self.neighbors.append([self.x, self.y - 1])
        if self.y < self.grid.shape[1] - 1: 
            if self.grid[self.x][self.y + 1] == 0:
                self.neighbors.append([self.x, self.y + 1]) 
        self.f_value()
    def f_value(self):
        print ('Ich bin da!')
        h_values = []
        g_values = []  
        for i in self.neighbors:     
            x_distance = abs(i[0] - self.goal_x)  
            y_distance = abs(i[1] - self.goal_y)  
            h_value = (x_distance + y_distance)
            h_values.append(h_value)
        for i in self.neighbors:
            x_distance = abs(i[0] - self.initial_x)  
            y_distance = abs(i[1] - self.initial_y)
            g_value = (x_distance + y_distance)
            g_values.append(g_value)
        self.f_values = [h + g for h, g in zip(h_values, g_values)]
        self.path()
        return (self.f_values)
    def path(self):
        global index
        print ('Ich bin hier!')
        for coordinate, i in enumerate(self.f_values):
            if i <= min(self.f_values):
                value = i
                index = coordinate
        self.x = self.neighbors[index][0]     #   
        self.y = self.neighbors[index][1]
        print('f_values:', self.f_values)
        print('neighbors:', self.neighbors)  
        print('x:', self.x)
        print('y:', self.y)
        self.neighbors.pop(index)
        self.f_values.pop(index)
        self.neighbor()

Test = AStar(nmap, c1,c2,s,r) 
func2 = Test.neighbor()
func3 = Test.f_value()
func4 = Test.path()
print (func2,func3,func4,'ich funktioniere')
Ich habe das ganze Bild einscannen der einfachheitshalber weggenommen.Größtenteils bekomme ich da den Fehler wo ich das # gemacht habe. Nämlich 'List Index out of range'

Auf jeden Fall Danke im Voraus,
Bananasplit
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

`AAStar` und `heapq` werden importiert, aber nicht verwendet. Das Rekursionslimit sollte man nicht verändern, und wenn, dann auf einen sinnvollen Wert. `weiss`, `schwarz`, ... `liste`, `walls`, `rechlist`, `rotlist`, `start`, `reachable`, `nmap`, `bigwalls`, `func1`, ... `func4`, `index`, `quaxerg`, `h` und `w` werden definiert, aber nie verwendet. Globale Variablen an sich sollten man vermeiden, so dass es gut ist, dass sie nicht verwendet werden; aber dann sollte man sie einfach löschen. `c1`, `c2`, `s` und `r` werden zwar verwendet, aber an einer ganz anderen Stellen. An der sollte man sie auch erst definieren. Die Namen sind zudem sehr schlecht, weil sie nichts aussagen. Durch unnötiges Zeug und schlechte Namen wird der Code unnötigerweise schwer lesbar und das finden von Fehlern behindert.

Die Klasse `AStar` hat drei Methoden, die sich gegenseitig rekursiv aufrufen. Niemand kann so einen Programmfluß nachvollziehen, Fehler sind damit unmöglich zu finden. Wenn Rekursion, dann nur eine Funktion, die sich selbst aufruft, Andere Methoden sollten definierte Rückgabewerte haben. Versuche für jede Funktion in einem Satz zu sagen, was sie tut.

Auf `== True` zu prüfen, ist meist unnötig, in der Zeile sind auch mindestens 3 Klammernpaare zu viel.
Dass es sich um Werte handelt, ist bei den meisten Variablen klar, aber was heißt denn und f, g, oder h bei f_values, g_values, und h_values? Namen sind wichtig für das Verstehen des Codes und damit das finden von Fehlern.

In `path` benutzt Du `global`. Vergiß das schnell wieder. global ist nie eine Lösung, sondern macht nur mehr Probleme. Das finden des Indexes des kleinsten Wertes einer Liste, geht einfacher per:

Code: Alles auswählen

index, value = min(enumerate(self.f_values), key=lambda a: a[1])
`x` und `y` sind eigentlich keine Attribute, sondern besser Argumente für die Funktion `neighbor`.
`neighbor` hat mal einen (nicht sollvollen) Rückgabewert, mal keinen; der Rückgabewert von `f_value` wird nicht verwendet.

Räume Deinen Code auf, und entwirre die Rekursionen. Danach kann man sich an die Fehlersuche machen.
Bananasplit
User
Beiträge: 10
Registriert: Sonntag 11. Februar 2018, 10:18

Danke für diese ausführliche Antwort! Ich werde mir das anschauen.
Die vielen Variablen sind noch Überbleibsel von den Teil die das Bild scannen. Ich bin kenne mein Problem zu viele Variablen zu benutzen bereits und versuche es zu bekämpfen.
Ich habe auch schon öfters gehört global nicht so oft zu benutzen aber ich weiß nicht wie ich das lösen kann Variablen von einer Definition zur anderen zu übertragen.

Ich werde versuchen die angesprochenen Problem zu klären und komme dann wieder.
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Eine 'Definition' heisst Funktion oder Methode (wenn in einer Klasse definiert). Und die Art, wie Werte da rein kommen sind Parameter. Zb statt

Code: Alles auswählen

def path(self):
     global index
     ...
machst du

Code: Alles auswählen

def path(self, index):
     ....
Wenn du Werte veraendern willst, dann gibst du die per return zurueck, Python kann auch mehrere Werte zurueck geben

Code: Alles auswählen

return a, b, c
Und in objektorienterter Programmierung hast du natuerlich auch noch den self-Parameter und damit die Instanz, mit der du auch Werte transportieren kannst. Allerdings ist es ratsam, so wenig Zustand wie moeglich zu haben, weil der nur verwirrt. Denn man muss ihn im Kopf haben. Parameter, die eine Funktion oder Methode bekommt hingegen sind immer einfacher, weil man darueber nachdenken kann, ohne sich zu fragen, welchen Wert sie warum haben koennte.
Antworten