Python 3.x 显示沿随机漫游的最短路径

Python 3.x 显示沿随机漫游的最短路径,python-3.x,turtle-graphics,python-turtle,random-walk,algorithm-animation,Python 3.x,Turtle Graphics,Python Turtle,Random Walk,Algorithm Animation,我是一名CS教师,我们在课堂上编写了一些Python代码,让海龟随机游走。有人问我们是否可以画一只新乌龟,它将沿着最小路径(从起点到终点)追踪路线。当前代码如下 我想我们必须先列出坐标,然后创建某种树。我肯定已经有一个图书馆来做这件事了,只是不确定 import turtle import random import time from math import sqrt leo = turtle.Turtle() leo.speed(0) leo.color("green") leo.dot

我是一名CS教师,我们在课堂上编写了一些Python代码,让海龟随机游走。有人问我们是否可以画一只新乌龟,它将沿着最小路径(从起点到终点)追踪路线。当前代码如下

我想我们必须先列出坐标,然后创建某种树。我肯定已经有一个图书馆来做这件事了,只是不确定

import turtle
import random
import time
from math import sqrt

leo = turtle.Turtle()
leo.speed(0)

leo.color("green")
leo.dot(6)  # mark the starting location
leo.color("black")

directions = ['N', 'S', 'E', 'W']

steps = 100
step_size = 10

start = time.time()

for i in range(steps):

    heading = random.choice(directions)

    if heading == 'N':
        leo.setheading(90)
    elif heading == 'S':
        leo.setheading(270)
    elif heading == 'E':
        leo.setheading(0)
    else:
        leo.setheading(180)

    leo.forward(step_size)

(x,y) = leo.position()

distance = sqrt( x**2 + y**2 )

end = time.time()

leo.color("red")    # mark the end location
leo.dot(6)
leo.hideturtle()

# drawing the final distance: start to end
raph = turtle.Turtle()
raph.color("blue")
raph.goto(x,y)
raph.hideturtle()

print("Total time:", end - start)
print("Total steps:", steps)
print("Total distance:", distance / step_size)
方法是:
1-生成一个随机行走并在画布上绘制它
2-使用该随机游动生成晶格(坐标图及其与相邻坐标的连接)。
2-使用起点和终点搜索晶格中的最短路径。此处使用宽度优先搜索,但也可以使用其他搜索。
3-在画布上,在晶格上绘制最短的路径

下面是一个叠加了最短路径的步行示例:

用于生成它的代码: (从您发布的代码扩展)

