也许问题可以通过删除所有这些功能来解决,不是吗? 但是,我真的不知道如何让源工作。 顺便说一句,它只是模拟一匹马在一个chesstable,周围和周围,随机,试图访问每个广场一次;并且我的递归深度超出错误。
import random
def main():
global tries,moves
tries,moves=0,0
restart()
def restart():
global a,indexes,x,y
a=[[0 for y in range(8)] for x in range(8)] #Costrutto chic
indexes=[x for x in range(8)]
#Random part
x=random.randint(0,7)
y=random.randint(0,7)
a[x][y]=1
start()
def start():
global i,indexes,moves,tries
i=0
random.shuffle(indexes) #List filled with random numbers that i'll use as indexes
while i<=7:
if indexes[i]==0:
move(-2,-1)
elif indexes[i]==1:
move(-2,1)
elif indexes[i]==2:
move(-1,-2)
elif indexes[i]==3:
move(-1,2)
elif indexes[i]==4:
move(1,-2)
elif indexes[i]==5:
move(1,2)
elif indexes[i]==6:
move(2,-1)
elif indexes[i]==7:
move(2,1)
i+=1
for _ in a:
if 0 in _:
print "Wasted moves: %d"%(moves)
tries+=1
moves=0
restart()
print "Success obtained in %d tries"%(tries)
def move(column,row):
global x,y,a,moves
try: b=a[x+row][y+column]
except IndexError: return 0
if b==0 and 0<=x+row<=7 and 0<=y+column<=7:
x=x+row
y=y+column
a[x][y]=1
moves+=1
start()
else: return 0
try :main()
#except: print "I couldn't handle it" <-Row added to prevent python from returning a huge amount of errors
编辑:这是修改后的版本,但仍然不起作用,但至少它是一个改进:
import random
def move((column,row),x,y):
try: cell=squares_visited[x+row][y+column]
except IndexError: return x,y ## NONE TYPE OBJECT
if cell==0 and 0<=x+row<=7 and 0<=y+column<=7:
x+=row
y+=column
squares_visited[x][y]=1
return x,y ## NONE TYPE OBJECT
squares_visited=[[0] * 8 for _ in range(8)]
x=random.randint(0,7)
y=random.randint(0,7)
squares_visited[x][y]=1
moves=[(-2,-1),(-2,1),(-1,-2),(-1,2),(1,-2),(1,2),(2,-1),(2,1)]
indexes=list(range(8))
tries=0
print "The horse starts in position %d,%d"%(x,y)
while True:
random.shuffle(indexes)
for _ in indexes:
cells=move(moves[indexes[_]],x,y) ##Passing as arguments x and y looks weird
x=cells[0]
y=cells[1]
#If you out this for cicle, there are no legal moves anymore(due to full completion with 1, or to lack of legit moves)
for _ in squares_visited:
if 0 in _:
squares_visited=[[0] * 8 for _ in range(8)]
tries+=1
else:
print "You managed to do it in %d tries."%(tries)
答案 0 :(得分:8)
这段代码存在很多问题 - 足以让它完全重复:
import random
def main():
global tries,moves
过度使用全局变量的许多例子中的第一个。如果可能,传递参数;或创建一个类。这是一个通用策略,可以帮助您构建更易于理解(因此更可调试)的算法;从一般意义上讲,这是您的代码失败的部分原因 - 不是因为任何特定的错误,而是因为代码的复杂性使得很难找到错误。
tries,moves=0,0
restart()
def restart():
global a,indexes,x,y
为什么要为电路板a
命名?这是一个可怕的名字!使用像squares_visited
这样的描述性内容。
a=[[0 for y in range(8)] for x in range(8)] #Costrutto chic
indexes=[x for x in range(8)]
Minor:在python 2中,[x for x in range(8)] == range(8)
- 它们完全相同,所以列表理解是不必要的。在3中,它的工作方式略有不同,但如果您想要列表(而不是range
对象),只需将其传递给list
,如(list(range(8))
)。
#Random part
x=random.randint(0,7)
y=random.randint(0,7)
a[x][y]=1
start()
因此,到目前为止,我对代码的理解是a
是主板,x
和y
是起始坐标,并且您已使用{标记了第一个访问过的地点{1}}。到现在为止还挺好。但事情开始变得毛茸茸,因为你在1
的末尾调用start
而不是从顶级控制函数调用它。这在理论上是可以的,但它使递归比必要的更复杂;这是你问题的另一部分。
restart
更多全局......
def start():
global i,indexes,moves,tries
好的,所以你要做的是按顺序遍历 i=0
random.shuffle(indexes) #List filled with random numbers that i'll use as indexes
while i<=7:
if indexes[i]==0:
move(-2,-1)
elif indexes[i]==1:
move(-2,1)
elif indexes[i]==2:
move(-1,-2)
elif indexes[i]==3:
move(-1,2)
elif indexes[i]==4:
move(1,-2)
elif indexes[i]==5:
move(1,2)
elif indexes[i]==6:
move(2,-1)
elif indexes[i]==7:
move(2,1)
i+=1
中的每个索引。你为什么要使用indexes
?为什么while
全局?我不认为它在其他任何地方使用过。这样做过于复杂。只需使用i
循环直接迭代for
,就像在
indexes
好的,现在针对具体问题......
for index in indexes:
if index==0:
...
我不明白你在这里要做什么。每当您在主板上找到 for _ in a:
if 0 in _:
print "Wasted moves: %d"%(moves)
tries+=1
moves=0
restart()
print "Success obtained in %d tries"%(tries)
(即未访问的位置)时,您似乎正在呼叫restart
。但0
将所有电路板值重置为restart
,因此除非在达到此点之前还有其他方法用0
s填充电路板,否则将导致无限递归。事实上,1
和move
之间的相互递归可能原则上能够实现这一点,但实际上,它太复杂了!问题是没有明确的递归终止条件。
start
原则上,这个想法似乎是如果你的移动命中def move(column,row):
global x,y,a,moves
try: b=a[x+row][y+column]
except IndexError: return 0
if b==0 and 0<=x+row<=7 and 0<=y+column<=7:
x=x+row
y=y+column
a[x][y]=1
moves+=1
start()
else: return 0
或者离开棋盘,那么递归的当前分支就会终止。但由于1
和i
在indexes
之上是全局的,因此重新调用start
时,会重新调整start
并重置indexes
到0!结果是纯粹的混乱!我甚至无法理解这将如何影响递归;似乎有可能因为i
每次都在i
开头重置,并且因为start
的每次成功通话都会调用move
,{{1}开始循环永远不会终止!
我认为有可能最终这个过程将设法访问每个方块,此时事情可能会按预期工作,但实际上,即使预测也太复杂了。
start
不确定你的最后一行是什么意思,但听起来并不是一个好兆头 - 你是在报错而不是找到根本原因。
我将稍微使用这段代码,看看我是否可以通过对其部分状态进行去全球化来使其表现得更好......将很快报告。
<强>更新强>:
好的,如上所述,我将while
去全球化了。然后,我使用try :main()
#except: print "I couldn't handle it" <-Row added to prevent python from returning a huge amount of errors
中的无限循环替换了indexes
/ start
递归,restart
中的restart
语句,其中使用了对return
的调用在start
结尾处有一个restart
(以便在成功时突破无限循环)。结果表现得更像预期。这仍然是糟糕的设计,但它现在有效,因为它递归地尝试一堆随机路径,直到每个本地位置都被访问过。
当然它仍然没有成功;它只是保持循环。实际上找到一个解决方案可能需要更多地重新思考这个算法!但遵循我的上述建议至少可以帮助一些人。
答案 1 :(得分:3)
start()
和move()
互相调用,使其成为间接递归调用但move()
return
启动退出move()
而不是递归
当你调用一个函数时,你会看到一个调用一个函数的函数,它会进入一个引用每个调用的堆栈。当你得到你的最终结果时,你应该向后退,然后取消堆叠这些函数调用。
在这里,你没有,你调用move()
,调用start()
,它会返回一些东西然后你继续深入堆栈。
尝试制作代码的迭代版本。递归很难,从容易开始。
如果你想坚持递归版本,请让move()
自己调用,然后一旦达到out条件就从它自己向后移动。它比处理来自两个函数的递归调用更清楚。
顺便说一句:
while
循环不是必需的。将其替换为索引上的for循环if/elif
语句,将其替换为字典你最终会得到这样的东西:
for i in indexes:
move(*MOVES[i])
MOVES
,是与i
的参数相关联的move()
值的词汇。
[x for x in range(8)]
可以写成range(8)
[[0 for y in range(8)] for x in range(8)]
可以写成[[0] * 8 for x in range(8)]
range()
可以替换为xrange()