8 svar
185 visningar
lamayo 2580
Postad: 26 jun 11:38 Redigerad: 26 jun 11:54

Return True istället för False

Hej! Om jag ändrade till return True istället för False för funktionen is_accessible(self, position) för att se vad som hände. Fick då 

Tre * ovanför G men annars samma väg som vid False. Varför får jag det? Tänker att den nu med True får gå genom väggar men fattar verkligen inte varför den slutar när den hittat G. Nu blir det som två olika vägar till G men den skulle ju bara hitta kortaste väg från S till G och sluta sedan som den gjorde innan? Och varför lade den dem just där? Tacksam för hjälp!!

lamayo 2580
Postad: 26 jun 12:05

Kom på en till grej. Varför gör den inte * i vägen när jag lägger in vissa labyrinter när jag har True men den gör det vid False?

Hej!

Jag hjälper gärna till, men skulle önska två saker:

  1. Posta all kod och använd funktionen för att infoga kod. Då kan jag provköra själv. 
  2. Berätta vad problemet är du försöker lösa. Vad gör koden och vad borde den göra. (Kommentarer i koden är hjälpsamt både för den som läser för första gången och för den som skrivit den när den återkommer till den.)

Just det där att beskriva problemet i detalj för en kursare, en okänd person på ett forum eller en gummianka är en nyttig övning. 

Det kallas ”rubber duck debugging” och leder inte sällan till att man själv hittar problemet när man talar om för någon annan vad koden gör. 

lamayo 2580
Postad: 27 jun 10:47 Redigerad: 27 jun 10:49
from collections import deque

class Maze:
    def __init__(self, grid):
        self.grid=grid
        self.rows=len(grid)
        self.cols=len(grid[0])

    def get_start_position(self):
        for row in range(self.rows):
            for col in range(self.cols):
                if self.grid[row][col]=="S":
                    return (row,col)
                
    def is_goal(self, position):
        (row, col)=position
        if self.grid[row][col]=="G":
            return True
        return False
    
    def is_accessible(self, position):
        (row, col)=position
        if row >= 0 and col >= 0 and row < len(self.grid) and col < len(self.grid[0]):
            return self.grid[row][col] != "#"
        return True
    
    def get_adjacent(self, position):
        (row, col) = position
        return [(row+1, col), (row, col+1), (row-1, col), (row, col-1)]
    
class Path:
    def __init__(self, steps=[]):
        self.steps=steps

    def __add__(self, position):
        return Path(self.steps + [position])
    
def read_maze_from_file(filename):
    with open(filename, "r") as file:
        grid=[]
        for line in file:
            line=line.rstrip()
            grid.append(line)
        return Maze(grid)
    
def get_shortest_path(maze): 
    start = maze.get_start_position()		
    path = Path([start])		
    
    queue = deque()
    queue.append(path)	
    visited = [start]	

    while queue:
        path = queue.popleft()	
        position = path.steps[-1]
        
        if maze.is_goal(position):
            return path

        for adjacent in maze.get_adjacent(position):
            if maze.is_accessible(adjacent) and adjacent not in visited:
                visited.append(adjacent)
                new_path=path + adjacent
                queue.append(new_path)

    raise Exception("This maze has no solution")

def print_maze_with_path(maze, path):
    maze_list = [list(row) for row in maze.grid]
    for (r, c) in path.steps[1:-1]:
        maze_list[r][c] = '*'
    for row in maze_list:
        print("".join(row))

def main():
    with open("maze.txt", "r") as file:
        grid = [line.rstrip() for line in file]
        maze = Maze(grid)
    path = get_shortest_path(maze)
    print_maze_with_path(maze, path)

if __name__ == '__main__':
    main()

Jag ska göra ett program som hittar den kortaste vägen genom en labyrint med hjälp av Breadth-First Search

Labyrinten läses in från en textfil

##########
S...#.##.#
###.#....#
#.#.#.#.##
#.#...#..G
#.#.####.#
#.#....#.#
#.#.##...#
#...#..#.#
##########

