【问题标题】:Recursive maze solver with a twist - Python带有扭曲的递归迷宫求解器 - Python
【发布时间】:2022-01-03 15:43:47
【问题描述】:

我正在尝试解决以下问题:骰子(骰子?)在一个空网格上滚动,给它传递的每个单元格提供骰子眼数的值(顶部)。有一个给定的开始和退出单元格。我想找到一条经过每个单元格的路线,最终到达出口。 1个解决方案就足够了。程序应该按照掷骰子的规则返回该路线和带有所有编号单元格的网格。

我从一个带有空“迷宫”的 DFS 迷宫求解器脚本开始,并根据额外规则进行了更改。我找到了一条覆盖每个单元格的路线。我得到了一个脚本(我认为),它可以为骰子的任何给定 X 或 Y 运动生成正确的数值。但是试图将这两者结合起来会让我的大脑融化。我无论如何都不是程序员,所以递归在这里杀死了我。

编辑:我想我成功了!我用你的骰子滚动脚本替换了我的骰子脚本,并且不得不解决其他一些问题,但据我所知,它现在正在运行!非常感谢! 但这并不是我冒险的结束,我还需要实现另一层复杂性,但我会先看看我是否能够自己解决它。

这是更新后的代码:

def roll(die, old_dir, new_dir):
    return dict(zip(new_dir, [die[s] for s in old_dir]))

def roll_north(die):
    return roll(die, 'TBNESW', 'NSBETW')

def roll_west(die):
    return roll(die, 'TBNESW', 'WENTSB')

def roll_south(die):
    return roll(die, 'TBNESW', 'SNTEBW')

def roll_east(die):
    return roll(die, 'TBNESW', 'EWNBST')

def DFS(x,y,maze,dice,c,dir):
    global Map
    Map=maze
    if ((Map[x][y]=="exit") & (c==35)):                 #check if we're at the exit
        return [(x,y)]                                  #if so then we solved it so return this spot
    if (Map[x][y]!="path"):                             #if it's not a path, we can't try this spot
        return []
    stat = Map[x][y]
    c += 1
    Map[x][y] = dice['T']                               #make this spot explored so we don't try again

    poss = [[x+1,y],[x-1,y],[x,y+1],[x,y-1]]
    for dir in range(0, 4):                               #new spots to try
        if(dir == 0):
            dice = roll_south(dice)
        elif(dir == 1):
            dice = roll_north(dice)
        elif(dir == 2):
            dice = roll_east(dice)
        elif(dir == 3):
            dice = roll_west(dice)

        result = DFS(poss[dir][0],poss[dir][1],Map,dice,c,dir)       #recursively call itself
        if (dir == 0):
            dice = roll_north(dice)
        elif (dir == 1):
            dice = roll_south(dice)
        elif (dir == 2):
            dice = roll_west(dice)
        elif (dir == 3):
            dice = roll_east(dice)
        if len(result)>0:                                    #if the result had at least one element, it found a correct path, otherwise it failed
            result.append((x,y))                             #if it found a correct path then return the path plus this spot
            return result
    Map[x][y] = stat
    c -= 1
    return []                                                #return the empty list since we couldn't find any paths from here

def GetMap():
    return [
        ["wall","wall","wall","wall","wall","wall","wall","wall"],
        ["wall","path","path","path","path","path","path","wall"],
        ["wall","path","path","path","path","path","path","wall"],
        ["wall","path","path","path","path","path","path","wall"],
        ["wall","path","exit","path","path","path","path","wall"],
        ["wall","path","path","path","path","path","path","wall"],
        ["wall","path","path","path","path","path","path","wall"],
        ["wall","wall","wall","wall","wall","wall","wall","wall"]
    ]

def DrawMap(Map,path):
    cntr = 0
    for x in range(0,len(Map)):
        for y in range(0,len(Map[x])):
            if ((x,y) in path):
                if (Map[x][y] == 1):
                    print("1 ", end="")
                elif (Map[x][y] == 2):
                    print("2 ", end="")
                elif (Map[x][y] == 3):
                    print("3 ", end="")
                elif (Map[x][y] == 4):
                    print("4 ", end="")
                elif (Map[x][y] == 5):
                    print("5 ", end="")
                elif (Map[x][y] == 6):
                    print("6 ", end="")
                elif (Map[x][y] == "exit"):
                    print("e ", end="")
            elif (Map[x][y]=="wall"):
                print("# ",end="")

            else:
                print('  ',end="")
            cntr += 1
        print()
    if path:
        print("\nPATH:")
        path.reverse()
        print(path)

initial_die = dict(zip('TBNESW', [6,1,5,4,2,3]))

