Python实现Kruskal迷宫算法的问题

时间:2017-11-07 14:38:38

标签: python turtle-graphics maze

我决定制作一个可变大小的二叉树迷宫生成器。我正在尝试使用Kruskal的迷宫算法,我需要创建一个程序来查看玩家是否有办法从单元格x到单元格y。我无法搞清楚解决迷宫的问题。我决定在二叉树生成器中实现一个迷宫求解器,我有基础但它有一些我无法弄清楚的问题。

它从第一个单元格的中间开始,然后随机选择一个方向并尝试前进到墙壁可能或不可能的位置,如果它不是可能的移动,则它会在另一个随机方向上再次尝试。由于我简单地在墙壁上制作了空间,但是将它们画成白色,我不得不创建一个每个可接受的墙壁列表。

我目前的问题是由于某种原因它不能垂直两次,但它(通常)水平两次没有问题。有什么想法吗?

from turtle import *
import random

def online(y,z):
  first = z[0]
  second = z[1]
  firstx = first[0]
  firsty = first[1]
  secondx = second[0]
  secondy = second[1]
  if firstx <= y[0] <= secondx and firsty >= y[1] >= secondy:
    return(True)
  elif firstx <= y[0] <= secondx and firsty <= y[1] <= secondy:
    return(True)
  elif firstx >= y[0] >= secondx and firsty >= y[1] >= secondy:
    return(True)
  elif firstx <= y[0] <= secondx and firsty >= y[1] >= secondy:
    return(True)

speed(0)
gridsize = 4
cellsize = 50
hideturtle()

cango = []

for i in range(4):
  a = pos()
  forward(gridsize*cellsize)
  b = pos()
  x = (a,b)
  left(90)
goto(0,0)
for i in range(gridsize):
  forward(cellsize)
  left(90)
  a = pos()
  forward(gridsize*cellsize)
  b = pos()
  x = (a,b)
  forward(-gridsize*cellsize)
  seth(0)
goto(0,0)
seth(90)
for i in range(gridsize):
  forward(cellsize)
  right(90)
  a = pos()
  forward(gridsize*cellsize)
  b = pos()
  x = (a,b)
  forward(-gridsize*cellsize)
  seth(90)

color("white")
pensize(2)
seth(270)
a = pos()
forward(cellsize)
b = pos()
x = (a,b)
forward(-cellsize)
seth(0)


choices = (1,2)
for i in range(gridsize):
  choices = (1,2) #Choice 1 cuts the right wall and choice 2 cuts the bottom wall
  for i in range(gridsize):
    a = int(pos()[0])
    b = int(pos()[1])
    #if the x value is all the way on the right, force the choice to cut the bottom
    if a == (gridsize-1)*cellsize or a == (gridsize-1)*cellsize-1:
      x = 2
    #if the y value is all the way on the bottom, force the choice to cut the right
    elif b == cellsize or b == cellsize-1:
      x = 1
    else:
    #if not at x or y max choose randomly between cutting right and cutting down
      x = random.choice(choices)
    #cut right
    if x == 1:
      penup()
      seth(0)
      forward(cellsize)
      right(90)
      pendown()
      a = pos()
      forward(cellsize)
      b = pos()
      x = a,b
      cango.append(x)
      forward(-cellsize)
      seth(0)
    #cut bottom
    elif x == 2:
      penup()
      seth(270)
      forward(cellsize)
      seth(0)
      pendown()
      a = pos()
      forward(cellsize)
      b = pos()
      x = a,b
      cango.append(x)
      penup()
      seth(90)
      forward(cellsize)
      seth(0)
  penup()
  seth(180)
  forward(cellsize*gridsize)
  seth(270)
  forward(cellsize)
  seth(0)
speed(3)
showturtle()
color("red")
goto(25,175)
penup()
print(cango)
pensize(4)
for i in range(1000):
    if pos() == (175.0,0.0):
        pensize(10)
        pencolor("green")
        break
    direction = random.randint(1,4)
    penup()
    if direction == 1:
        seth(0)
    elif direction == 2:
        seth(90)
    elif direction == 3:
        seth(180)
    else:
        seth(270)
    penup()
    forward(25)
    nohit = True
    for i in cango:
      if online(pos(),i) == True:
          nohit = False
      x = i[0]
      y = i[1]
      #if x[0] == pos()[0] and x[1] == pos()[1] or y[0] == pos()[0] and y[1] == pos()[1]:
        #nohit = True
    if nohit == False:
      backward(25)
      pendown()
      forward(50)
    else:
      backward(25)

