水暖随机路径


23

编写一个包含三个整数,宽度w,高度h和步数的程序或函数s。您将在一个按像素图像上绘制很长的非自相交随机 s步长,其中每5 x 5像素单元为空(纯米色)或以下十二个简单“管道”之一:5*w5*h

扩大的管道

上面的图像被放大以显示细节。这是实际尺寸的管道:

管道

(灰色线仅用于分隔管道类型。)

随机游走将是一条连续的管道路径,该路径从一个管道端点(底部四种管道类型之一)开始,到另一个管道端点结束。

从一个空wh网格开始,并随机选择一个单元格作为起点。然后随机选择四个方向之一以开始并绘制相应的管道端点。这个开始的单元格标志着您步行的第一步,每当您绘制一个新的单元格或覆盖一个现有的单元格时,它便被视为采取的另一步骤。

现在,如果选择的方向有效,则反复地随机选择向右,向左或向右走,绘制适当的管单元。回溯并重新选择方向,直到s形成完整的步阶路径才有效。该路径应以管道端点结尾,该端点可以在网格上的任何位置,具体取决于路径所采用的路线。

重要的是要注意,只有两个直管单元可以被覆盖,并且只能被方向相反的直管单元覆盖,结果是相交单元。否则,必须将所有管道放置在空的单元格中。

绘制相交时,应将路径中距起始像元更远的部分绘制在顶部。

由您决定网格是否具有周期性边界条件(PBC),即,从网格一侧退出的管道是否会从另一侧伸出。如果没有PBC,则网格边界会像其他管道一样成为障碍。

