题目:
(a)在一个网格中的自我规避游走是一条从一点到另一点的路径,并且这条路径不会经过同一个点两次。自我规避游走在物理、化学和数学中有很多的应用。它可以用来模拟链状实体,例如溶剂和高分子聚合物。编写一个Turtle程序显示一条随机路径,该路径从中心点开始在边界上的某点结束。或者在死点处结束(即该点被其他已经经过的4个点包围)。假设这个网格的大小是16*16。
(a)在死点结束的一条路径 (b)在边界点结束的一条路径
(b)再编写一个仿真程序来显示随着网格大小的扩大,路径在死点结束的概率将会提高。程序模拟网络大小从10变化到50。对于每一种网格大小,仿真10000次自我规避游走然后显示在死点结束的概率,输出如下所示。
For lattice of size 10, the probability of dead-end paths is 10.57%
For lattice of size 11, the probability of dead-end paths is 14.09%
……
For lattice of size 49, the probability of dead-end paths is 94.22%
For lattice of size 50, the probability of dead-end paths is 94.33%
示例代码:
import random
import turtle
count = 0#死点的计数
#判断是否走过
def Judge(xl,yl,listx,listy):
res=False
for i in range(len(listx)):
if xl==listx[i] and yl==listy[i]:#成对判断坐标是否已存在
res=True
return res
#判断是否死点
def Die(x,y,listx,listy):
x1=x+10
x2=x-10
y1=y-10
y2=y+10
Res=Judge(x1,y,listx,listy)&Judge(x2,y,listx,listy)&Judge(x,y1,listx,listy)&Judge(x,y2,listx,listy)
return Res
#地图可视化
def Map(size):
xs = -((size*10)//2)
turtle.pensize(1)
turtle.speed(10)
#纵坐标的线绘制
for y in range(-((size*10)//2),((size*10)//2)+1,10):
turtle.penup()
turtle.goto(xs,y)
turtle.pendown()
turtle.forward(size*10)
#横坐标线绘制
ys = ((size*10)//2)
turtle.right(90)
for x in range(-((size*10)//2),((size*10)//2)+1,10):
turtle.penup()
turtle.goto(x,ys)
turtle.pendown()
turtle.forward(size*10)
#路径绘制函数
def Draw(size):
global count
x = y = 0
listx=[0]
listy=[0]
#设定笔的属性
turtle.pensize(2)
turtle.speed(0)
turtle.color("red")
#模拟走动(是个方向等概率)
turtle.penup()
turtle.goto(0,0)
turtle.pendown()
while abs(x) < ((size*10)//2) and abs(y) < ((size*10)//2):
r = random.randint(0,3)#产生随机数,0右,1下,2左,3上表示是个方向
if Die(x,y,listx,listy):#判断死点
count+=1#计数
break
elif r == 0:#右
x += 10
if Judge(x,y,listx,listy):#判断是否为走过的点
x-=10 #是的话坐标不变
continue#终止本次循环
else:
listx.append(x)
listy.append(y)
turtle.setheading(0)
turtle.forward(10)
elif r == 1:#下
y -= 10
if Judge(x,y,listx,listy):
y+=10
continue
else:
listx.append(x)
listy.append(y)
turtle.setheading(270)
turtle.forward(10)
elif r == 2:#左
x -= 10
if Judge(x,y,listx,listy):
x+=10
continue
else:
listx.append(x)
listy.append(y)
turtle.setheading(180)
turtle.forward(10)
elif r == 3:#上
y += 10
if Judge(x,y,listx,listy):
y-=10
continue
else:
listx.append(x)
listy.append(y)
turtle.setheading(90)
turtle.forward(10)
#主程序部分
if __name__ == "__main__":
temp = input('请输入a,b来选择要解决的问题')
if temp=='a':
turtle.hideturtle()#隐藏画笔
Map(16)
Draw(16)
turtle.done()
elif temp=='b':
turtle.tracer(False)#隐藏动画效果
for i in range(10,51): #模拟地图规模变化
count=0#每次变化对死点计数器初始化
for j in range(0,10000):#10000次仿真训练
Draw(i)
turtle.reset()
print('For lattice of size ',i,', the probability of dead-end paths is ',count/100,'%')
else:
print('input error')
代码解释:
对于a部分,地图的可视化绘制的算法我将其封装为Map()函数,通过两次for循环来根据指定距离和步长绘制网格地图。随机路径绘制的算法采用while循环的判断条件判断点的坐标的绝对值是否小于地图边长一半来确定点是否在地图内,如果在,通过随机种子的方法随机获取0到3中的某一数字,代表上下左右四个行进方向,之后首先通过if判断是否为死点,不是则继续用elif判断方向,之后通过嵌套的if判断该点是否走过,若走过,跳出此次循环,没有,将该点的x和y值存与列表中,并设置该方向的角度,沿该方向前进一格的距离,并将整个过程封装为Draw()函数。判断死点和是否走过部分,我将其封装为Judge()和Die()两个函数,前者通过for循环成对遍历x和y的列表来判断即将要进入的坐标是否存在来判断是否走过该点,后者通过判断该点的上下左右四个点是否都成对存在于x和y的列表里来判断该点是否为死点。最后,调用这几个函数,并设定地图规模为16*16来完成a部分。对于b部分,实质上是对a部分算法的扩充,为了加快计算,设定隐藏动画效果,并取消运行地图可视化的Map()函数,因为Map()函数绘制的地图只是为了第一部分更直观的看到结果,其显示与否不影响路径绘制的算法。动态扩大地图范围的算法采用将地图边长作为参数传入Draw()函数中,动态判断每次是否出边界。在主程序上首先输入a或者b,通过if判断要显示a还是b问题的结果,输入为a,则直接调用Map()和Draw()函数,并设定规模为16,输入为b,则使用for循环模拟地图规模从10到50的变化,通过嵌套的for循环执行10000模拟仿真游走,并根据要求按百分比输出死点的概率。
简要使用说明:
输入描述:输入a,启动解决a问题,输入b,启动解决b问题
输出描述:输入a时输出画图界面,显示16*16地图并按规则开始随机游走;输入b时,按要求输出从10到50地图规模每次10000次游走死点的概率。
输入输出的实例:
输入为a时的实例:
输入为b时的实例: