#python #algorithm #turtle-graphics #python-turtle
#python #алгоритм #черепаха-графика #python-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()
Изображение лабиринта в настоящее время выглядит следующим образом:
Итак, что мне нужно сделать, это заставить фиолетовую черепаху (которую трудно разглядеть) перемещаться из зеленого квадрата в красный квадрат по наилучшему пути (желтые квадраты).
Ответ №1:
Шаг 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)