特别案例

  • s为0时,不应绘制任何管道,并且输出5*w5*h图像应为空白(即所有米色)。
  • s为1时,单个管道存根

    扩大的管头(实际尺寸:短管

    应该在随机选择的起始单元格上绘制。

其他详情

  • 您可能会认为这s是最多的,w*h因此一条路径永远是可能的。(尽管由于相交,可能会有更长的路径。)
  • w并且h将始终是积极的。
  • 所有随机选择都必须一致地随机。例如,即使这样会使问题变得更容易,您也不应避免在可能的情况下进行交叉。允许使用伪随机数生成器。
  • 可以使用任何三种视觉上不同的颜色来代替黑色,蓝色和米色。
  • 您的输出图像可能会被放大,以使它们实际上是5*w*k5*h*k像素(其中k为正整数)表示的。(即使您k是1,也建议您放大发布的所有示例。)
  • 可以使用任何常见的无损图像文件格式,并且可以将图像保存到文件,显示或原始输出到stdout。

以字节为单位的最短代码获胜。

例子

(全部放大了500%。)

如果输入为,w=2, h=1, s=0则输出将始终为:

如果输入是,w=2, h=1, s=1则输出将是这些图像之一,机会均等:

如果输入为,w=2, h=1, s=2则输出为

或可能

如果假定网格具有PBC。

(请注意,像这样开始路径将使第二步变得不可能。)


以下是w=3, h=2, s=6假设PBC的一些可能的输出:


w=3, h=3, s=9假设PBC,这是的可能输出:

请注意,由于相交计算为两个步骤,因此路径不需要覆盖所有像元。同样,我们可以推断出拐角端点是起始像元,因为必须在之后绘制交叉点立交桥。因此,我们可以推断出做出的随机选择的顺序:

start at top left, facing east
go straight
go right
go right
go right
go straight
go left
go right
end

最后,这是w=4, h=5, s=20和的示例w=4, h=5, s=16


1
整个想法只是随意走动,对吧?
Akangka,2015年

第2行:You will be drawing a non-self-intersecting random walk...是自相交还是不相交?
edc65

@ChristianIrwan好吧,不是。随机游走通常可以使自己双退,或者完全不相交。这是一个独特的情况,因为已经形成了相交点,但是它们不算作是在追踪相同的地面。是的,这可以是ascii艺术格式或其他格式,但我喜欢制作美观图像的想法。
加尔文的爱好2015年

2
@ChristianIrwan我已经回答了,当我说“是的,它可以采用ascii格式或类似格式,但是我喜欢制作美观图像的想法。” 我选择不参与ascii艺术。
加尔文的爱好2015年

1
是否允许“打结”?
aditsu '16

Answers:


4

果酱,274

q~:K;:B;:A;{0aA*aB*:M5*5f*:I;K{[Bmr:QAmr:P]5f*:R;3Ym*{R.+:)2{1$0=I=2$W=@tI@0=@t:I;}:F~}/R2f+1FK({MQ=P=:EY4mr:D#&1{{MQMQ=PE2D#+tt:M;}:G~7,1>[W0_1_0_W]2/D=:Off*{[QP]5f*2f+.+_:H1F_OW%.+2FOW%.m2F}/H2FO~P+:P;Q+:Q;MQ=P=:E_5YD2%-*=!JK2-=+*1{D2+4%:D;G}?}?}fJ]}0?}g'P2NA5*SI,N2NI:+N*

在线尝试

使用PBC,以PGM格式输出。您可以删除:+末端附近的内容,以在浏览器中获得更好的视觉输出。

对于较大的输入,这非常慢,尤其是在步数接近该区域的情况下。

输入结果示例4 3 10(缩放比例为500%):

例

简要说明:

通用方法是:

  • 重复以下所有步骤,直到成功:
  • 初始化2个矩阵:一个记录每个单元中正在使用的边,另一个用于图像
  • 如果s = 0,我们就完成了,否则:
  • 选择一个随机单元并绘制一个正方形,然后执行以下s-1次:
  • 选择一个随机的方向;如果该侧已被使用,则失败并重新开始
  • 标记使用过的一面并在图像中绘制实际的管道(绘制3条相邻的长度为6的线,从当前单元格的中心像素“之后”开始,然后在管道的端部添加一个点)
  • 更新当前位置(移至下一个单元格)
  • 检查单元格是否为空或有效交叉点;如果没有,则失败并重新开始
  • 标记与该单元格中使用的方向相反的一侧,然后继续循环

1

QBasic,517516字节

RANDOMIZE TIMER
SCREEN 9
INPUT w,h,s
1CLS
IF s=0GOTO 9
x=5*INT(RND*w)
y=5*INT(RND*h)
GOSUB 7
FOR k=1TO s-1
r=INT(RND*4)+1
a=x+5*((r=2)-(r=4))
b=y+5*((r=1)-(r=3))
c=(POINT(a,b+2)*POINT(a+4,b+2)+POINT(a+2,b)*POINT(a+2,b+4))*(0=POINT((a+x)\2+2,(b+y)\2+2))
IF((0=POINT(a+2,b+2))+c)*(a>=0)*(b>=0)*(a<5*w)*(b<5*h)=0GOTO 1
x=a
y=b
GOSUB 7
o=1AND r
p=x-2+3*o-5*(r=2)
q=y+1-3*o-5*(r=1)
u=p+3-o
v=q+2+o
LINE(p,q)-(u,v),7,B
LINE(p+o,q+1-o)-(u-o,v-1+o),1
NEXT
9IF c GOTO 1
END
7LINE(x+1,y+1)-(x+3,y+3),7,B
PSET(x+2,y+2),1
RETURN
  • w,,hs从用户输入中以逗号分隔。
  • 屏幕上显示输出。在程序搜索解决方案时,您可能会看到部分解决方案闪烁。
  • 不使用周期性边界条件。我发现绘制和测试连接管道更加容易,而不必担心一半的管道在网格的一侧,而另一半在网格的另一侧。

这里的方法是在每个步骤尝试随机方向,如果导致无效移动,则从头开始。我们根据确定的方向绘制管道,并POINT根据我们的有效性条件在屏幕上测试点。如果移动没有超出网格的边界,并且:

  1. 移至的单元格为空;要么
    1. 移动到的单元格包含水平或垂直直通的管道,以及
    2. 新管道段不会将现有管道段加倍

就像aditsu的CJam答案一样,这段代码非常慢,如果s占很大一部分,可能会令人麻木w*h。在我的QB64设置上,它会5,5,19很快给出一个答案,但所需的时间却比我等待的时间长5,5,20

如果您想运行更大/更密集的示例,这是我使用深度优先搜索的原始方法。它要高效得多,但要多花300个额外的字节。

RANDOMIZE TIMER
SCREEN 9
INPUT w,h,s
DIM t(s),m(s)
0
FOR z=1TO s
t(z)=-1
NEXT
i=5*INT(RND*w)
j=5*INT(RND*h)
k=1
1CLS
IF s=0GOTO 9
x=i
y=j
GOSUB 7
FOR z=1TO k-1
r=m(z)
GOSUB 6
x=a
y=b
GOSUB 7
o=1AND r
p=x-2+3*o-5*(r=2)
q=y+1-3*o-5*(r=1)
u=p+3-o
v=q+2+o
LINE(p,q)-(u,v),7,B
LINE(p+o,q+1-o)-(u-o,v-1+o),1
NEXT
IF c*(k=s)THEN k=k-1:GOTO 1 ELSE IF k=s GOTO 9
IF k<1GOTO 0
IF t(k)>=0GOTO 4
t(k)=0
f=30
WHILE f
r=INT(RND*4)+1
IF f AND 2^r THEN t(k)=t(k)*5+r:f=f-2^r
WEND
4r=t(k)MOD 5
m(k)=r
t(k)=t(k)\5
GOSUB 6
c=(POINT(a,b+2)*POINT(a+4,b+2)+POINT(a+2,b)*POINT(a+2,b+4))*(0=POINT((a+x)\2+2,(b+y)\2+2))
IF((0=POINT(a+2,b+2))+c)*(a>=0)*(b>=0)*(a<5*w)*(b<5*h)THEN k=k+1 ELSE IF t(k)>0GOTO 4 ELSE t(k)=-1:k=k-1
GOTO 1
6a=x+5*((r=2)-(r=4))
b=y+5*((r=1)-(r=3))
RETURN
7LINE(x+1,y+1)-(x+3,y+3),7,B
PSET(x+2,y+2),1
RETURN
9

输入示例输出10, 10, 100,实际大小:10x10随机管道

这个要点中可以找到更高级的版本。除了无需打扰和彻底注释之外,它还以恒定因子放大输出,并允许在各步骤之间设置一定的延迟,使您能够观看DFS算法的工作情况。这是一个示例运行:

豪华水暖行动

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.