如何使精灵(乌龟)逐格移动通过最佳路径

时间:2020-11-10 08:05:38

标签: python algorithm turtle-graphics python-turtle

现在我正在使用广度优先搜索来创建迷宫寻路算法。查找“最佳路径”的算法似乎有效。但是,问题是我不确定如何使sprite(turtle)沿着最佳路径移动。

这些是我的代码:

import turtle
import time
import sys
from collections import deque

bs = turtle.Screen()
bs.bgcolor("black")
bs.setup(1300,700)

class Building(turtle.Turtle):                             # Define building class
    def __init__(self):
        turtle.Turtle.__init__(self)
        self.shape("square")                               # Shape of the building
        self.color("grey")                                 # Colour of the building
        self.penup()                                       # Lift the pen up so it does not leave a trail
        self.speed('fast')                                 # Sets the speed that the building is drawn on the screen
        
class Road(turtle.Turtle):                                 # Define road class
    def __init__(self):
        turtle.Turtle.__init__(self)
        self.shape("square")                               # Shape of the road
        self.color("white")                                # Colour of the road
        self.penup()                                       # Lift the pen up so it does not leave a trail
        self.hideturtle()
        self.speed('fast')                                 # Sets the speed that the road is drawn on the screen
        
class Start(turtle.Turtle):                                # Define start class
    def __init__(self):
        turtle.Turtle.__init__(self)
        self.shape("square")                               # Shape of the start point
        self.color('green')                                # Colour of the start point 
        self.penup()                                       # Lift the pen up so it does not leave a trail
        self.hideturtle()
        self.speed('fast')
        
class Route(turtle.Turtle):
    def __init__(self):
        turtle.Turtle.__init__(self)
        self.shape("square")
        self.color("yellow")
        self.penup()
        self.hideturtle()
        self.speed('fast')
        
class End(turtle.Turtle):                                  # Define end class
    def __init__(self):
        turtle.Turtle.__init__(self)
        self.shape("square")                               # Shape of the end point
        self.color("red")                                  # Colour of the end point
        self.penup()                                       # Lift the pen up so it does not leave a trail
        self.hideturtle()
        self.speed('fast')    
        
class Searcher(turtle.Turtle):
    def __init__(self):
        turtle.Turtle.__init__(self)
        self.shape("square")
        self.color("white")
        self.penup()
        self.hideturtle()
        self.speed('fast')
        
class sprite(turtle.Turtle):                               # Define sprite class
    noOfSteps = 0                                          # Declare variable noOfSteps and instantiate it as 0
    def __init__(self):
        turtle.Turtle.__init__(self)
        self.shape("turtle")                               # Shape of the sprite
        self.color("purple")                               # Colour of the sprite
        self.penup()                                       # Lift the pen up so it does not leave a trail
        self.hideturtle()
        self.speed('fast')

    def moveSprite(self):
        start.color('green')
        start.stamp()
        searcher.color('red')
        searcher.stamp()
        self.goto(start_x, start_y)
        self.showturtle()
        # self.goto(solution[x,y])
        
# Read maze txt file
def readMaze(mazeSet, filename):
    mazeFile = open(filename, "r")
    lines = mazeFile.readlines()
    for line in lines:
        line = line.strip()
        row = [c for c in line]
        mazeSet.append(row)

mazeSet = []  # This declares the maze as an empty list
readMaze(mazeSet, "CA1_Map.txt") # This reads the maze into the list

# Setting up of maze
def setupMaze(mazeSet):
    global start_x, start_y, end_x, end_y
    m_height, m_width = len(mazeSet), len(mazeSet[0])     # Define maze height and maze width

    for y in range(m_height):                             # Select each line in the maze
        for x in range(m_width):                          # Identify each character in the line
            character = mazeSet[y][x]                     # Assign the maze reference to the variable 'character'
            screen_x = ((x - m_width) * 24) + 150         # Assign screen_x to screen starting position for x coords
            screen_y = ((m_width - y) * 24) - 200         # Assign screen_y to screen starting position for y coords

            if character == "X":                          
                building.goto(screen_x, screen_y)         
                building.stamp()                          
                walls.append((screen_x, screen_y))       
                
            if character == "." or character == 'e':      
                path.append((screen_x, screen_y))

            if character == "e":   
                end_x, end_y = screen_x, screen_y
                searcher.color('red')
                searcher.goto(screen_x, screen_y)
                searcher.stamp()
                searcher.color('white')
                finish.append((screen_x, screen_y))
                
            if character == "s":
                start_x, start_y = screen_x, screen_y                                  
                start.goto(screen_x,screen_y)
                start.stamp()
    
