仅用一个解决方案创建一个多级5x5x5迷宫


11

这项挑战的目的是创建最短的代码(以字符为单位),以成功执行以下操作:

规格

  • 必须5x5x5 labyrinth精确地创建一个1 possible solution(不多不少)
  • 必须创建迷宫 randomly 如果运行多年,它必须能够生成每个现有解决方案
  • startfinish必须放在*opposite corners
  • 地图output必须采用以下格式之一:

选项输出格式1 strings, printed or alerted

xxxxx,xxxxx,xxxxx,xxxxx,xxxxx/
xxxxx,xxxxx,xxxxx,xxxxx,xxxxx/
xxxxx,xxxxx,xxxxx,xxxxx,xxxxx/
xxxxx,xxxxx,xxxxx,xxxxx,xxxxx/
xxxxx,xxxxx,xxxxx,xxxxx,xxxxx

选项输出格式2 arrays

[[xxxxx,xxxxx,xxxxx,xxxxx,xxxxx],
[xxxxx,xxxxx,xxxxx,xxxxx,xxxxx],
[xxxxx,xxxxx,xxxxx,xxxxx,xxxxx],
[xxxxx,xxxxx,xxxxx,xxxxx,xxxxx],
[xxxxx,xxxxx,xxxxx,xxxxx,xxxxx]]

输出说明:

  • 使用0empty1用于squares

  • 换行是不是必要的

  • 您决定什么index是什么,但请务必将其解释清楚


*以下是我在相反的角落所指的例子:

在此处输入图片说明

说明

  • 动的diagonal
  • 相同的路径上通过两次
  • inaccessible areas被允许
  • 您可以go up/down连续超过一个级别

提示:

  • 不要将它们视为墙,而应将它们视为5x5x5一堆正方形,其中一些缺失,您可以遍历缺失的正方形

如果不清楚,请问我:)
ajax333221 2012年

3
但是,我想澄清一个细节:墙是放置正方形之间还是墙填充整个正方形?
Ilmari Karonen 2012年

1
您在几个地方说了5x5(一个2D阵列),但是代码示例和图像建议使用5x5x5(一个3D阵列)。我认为3D阵列是什么意思?
Kae Verens 2012年

1
如何确定解决方案是有效的迷宫?我的意思是,正确路径的分支数量是多少?1s与0s的比率有关吗?
Kae Verens 2012年

2
当您说“迷宫必须随机创建”时,我们应该推断出哪些限制?例如,我假设您不打算像目前对规则的字面读取那样,允许一个程序在两个硬编码输出之间随机选择。
彼得·泰勒

Answers:


10

C ++ C,约1000 670 643 395 297 248个字符

样本输出:

00111,10011,10111,00110,11000,
11001,01010,00100,11011,10101,
10111,10101,10001,01010,00101,
11001,11110,11100,11110,10101,
11100,10010,11001,10101,00000,

工作原理:该程序使用Brownian Motion生成解决方案。设定起点。然后,选择一个随机点并重复随机移动,直到它碰到开始分支上的一个且只有一个点。然后设置该点,如果它也触及终点,程序将退出并显示矩阵。由于没有点可以连接两个分支,因此只有一条通过迷宫的路径。该程序使用rand函数和一个命令行整数参数作为种子,因此,有了足够的rand函数,最终应该可以生成所有有效的迷宫(但是该算法不会创建未连接的区域,因此不会生成所有可能的迷宫)。

布朗运动被丢弃,因为事实证明这是不需要的,并且将其删除可大大简化代码。我确实认为它使迷宫效果更好。同样,由于没有状态随机数生成器比使用128位种子更有意义,因此删除了种子参数。

程序有可能陷入无限循环,因为添加到分支的任何点都可能创建多个路径的情况。这是可以解决的,但是我认为很少有人会成为代码高尔夫球的关注者。