解决

如果有人遇到类似的问题,我的问题来自于python龟在定义点时没有100%准确的事实,因为我的观点有时像(24.999999991,100)并且我最终强迫它们是整数,对于我的程序,我只使用5的倍数,所以对于我测试的每个点,如果有什么是4或9,如果有的话,我加1。

1 个答案:

答案 0 :(得分:1)

  由于这个原因,在定义点时,python龟并不是100%准确   积分有时像(24.999999991,100)

你必须改变你的想法。乌龟徘徊在浮点飞机上。所有浮点实现都有妥协。学会处理它们:

  

我最终强迫他们成为整数......对于我测试的每一点,如果有什么是4或9,如果有的话我加了1

我建议使用round(),而不是int()的组合,并测试上方和下方。但更好的方法是使用减法或turtle.distance(),并检查差异是否足够小,可以将其称为相同。

这是我使用上述方法对代码进行的返工;修复问题以允许网格调整大小;风格和优化变化。看看这些修改是否对您有意义:

from turtle import *
from random import randrange, choice

GRID_SIZE = 5
CELL_SIZE = 50
RIGHT, BOTTOM = 1, 2  # Choice 1 cuts the right wall and choice 2 cuts the bottom wall

def online(position, line):

    x, y = position

    (firstx, firsty), (secondx, secondy) = line

    if firstx <= x <= secondx and firsty >= y >= secondy:
        return True
    if firstx <= x <= secondx and firsty <= y <= secondy:
        return True
    if firstx >= x >= secondx and firsty >= y >= secondy:
        return True
    if firstx <= x <= secondx and firsty >= y >= secondy:
        return True

    return False

# Draw the grid

hideturtle()
speed('fastest')

for _ in range(GRID_SIZE):
    forward(CELL_SIZE)
    left(90)
    forward(GRID_SIZE * CELL_SIZE)
    backward(GRID_SIZE * CELL_SIZE)
    right(90)

home()
setheading(90)

for _ in range(GRID_SIZE):
    forward(CELL_SIZE)
    right(90)
    forward(GRID_SIZE * CELL_SIZE)
    backward(GRID_SIZE * CELL_SIZE)
    left(90)

# Undraw walls to create a maze

color('white')
setheading(270)

forward(CELL_SIZE)
backward(CELL_SIZE)
setheading(0)

cango = []

for _ in range(GRID_SIZE):

    for i in range(GRID_SIZE):
        a, b = position()

        # if the x value is all the way on the right, force the choice to cut the bottom
        if abs(((GRID_SIZE - 1) * CELL_SIZE) - a) < CELL_SIZE / 4:
            wall = BOTTOM
        # if the y value is all the way on the bottom, force the choice to cut the right
        elif abs(CELL_SIZE - b) < CELL_SIZE / 4:
            wall = RIGHT
        else:
            # if not at x nor y max, choose randomly between cutting right and cutting down
            wall = choice([RIGHT, BOTTOM])

        penup()

        if wall == RIGHT:  # cut right
            setheading(0)
            forward(CELL_SIZE)
            right(90)
            pendown()
            start = position()
            forward(CELL_SIZE)
            end = position()

        elif wall == BOTTOM:  # cut bottom
            setheading(270)
            forward(CELL_SIZE)
            setheading(0)
            pendown()
            start = position()
            forward(CELL_SIZE)
            end = position()
            right(90)

        cango.append((start, end))
        penup()
        backward(CELL_SIZE)
        setheading(0)

    penup()
    backward(CELL_SIZE * GRID_SIZE)
    setheading(270)
    forward(CELL_SIZE)
    setheading(0)

#  Solve the maze

speed('slow')
shape('turtle')
color('red')
pensize(4)
goto(CELL_SIZE / 2, GRID_SIZE * CELL_SIZE - CELL_SIZE / 2)
showturtle()

change_heading = False  # get the most you can out of a direction change

while pencolor() == 'red':

    if distance(GRID_SIZE * CELL_SIZE - CELL_SIZE / 2, -CELL_SIZE / 2) <= CELL_SIZE / 4:
        color('green')
        break

    penup()

    if change_heading:
        direction = randrange(4) * 90
        setheading(direction)
        change_heading = False

    forward(CELL_SIZE / 2)

    nohit = True

    for line in cango:
        if online((round(xcor()), round(ycor())), line):
            nohit = False
            break

    backward(CELL_SIZE / 2)

    if not nohit:
        pendown()
        forward(CELL_SIZE)
    else:
        change_heading = True

mainloop()

enter image description here