def search(x,y):
    frontier.append((x, y))
    solution[x,y] = x,y

    while len(frontier) > 0:       
        time.sleep(0)
        x, y = frontier.popleft()     

        if(x - 24, y) in path and (x - 24, y) not in visited:  
            cell = (x - 24, y)
            solution[cell] = x, y   
            frontier.append(cell)  
            visited.add((x-24, y)) 

        if (x, y - 24) in path and (x, y - 24) not in visited: 
            cell = (x, y - 24)
            solution[cell] = x, y
            frontier.append(cell)
            visited.add((x, y - 24))

        if(x + 24, y) in path and (x + 24, y) not in visited:  
            cell = (x + 24, y)
            solution[cell] = x, y
            frontier.append(cell)
            visited.add((x + 24, y))

        if(x, y + 24) in path and (x, y + 24) not in visited:  
            cell = (x, y + 24)
            solution[cell] = x, y
            frontier.append(cell)
            visited.add((x, y + 24))
            
        searcher.goto(x,y)
        searcher.stamp()

def correctRoute(x, y):
    route.goto(x, y)
    route.stamp()
    while (x, y) != (start_x, start_y):    
        route.goto(solution[x, y])     
        route.stamp()
        x, y = solution[x, y]
 
def endProgram():
    bs.exitonclick()
    sys.exit()


# Main program

# Setting up classes
building = Building()
road = Road()
start = Start()
end = End()
searcher = Searcher()
route = Route()
sprite = sprite()

# Setting up lists
walls = []
path = []
finish = []
visited = set()
frontier = deque()
solution = {}                   

setupMaze(mazeSet)
search(start_x, start_y)
correctRoute(end_x, end_y)

while True:
    sprite.moveSprite()

迷宫的图像当前如下所示:
enter image description here


因此,我需要做的是使紫色的乌龟(很难看见的)通过最佳的路径(黄色正方形)从绿色方块移到红色方块。

1 个答案:

答案 0 :(得分:0)

步骤1:在程序确定正确路线的功能处, 将每个坐标记录到一个列表中 并返回列表(倒排的),以便可以在函数外部进行访问:

def correctRoute(x, y):
    routes = [(x, y)]
    route.goto(x, y)
    route.stamp()
    while (x, y) != (start_x, start_y):    
        route.goto(solution[x, y])     
        route.stamp()
        x, y = solution[x, y]
        routes.append((x, y))
    return routes[::-1]

步骤2:moveSprite函数提供另一个参数,该参数将成为坐标列表。 然后,列表将分为两部分:起始坐标和路径。致电self.showturtle()之前, 确保乌龟先处于正确的起始位置。 使用for循环,用time.sleep在路径列表中循环,使乌龟进入每个坐标:

def moveSprite(self, routes):
    starting, path = routes[0], routes[1:]
    start.color('green')
    start.stamp()
    searcher.color('red')
    searcher.stamp()
    self.goto(starting)
    self.showturtle()
    for path in path:
        time.sleep(0.3)
        self.goto(path)

步骤3:在代码的最底部,将correctRoute调用分配给变量以检索坐标。 删除while循环,然后将坐标列表放入moveSprite函数中:

routes = correctRoute(end_x, end_y)

sprite.moveSprite(routes)

一起:

import turtle
import time
import sys
from collections import deque

bs = turtle.Screen()
bs.bgcolor("black")
bs.setup(1300,700)

class Building(turtle.Turtle):                             # Define building class
    def __init__(self):
        turtle.Turtle.__init__(self)
        self.shape("square")                               # Shape of the building
        self.color("grey")                                 # Colour of the building
        self.penup()                                       # Lift the pen up so it does not leave a trail
        self.speed('fast')                                 # Sets the speed that the building is drawn on the screen
        
class Road(turtle.Turtle):                                 # Define road class
    def __init__(self):
        turtle.Turtle.__init__(self)
        self.shape("square")                               # Shape of the road
        self.color("white")                                # Colour of the road
        self.penup()                                       # Lift the pen up so it does not leave a trail
        self.hideturtle()
        self.speed('fast')                                 # Sets the speed that the road is drawn on the screen
        
class Start(turtle.Turtle):                                # Define start class
    def __init__(self):
        turtle.Turtle.__init__(self)
        self.shape("square")                               # Shape of the start point
        self.color('green')                                # Colour of the start point 
        self.penup()                                       # Lift the pen up so it does not leave a trail
        self.hideturtle()
        self.speed('fast')
        
class Route(turtle.Turtle):
    def __init__(self):
        turtle.Turtle.__init__(self)
        self.shape("square")
        self.color("yellow")
        self.penup()
        self.hideturtle()
        self.speed('fast')
        
class End(turtle.Turtle):                                  # Define end class
    def __init__(self):
        turtle.Turtle.__init__(self)
        self.shape("square")                               # Shape of the end point
        self.color("red")                                  # Colour of the end point
        self.penup()                                       # Lift the pen up so it does not leave a trail
        self.hideturtle()
        self.speed('fast')    
        
class Searcher(turtle.Turtle):
    def __init__(self):
        turtle.Turtle.__init__(self)
        self.shape("square")
        self.color("white")
        self.penup()
        self.hideturtle()
        self.speed('fast')
        
class sprite(turtle.Turtle):                               # Define sprite class
    noOfSteps = 0                                          # Declare variable noOfSteps and instantiate it as 0
    def __init__(self):
        turtle.Turtle.__init__(self)
        self.shape("turtle")                               # Shape of the sprite
        self.color("purple")                               # Colour of the sprite
        self.penup()                                       # Lift the pen up so it does not leave a trail
        self.hideturtle()
        self.speed('fast')

    def moveSprite(self, routes):
        starting, path = routes[0], routes[1:]
        start.color('green')
        start.stamp()
        searcher.color('red')
        searcher.stamp()
        self.goto(starting)
        self.showturtle()
        for path in path:
            time.sleep(0.3)
            self.goto(path)

# Read maze txt file
def readMaze(mazeSet, filename):
    mazeFile = open(filename, "r")
    lines = mazeFile.readlines()
    for line in lines:
        line = line.strip()
        row = [c for c in line]
        mazeSet.append(row)

mazeSet = []  # This declares the maze as an empty list
readMaze(mazeSet, "CA1_Map.txt") # This reads the maze into the list

# Setting up of maze
def setupMaze(mazeSet):
    global start_x, start_y, end_x, end_y
    m_height, m_width = len(mazeSet), len(mazeSet[0])     # Define maze height and maze width

    for y in range(m_height):                             # Select each line in the maze
        for x in range(m_width):                          # Identify each character in the line
            character = mazeSet[y][x]                     # Assign the maze reference to the variable 'character'
            screen_x = ((x - m_width) * 24) + 150         # Assign screen_x to screen starting position for x coords
            screen_y = ((m_width - y) * 24) - 200         # Assign screen_y to screen starting position for y coords

            if character == "X":                          
                building.goto(screen_x, screen_y)         
                building.stamp()                          
                walls.append((screen_x, screen_y))       
                
            if character == "." or character == 'e':      
                path.append((screen_x, screen_y))

            if character == "e":   
                end_x, end_y = screen_x, screen_y
                searcher.color('red')
                searcher.goto(screen_x, screen_y)
                searcher.stamp()
                searcher.color('white')
                finish.append((screen_x, screen_y))
                
            if character == "s":
                start_x, start_y = screen_x, screen_y                                  
                start.goto(screen_x,screen_y)
                start.stamp()
    
def search(x,y):
    frontier.append((x, y))
    solution[x,y] = x,y

    while len(frontier) > 0:       
        time.sleep(0)
        x, y = frontier.popleft()     

        if(x - 24, y) in path and (x - 24, y) not in visited:  
            cell = (x - 24, y)
            solution[cell] = x, y   
            frontier.append(cell)  
            visited.add((x-24, y)) 

        if (x, y - 24) in path and (x, y - 24) not in visited: 
            cell = (x, y - 24)
            solution[cell] = x, y
            frontier.append(cell)
            visited.add((x, y - 24))

        if(x + 24, y) in path and (x + 24, y) not in visited:  
            cell = (x + 24, y)
            solution[cell] = x, y
            frontier.append(cell)
            visited.add((x + 24, y))

        if(x, y + 24) in path and (x, y + 24) not in visited:  
            cell = (x, y + 24)
            solution[cell] = x, y
            frontier.append(cell)
            visited.add((x, y + 24))
            
        searcher.goto(x,y)
        searcher.stamp()

def correctRoute(x, y):
    routes = [(x, y)]
    route.goto(x, y)
    route.stamp()
    while (x, y) != (start_x, start_y):    
        route.goto(solution[x, y])     
        route.stamp()
        x, y = solution[x, y]
        routes.append((x, y))
    return routes[::-1]
 
def endProgram():
    bs.exitonclick()
    sys.exit()


# Main program

# Setting up classes
building = Building()
road = Road()
start = Start()
end = End()
searcher = Searcher()
route = Route()
sprite = sprite()

# Setting up lists
walls = []
path = []
finish = []
visited = set()
frontier = deque()
solution = {}                   

setupMaze(mazeSet)
search(start_x, start_y)
routes = correctRoute(end_x, end_y)

sprite.moveSprite(routes)

如果您希望乌龟每次改变方向,请将其用作moveSprite功能:

    def moveSprite(self, routes):
        starting, routes = routes[0], routes[1:]
        start.color('green')
        start.stamp()
        searcher.color('red')
        searcher.stamp()
        self.goto(starting)
        self.showturtle()
        for path1, path2 in zip(routes, routes[1:]):
            self.goto(path1)
            time.sleep(0.3)
            if path1[0] == path2[0]: # If the x coordinates of two consecutive moves are equal, that means that the turtle is moving along the `y` axis
                if path1[1] > path2[1]:
                    self.setheading(270)
                else:
                    self.setheading(90)
            else: # If the x coordinates of two consecutive moves aren't equal, that means that the turtle is moving along the `x` axis
                if path1[0] > path2[0]:
                    self.setheading(180)
                else:
                    self.setheading(0)
        self.goto(path2)