#define M m[*p+1][p[1]][p[2]]
#define F(a,b)for(p[a]=5;p[a]--;putchar(b))
#define f for(i=3;i--;p[i]
p[]={4,4,4},h[3],m[7][6][6]={1};
main(i){
    for(M=2;h[1]^1||(M=1)^h[2];){
        f=rand()%5)
            h[i]=0;
        f++)
            p[i]++,
            h[M]++,
            p[i]-=2,
            h[M]++;
    }
    F(0,10)
        F(1,44)
            F(2,48+!M);
}

我为显示的代码添加了换行符和缩进以提高可读性。


我认为您赢了这一

我真的很喜欢比赛:-)我很惊讶我们仍然是唯一的答案,我希望到目前为止,一位高尔夫球手或类似的手风琴能打败我们。
Sir_Lagsalot 2012年

不知何故,没有分叉或决策节点的简单路径似乎并没有资格成为真正的迷宫。尝试添加一些盲目的小巷。
DavidC 2012年

@David Carraher该算法确实生成了死端和分支路径,如示例中所示。不允许新点连接两个已经存在的分支,只会阻止迷宫中的多个解决方案或循环。
Sir_Lagsalot

@Sir_Lagsalot感谢您的澄清
DavidC 2012年

5

JavaScript中,874个 816 788 686 682 668 637字符

样本输出:

00000,10111,10111,01010,11000
01011,01000,01010,01111,00011
00100,11010,00111,10111,11010
01111,10001,01110,01010,01000
00000,11110,00001,10101,10110

该选项的工作方式是从[0,0,0]点开始,并在允许的任意位置0旁边随机添加一个附加的0(允许==新的0除了始发者之外,不与其他任何0相邻),直到不再存在为止可能的增加。

如果出口点(x * y * z == 48)旁边有任何新的0,则我们打开出口。

打高尔夫球

b=[]
I=Math.random
for(i=5;i--;)for(j=5,b[i]=[];j--;)b[i][j]=[1,1,1,1,1]
b[0][0][0]=0
k=[[0,0,0]]
function q(x,y,z){J=b[x]
if(x<0||y<0||z<0||x>4||y>4||z>4||!J[y][z])return 
n=6-!x||b[x-1][y][z]
n-=!y||J[y-1][z]
n-=!z||J[y][z-1]
n-=x==4||b[x+1][y][z]
n-=y==4||J[y+1][z]
n-=z==4||J[y][z+1]
n==1&&v.push([x,y,z])}while(I){F=k.length
B=k[C=0|I(v=[])*F]
x=B[0]
q(x-1,y=B[1],z=B[2])
q(x,y-1,z)
q(x,y,z-1)
q(x+1,y,z)
q(x,y+1,z)
q(x,y,z+1)
if(D=v.length){k.push(A=v[0|I()*D])
b[A[0]][A[1]][A[2]]=0
if(A[0]*A[1]*A[2]==48)b[4][4][4]=I=0}else{for(E=[];F--;)F^C&&E.push(k[F])
k=E}}for(i=25;i--;)b[H=0|i/5][i%5]=b[H][i%5].join('')
alert(b.join("\n"))

原版的

window.map=[];
for (i=0;i<5;++i) {
  map[i]=[];
  for (j=0;j<5;++j) {
    map[i][j]=[1,1,1,1,1];
  } 
} 
points=[[0,0,0]];
map[0][0][0]=0;
function spaces(x,y,z) {
  var n=6;
  if (x<0 || y<0 || z<0) return 0;
  if (x>4 || y>4 || z>4) return 0;
  if (!map[x][y][z]) return 0;
  if (!x || map[x-1][y][z]) n--;
  if (!y || map[x][y-1][z]) n--;
  if (!z || map[x][y][z-1]) n--;
  if (x==4 || map[x+1][y][z]) n--;
  if (y==4 || map[x][y+1][z]) n--;
  if (z==4 || map[x][y][z+1]) n--;
  return n;
} 
do {
  var index=Math.floor(Math.random()*points.length);
  point=points[index];
  v=[];
  x=point[0];
  y=point[1];
  z=point[2];
  spaces(x-1,y,z)==1 && v.push([x-1,y,z]);
  spaces(x,y-1,z)==1 && v.push([x,y-1,z]);
  spaces(x,y,z-1)==1 && v.push([x,y,z-1]);
  spaces(x+1,y,z)==1 && v.push([x+1,y,z]);
  spaces(x,y+1,z)==1 && v.push([x,y+1,z]);
  spaces(x,y,z+1)==1 && v.push([x,y,z+1]);
  if (v.length) {
    var point=v[Math.floor(Math.random()*v.length)];
    points.push(point);
    map[point[0]][point[1]][point[2]]=0;
    if (point[0]*point[1]*point[2]==48) {
      map[4][4][4]=0;
    } 
  } 
  else {
    var np=[];
    for (var i=0;i<points.length;++i) {
      i!=index && np.push(points[i]); 
    } 
    points=np;
  } 
} while(points.length);
for (i=0;i<5;++i) {
  for (j=0;j<5;++j) {
    map[i][j]=map[i][j].join('');
  } 
  map[i]=map[i].join();
} 
alert(map.join("\n"));

4

Mathematica:真正的迷宫(827个字符)

最初,我产生了从{1,1,1}到{5,5,5}的路径,但是由于不可能进行错误的转弯,我引入了分叉或“决策点”(度数顶点> 2),其中一个人需要决定走哪条路。结果是真正的迷宫或迷宫。

解决“盲巷”要比找到一条简单直接的道路更具挑战性。最具挑战性的事情是消除路径内的循环,同时允许解决方案路径外的循环。

以下两行代码仅用于呈现绘制的图形,因此该代码不计算在内,因为该解决方案未使用该代码。

o = Sequence[VertexLabels -> "Name", ImagePadding -> 10, GraphHighlightStyle -> "Thick", 
    ImageSize -> 600];

o2 = Sequence[ImagePadding -> 10, GraphHighlightStyle -> "Thick", ImageSize -> 600];

使用的代码:

e[c_] := Cases[EdgeList[GridGraph[ConstantArray[5, 3]]], j_ \[UndirectedEdge] k_ /; (MemberQ[c, j] && MemberQ[c, k])]

