Tek bir çözümle çok seviyeli 5x5x5 Labirent oluşturun


11

Bu zorluğun amacı, aşağıdakileri başarıyla yapan en kısa kodu (karakterlerle) oluşturmaktır:

Özellikler :

  • 5x5x5 labyrinthTam olarak bir tane oluşturmalıdır 1 possible solution(daha fazla, daha az değil)
  • Labirent yaratılmalı randomly Yıllarca çalışır durumda kalırsa mevcut her çözümü üretebilmelidir.
  • startVe finishyerleştirilmelidir*opposite corners
  • Harita outputaşağıdaki biçimlerden birinde olmalıdır:

Seçenek çıkış biçimi 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

Seçenek çıkış biçimi 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]]

Çıktı Notları:

  • 0İçin emptyve 1için kullanınsquares

  • Kesme çizgileri gerekli DEĞİLDİR

  • Ne olduğuna karar veriyorsunuz index, ama iyi açıkladığınızdan emin olun


* İşte karşıt köşelerle ne demek istediğimin bir örneği:

resim açıklamasını buraya girin

Açıklamalar :

  • Can DEĞİL hareketdiagonal
  • Can DEĞİL aynı yolda iki kez geçmesi
  • Sonra inaccessible areasizin verilir
  • go up/downArka arkaya birden fazla seviye yapabilirsiniz

İpuçları:

  • Onları duvar olarak görmeyin, bunun yerine 5x5x5bazılarının eksik olduğu bir kareler yığını olarak görün ve eksik olanlardan geçebilirsiniz.

Bir şey net değilse, bana sorun :)
ajax333221

3
Bununla birlikte, açıklığa kavuşturmak istediğim bir ayrıntı var: duvarlar kareler arasına mı yerleştirilmiş , yoksa bir duvar tüm kareyi dolduruyor mu?
Ilmari Karonen

1
birkaç yerde 5x5 (bir 2D dizi) diyorsunuz, ancak kod örnekleri ve görüntü 5x5x5 (bir 3D dizi) öneriyor. 3D dizinin ne anlama geldiğini varsayıyorum?
Kae Verens

1
çözümün geçerli bir labirent olduğuna nasıl karar verilir? Yani, doğru yolun sahip olduğu sürgünlerin sayısı mı? 1'lerin 0'lara oranı ile ilgili bir şey mi var?
Kae Verens

2
"Labirent rastgele oluşturulmalı" derken, hangi sınırlamaları çıkarmalıyız? Örneğin, şu anda kuralların gerçek anlamda okunması gibi, iki sabit kodlu çıktı arasında rasgele seçilen bir programa izin vermek istemediğinizi varsayıyorum.
Peter Taylor

Yanıtlar:


10

C ++ C 1000 670 643 395 297 248 karakter

Örnek çıktı:

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,

Nasıl çalışır: Program, çözümler üretmek için Brownian Motion'ı kullanır . Başlangıç ​​noktası ayarlanmıştır. Daha sonra, rastgele bir nokta seçilir ve başlangıç ​​dalında bir ve sadece bir noktaya değene kadar rastgele tekrar tekrar hareket ettirilir . Nokta daha sonra ayarlanır ve bitiş noktasına da dokunursa, program çıkar ve matris görüntülenir. Hiçbir nokta iki dala katılamayacağından, labirentte sadece bir yol vardır. Program, rand işlevini ve bir komut satırı tamsayı bağımsız değişkenini tohum olarak kullanır, bu nedenle yeterli bir rand işleviyle sonunda tüm geçerli labirentleri oluşturmak mümkün olmalıdır (ancak bu algoritma bağlı olmayan alanlar oluşturmaz, bu nedenle tümünü oluşturmaz) olası labirentler).

Brownian hareketi gereksiz olduğu ortaya çıktı ve kaldırılması kodu önemli ölçüde basitleştirdi. Gerçi güzel labirentler yaptığını düşünüyorum. Aynı şekilde, vatansız rasgele sayı üretecine ihtiyaç duyulması benim için 128 bitlik bir tohumdan daha mantıklı olduğu için tohum argümanı bırakıldı.

Dallara eklenen herhangi bir noktanın birden çok yol oluşturacağı durumlar için mümkün olduğu için, programın sonsuz bir döngüde sıkışması mümkündür. Bu düzeltilebilir, ancak kod golf için bir endişe olmayacak kadar nadir olduğunu düşünüyorum.

#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);
}

Görüntülenebilir kod için okunabilirlik için yeni satırlar ve girinti ekledim.


Bu seferki kazanacak mı ;-) O kadar mayın küçültmek hiçbir yolu yoktur
Kae Verens

Rekabetten gerçekten keyif aldım :-) Hala tek cevap olduğumuz için biraz şaşırdım, bir golf scripter ya da benzeri bir beklenti bizi ikimiz de yendi.
Sir_Lagsalot

Her nasılsa, çatalları veya karar düğümleri olmayan basit bir yol, gerçek bir labirent olarak nitelendirilemez. Bazı kör sokaklar eklemeyi deneyin.
DavidC

@David Carraher Algoritma, örnekte gösterildiği gibi çıkıntılar ve dallanma yolları oluşturur. Yeni bir noktanın zaten var olan iki dalı birleştirmesine izin vermemek, labirentte birden fazla çözümü veya döngüyü önler.
Sir_Lagsalot

Açıklama @Sir_Lagsalot teşekkürler
DavidC

5

JavaScript, 874 816 788 686 682 668 637 karakter

örnek çıktı:

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

bu, [0,0,0] noktasından başlayarak ve izin verilen her yerde 0'ın yanına bir tane daha 0 ekleyerek rastgele çalışır (izin verilen == yeni 0, gönderen hariç diğer 0'ların yanında değildir) olası eklemeler.

çıkış noktasının yanında yeni bir 0 varsa (x * y * z == 48) çıkışı açarız.

golfed

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"))

orijinal

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: Gerçek Labirent (827 karakter)

Başlangıçta, {1,1,1} 'den {5,5,5}' e bir yol ürettim, ancak yapılması gereken yanlış dönüşler olmadığı için çatalları veya "karar noktalarını" (derece 2> köşeleri) kişinin hangi yöne gideceğine karar vermesi gerekir. Sonuç gerçek bir labirent veya labirenttir.

"Kör sokakları" çözmek basit, doğrudan bir yol bulmaktan çok daha zordu. En zorlu şey, çözüm yolundaki döngülere izin verirken yol içindeki döngüleri ortadan kaldırmaktı.

Aşağıdaki iki kod satırı yalnızca çizilen grafikleri oluşturmak için kullanılır, bu nedenle çözümde kullanılmadığından kod sayılmaz.

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

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

Kullanılan kod:

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]

Örnek çıktı

{{"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 "}}

Kaputun altında

Aşağıdaki resim, ({{"ooxoo",...}}yukarıda görüntülenen çözüme karşılık gelen labirent veya labirenti gösterir :

Solution1

İşte aynı labirent, 5x5x5'e yerleştirildi GridGraph. Numaralı köşeler, labirentten en kısa yoldaki düğümlerdir. Çatalları veya karar noktalarını 34, 64 ve 114'te not edin. Çözümün bir parçası olmasa bile grafiği oluşturmak için kullanılan kodu ekleyeceğim:

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

solution2

Ve bu grafik sadece labirentin çözümünü gösterir:

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

solution3

Son olarak, kodun okunmasına yardımcı olabilecek bazı tanımlar:

tanımlar


Orijinal çözüm (432 karakter, Bir yol oluşturdu, ancak gerçek bir labirent veya labirent değil)

Farklı birim küplerden oluşan 5x5x5 büyüklüğünde bir katı küp düşünün. Aşağıdakiler, çözümün bir parçası olması gerektiğini bildiğimiz için {1,1,1} ve {5,5,5} 'de birim küpler olmadan başlar. Daha sonra {1,1,1} 'den {5,5,5}' e engelsiz bir yol olana kadar rastgele küpleri kaldırır.

"Labirent", kaldırılmış birim küpler göz önüne alındığında en kısa yoldur (birden fazla mümkünse).

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]

Misal:

{{"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"}}

Teknik olarak bu henüz gerçek bir labirent değildir, çünkü kişinin yapabileceği yanlış dönüşler yoktur. Ama grafik teorisine dayandığından ilginç bir başlangıç ​​olarak düşündüm.

Rutin aslında bir labirent yapar ama döngülere neden olabilecek tüm boş yerleri tıkadım. Döngüler kaldırmanın bir yolunu bulursam bu kodu buraya ekleyeceğim.


Güzel güncelleme, güncellenmiş çözümünüzün çözüm olmayan yollarda döngülere izin vermesini seviyorum, daha kafa karıştırıcı bir labirent yapıyor.
Sir_Lagsalot

Teşekkürler. Çözüm yolunun zaman zaman son düğümden uzaklaşma olasılığının daha yüksek olmasını istiyorum. Bu şu anda cesaretini kırıyor (ama tam olarak engellenmiyor) FindShortestPath.
DavidC

Matlab'a çok aşina değilim, ancak FindShortestPath gibi bir şey yapabilir, en kısa yolda her düğüme karşı bir önyargı ekleyebilir ve daha sonra en kısa çözümdeki düğümlerden kaçınacak şekilde önyargıyı dikkate alarak FindShortestPath'i tekrar çalıştırabilir misiniz? Bu yinelemeli olarak da yapılabilir. Ne tür bir yol üreteceğini görmek isterim.
Sir_Lagsalot

@Sir_Lagsalot Bunu burada Mathematica SE grubu için bir soru olarak gönderdim ( mathematica.stackexchange.com/questions/4084/… )
DavidC
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.