随机导入
进口海龟
班级步行者:
“”“虚拟晶格上的随机漫游器”
定义在一个方向上迈出一步的规则
记录步骤的方向顺序
"""
#四个方向
方向=('N','S','E','W')
ID=1
定义初始化(自):
self.name=f“{self.\uuuuuu class.\uuuuuuu name.\uuuuuu}编号:{Walker.ID}”
Walker.ID+=1
self.sequence_of_steps=[]#一个方向序列
def采取步骤(自我):
方向=随机选择(Walker.DIRECTIONS)
self.sequence\u of_steps.append(方向)
定义(自我):
返回f“{self.name}”
上课时间:
“”“管理步行者采取步骤”“”
定义初始化(self,walker=walker,numwalkers=1,numsteps=100):
self.numsteps=numsteps
self.numwalkers=numwalkers
self.walkers=[walker()用于范围内的(numwalkers)]
打印{self.numsteps}步骤的f'walking{self.numwalkers}{walker}
self.do_walk()
def do_步行(自我):
对于步进范围(self.numsteps):
对于self.walkers中的walker:
沃克,走一步
定义(自我):
返回'\n'.join(str(walker.sequence\u of\u步骤)
适用于自我中的步行者。步行者)
def喷漆_步行者_路径(步行者):
“”“在画布上绘制一个步行者的路径”“”
标题={'N':90,'S':270,'E':0,'W':180}
单位移动=10像素
方向\u路径=步数的步数
t=海龟。海龟()
t、 速度(“最快”)
t、 颜色(“绿色”)
t、 圆点(尺寸=10)
t=海龟。海龟()
t、 颜色(“灰色”)
report=turtle.turtle()
报告:penup()
报告:hideturtle()
报告。后藤(200200)
report.write(“步骤:”,True,字体=('courier',18,'normal'))
report.write('0',font=('courier',18',normal'))
对于idx,枚举中的方向(方向\路径):
t、 设置标题(标题[方向])
t、 前进(单位移动)
t、 圆点(尺寸=4)
report.undo()
报告:penup()
report.pendown()
report.write(f“{idx}”,font=('courier',18,'normal'))
t、 希德图尔()
t、 颜色(“红色”)
t、 dot(6)
t、 后藤(0,0)
def绘制路径(方向路径):
标题={'N':90,'S':270,'E':0,'W':180}
单位移动=10像素
t=海龟。海龟()
t、 速度(“最快”)
t、 颜色(“黑色”)
t=海龟。海龟()
t、 颜色(“黑色”)
t、 养老金(2)
对于方向_路径中的方向:
t、 设置标题(标题[方向])
t、 前进(单位移动)
t、 圆点(尺寸=4)
t、 希德图尔()
类坐标:
#偏移量为(列,行)i/e(x,y)
偏移量={'N':(0,1),'S':(0,-1),'E':(1,0),'W':(-1,0)}
COORD_TO_DIR={(0,1):(0,-1):'S',(1,0):'E',(-1,0):'W'}
定义初始化(self、col、row):
self.col=col
self.row=行
self.coord=(self.col,self.row)
def get_相邻(自身、方向):
“”“返回与自身相邻的新坐标对象。”
在给定的方向上
"""
d_col,d_row=坐标。偏移量[方向]
返回坐标(self.col+d_col,self.row+d_row)
def get_方向(自身、目的地):
“”“返回要移动的方向
从自我到目的地
offcol=destination.col-self.col
offrow=destination.row-self.row
助理秘书长(财务主任)
import random
import turtle


class Walker:
    """a random walker on a virtual lattice
    defines the rules of taking a step in a direction
    records the sequence of directions of the steps takem
    """

    # four directions
    DIRECTIONS = ('N', 'S', 'E', 'W')
    ID = 1

    def __init__(self):
        self.name = f"{self.__class__.__name__} no.: {Walker.ID}"
        Walker.ID += 1
        self.sequence_of_steps = []   # a sequence of directions

    def take_step(self):
        direction = random.choice(Walker.DIRECTIONS)
        self.sequence_of_steps.append(direction)

    def __str__(self):
        return f"{self.name}"


class RandomWalk:
    """manages Walkers take_step"""

    def __init__(self, walker=Walker, numwalkers=1, numsteps=100):
        self.numsteps = numsteps
        self.numwalkers = numwalkers
        self.walkers = [walker() for _ in range(numwalkers)]
        print(f'walking {self.numwalkers} {walker} for {self.numsteps} steps')
        self.do_walk()

    def do_walk(self):
        for step in range(self.numsteps):
            for walker in self.walkers:
                walker.take_step()

    def __str__(self):
        return '\n'.join(str(walker.sequence_of_steps)
                         for walker in self.walkers)


def paint_walker_path(walker):
    """paints the path of one walker on the canvas"""
    headings = {'N': 90, 'S': 270, 'E': 0, 'W': 180}
    unit_move = 10   # pixels

    direction_path = walker.sequence_of_steps
    t = turtle.Turtle()
    t.speed('fastest')
    t.color('green')
    t.dot(size=10)

    t = turtle.Turtle()
    t.color('gray')
    report = turtle.Turtle()
    report.penup()
    report.hideturtle()
    report.goto(200, 200)
    report.write("step: ", True, font=('courier', 18, 'normal'))
    report.write('0', font=('courier', 18, 'normal'))
    for idx, direction in enumerate(direction_path):
        t.setheading(headings[direction])
        t.forward(unit_move)
        t.dot(size=4)
        report.undo()
        report.penup()
        report.pendown()
        report.write(f"{idx}", font=('courier', 18, 'normal'))
    t.hideturtle()
    t.color('red')
    t.dot(6)
    t.goto(0, 0)