m[] :=
Module[{d = 5, v = {1, 125}},
   While[\[Not] MatchQ[FindShortestPath[Graph[e[v]], 1, 125], {1, __, 125}],

v = Join[v, RandomSample[Complement[Range[125], v], 1]]];
   Graph[e[Select[ConnectedComponents[Graph[e[v]]], MemberQ[#, 1] &][[1]]]]]

w[gr_, p_] := EdgeDelete[gr, EdgeList[PathGraph[p]]]

y[p_, u_] := Select[Intersection[#, p] & /@ ConnectedComponents[u], Length[#] > 1 &]

g = HighlightGraph[lab = m[],  PathGraph[s = FindShortestPath[lab, 1, 125]],o]
u = w[g, s]
q = y[s, u]

While[y[s, u] != {}, u =  EdgeDelete[u, Take[FindShortestPath[u,  q[[1, r = RandomInteger[Length@q[[1]] - 2] + 1]], 
  q[[1, r + 1]]], 2] /. {{a_, b_} :> a \[UndirectedEdge] b}];

q = y[s, u]]

g = EdgeAdd[u, EdgeList@PathGraph[s]];

Partition[StringJoin /@ Partition[ReplacePart[Table["x", {125}], 
Transpose[{VertexList[g], Table["o", {Length[VertexList@g]}]}]/. {{a_, b_} :>  a -> b}], {5}], 5]

样品输出

{{“ oxooo”,“ xxooo”,“ xoxxo”,“ xoxxo”,“ xxoox”},{“ ooxoo”,“ xoooo”,“ ooxox”,“ oooxx”,“ xooxx”},{“ oooxx”, “ ooxxo”,“ ooxox”,“ xoxoo”,“ xxxoo”},{“ oxxxx”,“ oooox”,“ xooox”,“ xoxxx”,“ oooxx”},{“ xxxxx”,“ ooxox”,“ oooox “,” xoxoo“,” oooxo“}}

引擎盖下

下图显示了与({{"ooxoo",...}}上面显示的解决方案相对应的迷宫或迷宫:

解决方案1

这是插入5x5x5中的相同迷宫GridGraph。编号的顶点是迷宫中最短路径上的节点。请注意位于34、64和114的分叉或决策点。即使它不是解决方案的一部分,我也将包括用于渲染图形的代码:

HighlightGraph[gg = GridGraph[ConstantArray[5, 3]], g,  
 GraphHighlightStyle ->"DehighlightFade", 
 VertexLabels -> Rule @@@ Transpose[{s, s}] ]

解决方案2

此图仅显示迷宫的解决方案:

HighlightGraph[gg = GridGraph[ConstantArray[5, 3]], 
   Join[s, e[s]], GraphHighlightStyle -> "DehighlightFade", VertexLabels -> Rule @@@    Transpose[{s, s}] ]

解决方案3

最后,一些定义可能有助于阅读代码:

定义


原始解决方案(432个字符,产生了一条路径,但不是真正的迷宫或迷宫)

想象一个由不同的单位立方体组成的5x5x5大型实心立方体。以下内容从{1,1,1}和{5,5,5}的单位立方开始,因为我们知道它们必须是解决方案的一部分。然后,它将删除随机立方体,直到从{1,1,1}到{5,5,5}的路径畅通无阻为止。

给定已删除的单位立方体,“迷宫”是最短的路径(如果可能的话)。

d=5
v={1,d^3}
edges[g_,c_]:=Cases[g,j_\[UndirectedEdge] k_/;(MemberQ[c,j]&&MemberQ[c,k])]

g:=Graph[v,edges[EdgeList[GridGraph[ConstantArray[d,d]]],v]];

While[\[Not]FindShortestPath[g,1,d^3]!={},
    v=Join[v,RandomSample[Complement[Range[d^3],v],1]]]

Partition[Partition[ReplacePart[
   Table["x",{d^3}],Transpose[{FindShortestPath[g,1,d^3],Table["o",{Length[s]}]}]
      /.{{a_,b_}:>  a->b}],{d}]/.{a_,b_,c_,d_,e_}:>  StringJoin[a,b,c,d,e],5]

例:

{{"ooxxx", "xxxxx", "xxxxx", "xxxxx", "xxxxx"}, 
 {"xoxxx", "xoooo", "xxxxo", "xxxxo", "xxxxo"}, 
 {"xxxxx", "xxxxx", "xxxxx", "xxxxx", "xxxxo"}, 
 {"xxxxx", "xxxxx", "xxxxx", "xxxxx", "xxxxo"}, 
 {"xxxxx", "xxxxx", "xxxxx", "xxxxx", "xxxxo"}}

从技术上讲,这还不是真正的迷宫,因为不会出现任何错误的转弯。但是我认为这很有趣,因为它依赖于图论。

该例程实际上使人迷宫,但我堵塞了所有可能引起周期的空白位置。如果我找到消除循环的方法,则将在此处包含该代码。


很好的更新,我喜欢您更新的解决方案允许在非解决方案路径上循环,这使迷宫变得更加混乱。
Sir_Lagsalot

谢谢。我仍然希望解决方案路径本身更可能不时偏离最终节点。目前不鼓励使用(但不能完全阻止)FindShortestPath
DavidC 2012年

我对matlab不太熟悉,但是您可以做类似FindShortestPath的事情,对最短路径中的每个节点添加偏见,然后再次考虑到该偏见再次运行FindShortestPath,这样它将避免使用最短解决方案中的节点?这也可以迭代完成。我很想知道会产生哪种类型的路径。
Sir_Lagsalot

@Sir_Lagsalot我张贴以此为这里的数学SE组问题(mathematica.stackexchange.com/questions/4084/...
DavidC
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.