(S är startpositionen, G är målet, # är väggar och . är fria rutor).

Programmet ska hitta den kortaste vägen från S till G och skriva ut labyrinten med vägen markerad med *.

Det fungerar bra när jag har return False för funktionen is_accessible(self, position) som det ska vara, men jag ville prova vad som händer om jag sätter return True istället. Då fick jag

##########
S...#.##.*
###.#....*
#.#.#.#.#*
#.#...#..G
#.#.####.#
#.#....#.#
#.#.##...#
#...#..#.#
##########

Jag undrar varför vägen hamnar där? Har den gått utanför labyrinten och sedan gått in vid (1,9)? Är det närmsta vägen då om man får gå utanför?

thedifference 621
Postad: 27 jun 11:28 Redigerad: 27 jun 11:54

Har kollat några minuter. Jag reagerar på detta:

    def is_accessible(self, position):
        (row, col) = position
        if row >= 0 and col >= 0 and row < len(self.grid) and col < len(self.grid[0]):
            return self.grid[row][col] != "#"
        return True

    def get_adjacent(self, position):
        (row, col) = position
        return [(row + 1, col), (row, col + 1), (row - 1, col), (row, col - 1)]

Det ser ut som om get_adjacent() kan returnera positioner som inte finns, medan is_accessible() inte kommer kolla vad dessa är för något utan bara returnera True eftersom de inte möter if-kriterierna. Ditt problem kan ligga här.

Edit: Och det är då varför return False löser problemet. Är det en legal ruta och inte en vägg så kan du gå på den. Ditt return False betyder i det här fallet att rutan helt ligger utanför labyrinten. Jag skulle ändå fixa get_adjacent() så den inte kan returnera rutor som inte finns.

Du kan förresten använda self.rows och self.cols i is_accessible(), istället för att kolla längden igen som du redan gjorde i init().

Ja, det stämmer. Jag lade till lite DEBUG-loggning, vilket gör det mycket lättare att felsöka:

Starting BFS from position (1, 0)

Iteration 0: Exploring position (1, 0)
  Adjacent (2, 0): accessible=False (in-bounds)
  Adjacent (1, 1): accessible=True (in-bounds)
  Adjacent (0, 0): accessible=False (in-bounds)
  Adjacent (1, -1): accessible=True (OUT-OF-BOUNDS)

Koden börjar med att se sig omkring från startpositionen (1, 0). Där returnerar get_adjacent() även (1, -1) som är utanför gränserna. Det fångar dock inte is_accessible() upp utan returnerar True på sista raden. 

Det som är lite spännande är att i python är maze_list[1][-1] helt OK, medan exempelvis C# skulle kasta exception. Här betyder det rad-index=1 och col-index=sista elementet.

Här har du hela utskriften från min körning:

============ RESTART: C:\src\py\pluggakuten_2026-06-27_maze\maze.py ============

Maze with coordinates:
    0123456789
   ----------
 0 |##########
 1 |S...#.##.#
 2 |###.#....#
 3 |#.#.#.#.##
 4 |#.#...#..G
 5 |#.#.####.#
 6 |#.#....#.#
 7 |#.#.##...#
 8 |#...#..#.#
 9 |##########

Starting BFS from position (1, 0)

Iteration 0: Exploring position (1, 0)
  Adjacent (2, 0): accessible=False (in-bounds)
  Adjacent (1, 1): accessible=True (in-bounds)
  Adjacent (0, 0): accessible=False (in-bounds)
  Adjacent (1, -1): accessible=True (OUT-OF-BOUNDS)

Iteration 1: Exploring position (1, 1)
  Adjacent (2, 1): accessible=False (in-bounds)
  Adjacent (1, 2): accessible=True (in-bounds)
  Adjacent (0, 1): accessible=False (in-bounds)
  Adjacent (1, 0): accessible=True (in-bounds)

Iteration 2: Exploring position (1, -1)
  Adjacent (2, -1): accessible=True (OUT-OF-BOUNDS)
  Adjacent (1, 0): accessible=True (in-bounds)
  Adjacent (0, -1): accessible=True (OUT-OF-BOUNDS)
  Adjacent (1, -2): accessible=True (OUT-OF-BOUNDS)

Iteration 3: Exploring position (1, 2)
  Adjacent (2, 2): accessible=False (in-bounds)
  Adjacent (1, 3): accessible=True (in-bounds)
  Adjacent (0, 2): accessible=False (in-bounds)
  Adjacent (1, 1): accessible=True (in-bounds)

Iteration 4: Exploring position (2, -1)
  Adjacent (3, -1): accessible=True (OUT-OF-BOUNDS)
  Adjacent (2, 0): accessible=False (in-bounds)
  Adjacent (1, -1): accessible=True (OUT-OF-BOUNDS)
  Adjacent (2, -2): accessible=True (OUT-OF-BOUNDS)

Iteration 5: Exploring position (0, -1)
  Adjacent (1, -1): accessible=True (OUT-OF-BOUNDS)
  Adjacent (0, 0): accessible=False (in-bounds)
  Adjacent (-1, -1): accessible=True (OUT-OF-BOUNDS)
  Adjacent (0, -2): accessible=True (OUT-OF-BOUNDS)

Iteration 6: Exploring position (1, -2)
  Adjacent (2, -2): accessible=True (OUT-OF-BOUNDS)
  Adjacent (1, -1): accessible=True (OUT-OF-BOUNDS)
  Adjacent (0, -2): accessible=True (OUT-OF-BOUNDS)
  Adjacent (1, -3): accessible=True (OUT-OF-BOUNDS)

Iteration 7: Exploring position (1, 3)
  Adjacent (2, 3): accessible=True (in-bounds)
  Adjacent (1, 4): accessible=False (in-bounds)
  Adjacent (0, 3): accessible=False (in-bounds)
  Adjacent (1, 2): accessible=True (in-bounds)

Iteration 8: Exploring position (3, -1)
  Adjacent (4, -1): accessible=True (OUT-OF-BOUNDS)
  Adjacent (3, 0): accessible=False (in-bounds)
  Adjacent (2, -1): accessible=True (OUT-OF-BOUNDS)
  Adjacent (3, -2): accessible=True (OUT-OF-BOUNDS)

Iteration 9: Exploring position (2, -2)
  Adjacent (3, -2): accessible=True (OUT-OF-BOUNDS)
  Adjacent (2, -1): accessible=True (OUT-OF-BOUNDS)
  Adjacent (1, -2): accessible=True (OUT-OF-BOUNDS)
  Adjacent (2, -3): accessible=True (OUT-OF-BOUNDS)

Iteration 10: Exploring position (-1, -1)
  Adjacent (0, -1): accessible=True (OUT-OF-BOUNDS)
  Adjacent (-1, 0): accessible=True (OUT-OF-BOUNDS)
  Adjacent (-2, -1): accessible=True (OUT-OF-BOUNDS)
  Adjacent (-1, -2): accessible=True (OUT-OF-BOUNDS)

Iteration 11: Exploring position (0, -2)
  Adjacent (1, -2): accessible=True (OUT-OF-BOUNDS)
  Adjacent (0, -1): accessible=True (OUT-OF-BOUNDS)
  Adjacent (-1, -2): accessible=True (OUT-OF-BOUNDS)
  Adjacent (0, -3): accessible=True (OUT-OF-BOUNDS)

Iteration 12: Exploring position (1, -3)
  Adjacent (2, -3): accessible=True (OUT-OF-BOUNDS)
  Adjacent (1, -2): accessible=True (OUT-OF-BOUNDS)
  Adjacent (0, -3): accessible=True (OUT-OF-BOUNDS)
  Adjacent (1, -4): accessible=True (OUT-OF-BOUNDS)

Iteration 13: Exploring position (2, 3)
  Adjacent (3, 3): accessible=True (in-bounds)
  Adjacent (2, 4): accessible=False (in-bounds)
  Adjacent (1, 3): accessible=True (in-bounds)
  Adjacent (2, 2): accessible=False (in-bounds)

Iteration 14: Exploring position (4, -1)

Goal found at position (4, -1)!
Total positions visited: 23

==================================================
SOLUTION PATH:
==================================================
##########
S...#.##.*
###.#....*
#.#.#.#.#*
#.#...#..G
#.#.####.#
#.#....#.#
#.#.##...#
#...#..#.#
##########

==================================================
ALL VISITED POSITIONS:
==================================================

Visited positions visualization:
    0123456789
   ----------
 0 |##########
 1 |S...#.##.#
 2 |###.#....#
 3 |#.#.#.#.##
 4 |#.#...#..G
 5 |#.#.####.#
 6 |#.#....#.#
 7 |#.#.##...#
 8 |#...#..#.#
 9 |##########

Out-of-bounds positions visited:
  (1, -1)
  (2, -1)
  (0, -1)
  (1, -2)
  (3, -1)
  (2, -2)
  (-1, -1)
  (0, -2)
  (1, -3)
  (4, -1)
  (3, -2)
  (2, -3)
  (-1, 0)
  (-2, -1)
  (-1, -2)
  (0, -3)
  (1, -4)

Din kod, något modifierad:

from collections import deque

class Maze:
    def __init__(self, grid):
        self.grid=grid
        self.rows=len(grid)
        self.cols=len(grid[0])

    def get_start_position(self):
        for row in range(self.rows):
            for col in range(self.cols):
                if self.grid[row][col]=="S":
                    return (row,col)
                
    def is_goal(self, position):
        (row, col)=position
        if self.grid[row][col]=="G":
            return True
        return False
    
    def is_accessible(self, position):
        (row, col)=position
        if row >= 0 and col >= 0 and row < len(self.grid) and col < len(self.grid[0]):
            return self.grid[row][col] != "#"
        return True
    
    def get_adjacent(self, position):
        (row, col) = position
        return [(row+1, col), (row, col+1), (row-1, col), (row, col-1)]
    
class Path:
    def __init__(self, steps=[]):
        self.steps=steps

    def __add__(self, position):
        return Path(self.steps + [position])
    
def read_maze_from_file(filename):
    with open(filename, "r") as file:
        grid=[]
        for line in file:
            line=line.rstrip()
            grid.append(line)
        return Maze(grid)
    
def get_shortest_path(maze, debug=False): 
    start = maze.get_start_position()		
    path = Path([start])		

    queue = deque()
    queue.append(path)	
    visited = [start]	

    if debug:
        print(f"Starting BFS from position {start}")

    iteration = 0
    while queue:
        path = queue.popleft()        
        position = path.steps[-1]

        if debug and iteration < 50:  # Limit debug output
            print(f"\nIteration {iteration}: Exploring position {position}")

        if maze.is_goal(position):
            if debug:
                print(f"\nGoal found at position {position}!")
                print(f"Total positions visited: {len(visited)}")
            return path, visited

        for adjacent in maze.get_adjacent(position):
            is_acc = maze.is_accessible(adjacent)
            if debug and iteration < 50:
                in_bounds = (0 <= adjacent[0] < maze.rows and 
                           0 <= adjacent[1] < maze.cols)
                bounds_str = "in-bounds" if in_bounds else "OUT-OF-BOUNDS"
                print(f"  Adjacent {adjacent}: accessible={is_acc} ({bounds_str})")

            if is_acc and adjacent not in visited:
                visited.append(adjacent)
                new_path=path + adjacent
                queue.append(new_path)

        iteration += 1

    raise Exception("This maze has no solution")

def print_maze_with_path(maze, path):
    maze_list = [list(row) for row in maze.grid]
    for (r, c) in path.steps[1:-1]:        
        maze_list[r][c] = '*'
    for row in maze_list:
        print("".join(row))

def print_maze_with_coordinates(maze):
    print("\nMaze with coordinates:")
    # Print column numbers
    col_header = "    " + "".join(f"{i%10}" for i in range(maze.cols))
    print(col_header)
    print("   " + "-" * maze.cols)

    for row_idx, row in enumerate(maze.grid):
        print(f"{row_idx:2} |{row}")
    print()

def print_visited_positions(maze, visited):
    print("\nVisited positions visualization:")
    maze_list = [list(row) for row in maze.grid]

    for (r, c) in visited:
        # Check if position is within bounds
        if 0 <= r < maze.rows and 0 <= c < maze.cols:
            if maze_list[r][c] not in ['S', 'G']:
                maze_list[r][c] = '.'

    # Print column numbers
    col_header = "    " + "".join(f"{i%10}" for i in range(maze.cols))
    print(col_header)
    print("   " + "-" * maze.cols)

    for row_idx, row in enumerate(maze_list):
        print(f"{row_idx:2} |{''.join(row)}")

    # Print out-of-bounds positions
    out_of_bounds = [(r, c) for (r, c) in visited 
                     if r < 0 or c < 0 or r >= maze.rows or c >= maze.cols]
    if out_of_bounds:
        print("\nOut-of-bounds positions visited:")
        for pos in out_of_bounds:
            print(f"  {pos}")
    print()

def main():
    with open("maze.txt", "r") as file:
        grid = [line.rstrip() for line in file]
        maze = Maze(grid)

    print_maze_with_coordinates(maze)

    # Run with debug mode to see positions investigated
    path, visited = get_shortest_path(maze, debug=True)    

    print("\n" + "="*50)
    print("SOLUTION PATH:")
    print("="*50)
    print_maze_with_path(maze, path)

    print("\n" + "="*50)
    print("ALL VISITED POSITIONS:")
    print("="*50)
    print_visited_positions(maze, visited)

if __name__ == '__main__':
    main()
thedifference 621
Postad: 27 jun 17:27

Är du förresten med på att is_accessible() fungerar så här just nu?

thedifference skrev:

Är du förresten med på att is_accessible() fungerar så här just nu?

Jo, det var själv kärnan i frågan. Programmet fungerar fint när False returneras. 

lamayo 2580
Postad: 30 jun 14:56
sictransit skrev:

Ja, det stämmer. Jag lade till lite DEBUG-loggning, vilket gör det mycket lättare att felsöka:

Starting BFS from position (1, 0)

Iteration 0: Exploring position (1, 0)
  Adjacent (2, 0): accessible=False (in-bounds)
  Adjacent (1, 1): accessible=True (in-bounds)
  Adjacent (0, 0): accessible=False (in-bounds)
  Adjacent (1, -1): accessible=True (OUT-OF-BOUNDS)

Koden börjar med att se sig omkring från startpositionen (1, 0). Där returnerar get_adjacent() även (1, -1) som är utanför gränserna. Det fångar dock inte is_accessible() upp utan returnerar True på sista raden. 

Det som är lite spännande är att i python är maze_list[1][-1] helt OK, medan exempelvis C# skulle kasta exception. Här betyder det rad-index=1 och col-index=sista elementet.

Här har du hela utskriften från min körning:

============ RESTART: C:\src\py\pluggakuten_2026-06-27_maze\maze.py ============

Maze with coordinates:
    0123456789
   ----------
 0 |##########
 1 |S...#.##.#
 2 |###.#....#
 3 |#.#.#.#.##
 4 |#.#...#..G
 5 |#.#.####.#
 6 |#.#....#.#
 7 |#.#.##...#
 8 |#...#..#.#
 9 |##########

Starting BFS from position (1, 0)

Iteration 0: Exploring position (1, 0)
  Adjacent (2, 0): accessible=False (in-bounds)
  Adjacent (1, 1): accessible=True (in-bounds)
  Adjacent (0, 0): accessible=False (in-bounds)
  Adjacent (1, -1): accessible=True (OUT-OF-BOUNDS)

Iteration 1: Exploring position (1, 1)
  Adjacent (2, 1): accessible=False (in-bounds)
  Adjacent (1, 2): accessible=True (in-bounds)
  Adjacent (0, 1): accessible=False (in-bounds)
  Adjacent (1, 0): accessible=True (in-bounds)

Iteration 2: Exploring position (1, -1)
  Adjacent (2, -1): accessible=True (OUT-OF-BOUNDS)
  Adjacent (1, 0): accessible=True (in-bounds)
  Adjacent (0, -1): accessible=True (OUT-OF-BOUNDS)
  Adjacent (1, -2): accessible=True (OUT-OF-BOUNDS)

Iteration 3: Exploring position (1, 2)
  Adjacent (2, 2): accessible=False (in-bounds)
  Adjacent (1, 3): accessible=True (in-bounds)
  Adjacent (0, 2): accessible=False (in-bounds)
  Adjacent (1, 1): accessible=True (in-bounds)

Iteration 4: Exploring position (2, -1)
  Adjacent (3, -1): accessible=True (OUT-OF-BOUNDS)
  Adjacent (2, 0): accessible=False (in-bounds)
  Adjacent (1, -1): accessible=True (OUT-OF-BOUNDS)
  Adjacent (2, -2): accessible=True (OUT-OF-BOUNDS)

Iteration 5: Exploring position (0, -1)
  Adjacent (1, -1): accessible=True (OUT-OF-BOUNDS)
  Adjacent (0, 0): accessible=False (in-bounds)
  Adjacent (-1, -1): accessible=True (OUT-OF-BOUNDS)
  Adjacent (0, -2): accessible=True (OUT-OF-BOUNDS)

Iteration 6: Exploring position (1, -2)
  Adjacent (2, -2): accessible=True (OUT-OF-BOUNDS)
  Adjacent (1, -1): accessible=True (OUT-OF-BOUNDS)
  Adjacent (0, -2): accessible=True (OUT-OF-BOUNDS)
  Adjacent (1, -3): accessible=True (OUT-OF-BOUNDS)

Iteration 7: Exploring position (1, 3)
  Adjacent (2, 3): accessible=True (in-bounds)
  Adjacent (1, 4): accessible=False (in-bounds)
  Adjacent (0, 3): accessible=False (in-bounds)
  Adjacent (1, 2): accessible=True (in-bounds)

Iteration 8: Exploring position (3, -1)
  Adjacent (4, -1): accessible=True (OUT-OF-BOUNDS)
  Adjacent (3, 0): accessible=False (in-bounds)
  Adjacent (2, -1): accessible=True (OUT-OF-BOUNDS)
  Adjacent (3, -2): accessible=True (OUT-OF-BOUNDS)

Iteration 9: Exploring position (2, -2)
  Adjacent (3, -2): accessible=True (OUT-OF-BOUNDS)
  Adjacent (2, -1): accessible=True (OUT-OF-BOUNDS)
  Adjacent (1, -2): accessible=True (OUT-OF-BOUNDS)
  Adjacent (2, -3): accessible=True (OUT-OF-BOUNDS)

Iteration 10: Exploring position (-1, -1)
  Adjacent (0, -1): accessible=True (OUT-OF-BOUNDS)
  Adjacent (-1, 0): accessible=True (OUT-OF-BOUNDS)
  Adjacent (-2, -1): accessible=True (OUT-OF-BOUNDS)
  Adjacent (-1, -2): accessible=True (OUT-OF-BOUNDS)

Iteration 11: Exploring position (0, -2)
  Adjacent (1, -2): accessible=True (OUT-OF-BOUNDS)
  Adjacent (0, -1): accessible=True (OUT-OF-BOUNDS)
  Adjacent (-1, -2): accessible=True (OUT-OF-BOUNDS)
  Adjacent (0, -3): accessible=True (OUT-OF-BOUNDS)

Iteration 12: Exploring position (1, -3)
  Adjacent (2, -3): accessible=True (OUT-OF-BOUNDS)
  Adjacent (1, -2): accessible=True (OUT-OF-BOUNDS)
  Adjacent (0, -3): accessible=True (OUT-OF-BOUNDS)
  Adjacent (1, -4): accessible=True (OUT-OF-BOUNDS)

Iteration 13: Exploring position (2, 3)
  Adjacent (3, 3): accessible=True (in-bounds)
  Adjacent (2, 4): accessible=False (in-bounds)
  Adjacent (1, 3): accessible=True (in-bounds)
  Adjacent (2, 2): accessible=False (in-bounds)

Iteration 14: Exploring position (4, -1)

Goal found at position (4, -1)!
Total positions visited: 23

==================================================
SOLUTION PATH:
==================================================
##########
S...#.##.*
###.#....*
#.#.#.#.#*
#.#...#..G
#.#.####.#
#.#....#.#
#.#.##...#
#...#..#.#
##########

==================================================
ALL VISITED POSITIONS:
==================================================

Visited positions visualization:
    0123456789
   ----------
 0 |##########
 1 |S...#.##.#
 2 |###.#....#
 3 |#.#.#.#.##
 4 |#.#...#..G
 5 |#.#.####.#
 6 |#.#....#.#
 7 |#.#.##...#
 8 |#...#..#.#
 9 |##########

Out-of-bounds positions visited:
  (1, -1)
  (2, -1)
  (0, -1)
  (1, -2)
  (3, -1)
  (2, -2)
  (-1, -1)
  (0, -2)
  (1, -3)
  (4, -1)
  (3, -2)
  (2, -3)
  (-1, 0)
  (-2, -1)
  (-1, -2)
  (0, -3)
  (1, -4)

Din kod, något modifierad:

from collections import deque

class Maze:
    def __init__(self, grid):
        self.grid=grid
        self.rows=len(grid)
        self.cols=len(grid[0])

    def get_start_position(self):
        for row in range(self.rows):
            for col in range(self.cols):
                if self.grid[row][col]=="S":
                    return (row,col)
                
    def is_goal(self, position):
        (row, col)=position
        if self.grid[row][col]=="G":
            return True
        return False
    
    def is_accessible(self, position):
        (row, col)=position
        if row >= 0 and col >= 0 and row < len(self.grid) and col < len(self.grid[0]):
            return self.grid[row][col] != "#"
        return True
    
    def get_adjacent(self, position):
        (row, col) = position
        return [(row+1, col), (row, col+1), (row-1, col), (row, col-1)]
    
class Path:
    def __init__(self, steps=[]):
        self.steps=steps

    def __add__(self, position):
        return Path(self.steps + [position])
    
def read_maze_from_file(filename):
    with open(filename, "r") as file:
        grid=[]
        for line in file:
            line=line.rstrip()
            grid.append(line)
        return Maze(grid)
    
def get_shortest_path(maze, debug=False): 
    start = maze.get_start_position()		
    path = Path([start])		

    queue = deque()
    queue.append(path)	
    visited = [start]	

    if debug:
        print(f"Starting BFS from position {start}")

    iteration = 0
    while queue:
        path = queue.popleft()        
        position = path.steps[-1]

        if debug and iteration < 50:  # Limit debug output
            print(f"\nIteration {iteration}: Exploring position {position}")

        if maze.is_goal(position):
            if debug:
                print(f"\nGoal found at position {position}!")
                print(f"Total positions visited: {len(visited)}")
            return path, visited

        for adjacent in maze.get_adjacent(position):
            is_acc = maze.is_accessible(adjacent)
            if debug and iteration < 50:
                in_bounds = (0 <= adjacent[0] < maze.rows and 
                           0 <= adjacent[1] < maze.cols)
                bounds_str = "in-bounds" if in_bounds else "OUT-OF-BOUNDS"
                print(f"  Adjacent {adjacent}: accessible={is_acc} ({bounds_str})")

            if is_acc and adjacent not in visited:
                visited.append(adjacent)
                new_path=path + adjacent
                queue.append(new_path)

        iteration += 1

    raise Exception("This maze has no solution")

def print_maze_with_path(maze, path):
    maze_list = [list(row) for row in maze.grid]
    for (r, c) in path.steps[1:-1]:        
        maze_list[r][c] = '*'
    for row in maze_list:
        print("".join(row))

def print_maze_with_coordinates(maze):
    print("\nMaze with coordinates:")
    # Print column numbers
    col_header = "    " + "".join(f"{i%10}" for i in range(maze.cols))
    print(col_header)
    print("   " + "-" * maze.cols)

    for row_idx, row in enumerate(maze.grid):
        print(f"{row_idx:2} |{row}")
    print()

def print_visited_positions(maze, visited):
    print("\nVisited positions visualization:")
    maze_list = [list(row) for row in maze.grid]

    for (r, c) in visited:
        # Check if position is within bounds
        if 0 <= r < maze.rows and 0 <= c < maze.cols:
            if maze_list[r][c] not in ['S', 'G']:
                maze_list[r][c] = '.'

    # Print column numbers
    col_header = "    " + "".join(f"{i%10}" for i in range(maze.cols))
    print(col_header)
    print("   " + "-" * maze.cols)

    for row_idx, row in enumerate(maze_list):
        print(f"{row_idx:2} |{''.join(row)}")

    # Print out-of-bounds positions
    out_of_bounds = [(r, c) for (r, c) in visited 
                     if r < 0 or c < 0 or r >= maze.rows or c >= maze.cols]
    if out_of_bounds:
        print("\nOut-of-bounds positions visited:")
        for pos in out_of_bounds:
            print(f"  {pos}")
    print()

def main():
    with open("maze.txt", "r") as file:
        grid = [line.rstrip() for line in file]
        maze = Maze(grid)

    print_maze_with_coordinates(maze)

    # Run with debug mode to see positions investigated
    path, visited = get_shortest_path(maze, debug=True)    

    print("\n" + "="*50)
    print("SOLUTION PATH:")
    print("="*50)
    print_maze_with_path(maze, path)

    print("\n" + "="*50)
    print("ALL VISITED POSITIONS:")
    print("="*50)
    print_visited_positions(maze, visited)

if __name__ == '__main__':
    main()

Tack så jättemycket! Nu förstår jag!!

Svara
Close