print("Solved with DFS:")
res = DFS(2,3,GetMap(),initial_die,0,0)
DrawMap(Map,res)
print("path is",len(DFS(2,3,GetMap(),initial_die,0,0))-1,"steps long\n")
print("\n")

这是输出:

Solved with DFS:
# # # # # # # # 
# 1 2 6 5 1 2 # 
# 4 2 6 3 1 4 # 
# 4 6 5 5 5 5 # 
# 5 e 1 4 6 3 # 
# 3 3 2 2 2 2 # 
# 2 6 6 3 1 4 # 
# # # # # # # # 

PATH:
[(2, 3), (3, 3), (4, 3), (5, 3), (6, 3), (6, 4), (5, 4), (4, 4), (3, 4), (2, 4), (2, 5), (3, 5), (4, 5), (5, 5), (6, 5), (6, 6), (5, 6), (4, 6), (3, 6), (2, 6), (1, 6), (1, 5), (1, 4), (1, 3), (1, 2), (1, 1), (2, 1), (2, 2), (3, 2), (3, 1), (4, 1), (5, 1), (6, 1), (6, 2), (5, 2), (4, 2)]
path is 35 steps long

【问题讨论】:

  • 代表骰子的数组是什么样子的?你能解释一下dice和rotatearray背后的逻辑吗?
  • 当前模具的方向应该是一个结构,告诉您哪个模具面朝向六个方向中的哪个:顶部、底部、北、南、东、西。那么你应该有 4 个函数来告诉你当你通过向北、南、西或东 4 个方向滚动骰子来旋转骰子时你会得到什么。
  • @Stef 骰子数组表示不同边的方向。它有 7 个项目,但第一个是空的,只是用于填充,所以我可以用 dice[1] 处理“1”侧,用 dice[2] 处理“2”侧等。每侧也有 4 个数字,即 4 个相邻边上的数字,按 N-E-S-W 顺序排列。例如,我们从“6”上的骰子和“2”面朝我们开始。如果我们看 dice[6],它的序列 '5, 4, 2, 3' 代表 N、E、S、W 面,与现实生活中的骰子匹配。
  • @Stef rotatearray() 函数在骰子移动后调用,它只循环 4 个面,直到它与实际情况相匹配。例如,考虑到相同的起始位置,假设我们向我滚动 1 步 (x+1)。它现在显示“5”,而 N-E-S-W 在现实生活中是“1-4-6-3”。但是,这与 dice[5] 数组中的方向不匹配,因此需要更新。这就是 DFS 函数中的大 if-else 块发挥作用的地方。我们移动了 x+1,所以第一种情况适用。 lastvalue 变为 6。newvalue 变为 5。然后我循环 4 个数字,直到它与现实生活相匹配。
  • 我发现您管理模具的方式过于复杂而无法调试。必须有更简单的方法来做到这一点。

标签: python recursion depth-first-search dice


【解决方案1】:

我建议使用更简单的方法来处理模具。

  • 骰子是将方向(T、B、N、E、S、W)映射到数字(1、2、3、4、5、6)的字典;
  • 有四个函数roll_north, roll_south, roll_west, roll_east 将骰子作为输入,然后返回一个新骰子,六个方向排列以反映掷骰结果。

可以通过die['T'] 访问骰子顶部的面。

initial_die = dict(zip('TBNESW', [6,1,5,4,2,3]))

def roll(die, old_dir, new_dir):
    return dict(zip(new_dir, [die[s] for s in old_dir]))

def roll_north(die):
    return roll(die, 'TBNESW', 'NSBETW')

def roll_west(die):
    return roll(die, 'TBNESW', 'WENTSB')

def roll_south(die):
    return roll(die, 'TBNESW', 'SNTEBW')

def roll_east(die):
    return roll(die, 'TBNESW', 'EWNBST')

测试:

d = initial_die
print(d['T'], d)
for r in roll_north, roll_east, roll_south, roll_west:
    d = r(d)
    print(d['T'], d)

# OUTPUT
6 {'T': 6, 'B': 1, 'N': 5, 'E': 4, 'S': 2, 'W': 3}
2 {'N': 6, 'S': 1, 'B': 5, 'E': 4, 'T': 2, 'W': 3}
3 {'E': 2, 'W': 5, 'N': 6, 'B': 4, 'S': 1, 'T': 3}
6 {'S': 3, 'N': 4, 'T': 6, 'E': 2, 'B': 1, 'W': 5}
2 {'W': 6, 'E': 1, 'N': 4, 'T': 2, 'S': 3, 'B': 5}

【讨论】:

  • 谢谢!我认为它现在有效。
猜你喜欢
  • 1970-01-01
  • 2023-01-09
  • 2014-04-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-02
  • 2017-09-12
  • 2011-09-22
相关资源
最近更新 更多