def paint_path(direction_path):
    headings = {'N': 90, 'S': 270, 'E': 0, 'W': 180}
    unit_move = 10  # pixels

    t = turtle.Turtle()
    t.speed('fastest')
    t.color('black')

    t = turtle.Turtle()
    t.color('black')
    t.pensize(2)
    for direction in direction_path:
        t.setheading(headings[direction])
        t.forward(unit_move)
        t.dot(size=4)
    t.hideturtle()


class Coordinate:

    # offsets are (col, row) i/e (x, y)
    OFFSETS = {'N': (0, 1), 'S': (0, -1), 'E': (1, 0), 'W': (-1, 0)}
    COORD_TO_DIR = {(0, 1): 'N', (0, -1): 'S', (1, 0): 'E', (-1, 0): 'W'}

    def __init__(self, col, row):
        self.col = col
        self.row = row
        self.coord = (self.col, self.row)

    def get_adjacent(self, direction):
        """returns a new Coordinate object adjacent to self
         in the given direction
        """
        d_col, d_row = Coordinate.OFFSETS[direction]
        return Coordinate(self.col + d_col, self.row + d_row)

    def get_direction(self, destination):
        """returns the direction to take in order to move
        from self to destination"""
        offcol = destination.col - self.col
        offrow = destination.row - self.row
        assert abs(offcol) <= 1 and abs(offrow) <= 1, "adjacent coordinates must be close by"
        return Coordinate.COORD_TO_DIR[(offcol, offrow)]

    def __hash__(self):
        return hash(self.coord)

    def __eq__(self, other):
        return self.coord == other.coord

    def __str__(self):
        return f"Coordinate {self.coord}"

    def __repr__(self):
        return str(self)


ORIGIN = Coordinate(0, 0)


class Lattice:
    def __init__(self):
        self.adjacency = {}

    def get_final_dest_and_merge_sequence_of_steps(self, sequence_of_steps,
                                                   origin=ORIGIN):
        current_coordinate = origin
        for direction in sequence_of_steps:
            adjacent_coordinate = current_coordinate.get_adjacent(direction)
            try:
                self.adjacency[current_coordinate].add(adjacent_coordinate)
            except KeyError:
                self.adjacency[current_coordinate] = {adjacent_coordinate}
            try:
                self.adjacency[adjacent_coordinate].add(current_coordinate)
            except KeyError:
                self.adjacency[adjacent_coordinate] = {current_coordinate}
            current_coordinate = adjacent_coordinate
        return current_coordinate

    @staticmethod
    def extract_sequence_of_steps(seq_of_coordinates):
        steps = []
        current_coord = seq_of_coordinates[0]
        for next_destination in seq_of_coordinates[1:]:
            steps.append(current_coord.get_direction(next_destination))
            current_coord = next_destination
        return steps

    def __str__(self):
        adjacency = []
        for k, v in self.adjacency.items():
            adjacency.append(f'{k},: {v}\n')
        return ''.join(adjacency)


class BFS:

    def __init__(self, lattice, start_coord, end_coord):
        self.lattice = lattice
        self.start_coord = start_coord
        self.end_coord = end_coord
        self.shortest_path = None   # a sequence of Coordinate
        self.bfs()

    def bfs(self):
        queue = []
        visited = set()
        queue.append([self.start_coord])
        while queue:
            path = queue.pop(0)
            print("queue: ", queue, "path: ", path)
            node = path[-1]
            if node == self.end_coord:
                self.shortest_path = path
                break
            if node not in visited:
                for adjacent in self.lattice.adjacency.get(node, []):
                    new_path = list(path)
                    new_path.append(adjacent)
                    queue.append(new_path)
            visited.add(node)


if __name__ == '__main__':

    walk = RandomWalk(walker=Walker, numsteps=1000)
    print(walk)

    tom = walk.walkers[0]

    paint_walker_path(tom)
    print("Done with turtle tom")

    lattice = Lattice()
    end_node = lattice.get_final_dest_and_merge_sequence_of_steps(tom.sequence_of_steps)
    print(end_node)
    print(lattice)

    search = BFS(lattice, ORIGIN, end_node)
    print('search: ', search.shortest_path)

    shortest_tom = Lattice.extract_sequence_of_steps(search.shortest_path)
    paint_path(shortest_tom)

    turtle.done()