Створіть багаторівневий лабіринт 5х5х5 лише одним рішенням


11

Мета цього завдання - створити найкоротший код (у символах), який успішно виконує наступні дії:

Технічні умови :

  • Потрібно створити 5x5x5 labyrinthточно 1 possible solution(не більше, не менше)
  • Лабіринт повинен бути створений randomly Він повинен бути здатний генерувати кожне існуюче рішення, якщо його працювати протягом років
  • startІ finishповинні бути поміщені в*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]]

Вихідні примітки:

  • Використання 0для emptyі 1дляsquares

  • Лінії розриву НЕ потрібні

  • Ви вирішуєте, що indexє, але просто обов’язково це добре поясніть


* Ось приклад того, що я маю на увазі під протилежними кутами:

введіть тут опис зображення

Роз'яснення :

  • Може НЕ рухатися вdiagonal
  • Може НЕ проходити двічі по тому ж шляху
  • Маючи inaccessible areasдозволено
  • Можна go up/downбільше ніж один рівень поспіль

Поради:

  • Не бачте їх як стіни, натомість бачте їх як 5x5x5купу квадратів, яких деякі з них відсутні, і ви можете пройти через відсутні

Якщо щось незрозуміло, просто запитайте мене
ajax333221

3
Однак є одна деталь, яку я хотів би уточнити: чи стіни розміщуються між квадратами, чи стіна заповнює цілий квадрат?
Ільмарі Каронен

1
ви говорите 5x5 (двовимірний масив) у кількох місцях, проте зразки коду та зображення пропонують 5x5x5 (3D-масив). Я припускаю, що це мається на увазі 3D-масив?
Kae Verens

1
як вирішено, що рішення - дійсний лабіринт? Я маю на увазі, чи є кількість відростків правильним шляхом? це щось стосується відношення 1s до 0s?
Kae Verens

2
Коли ви говорите "Лабіринт повинен бути створений випадковим чином", які обмеження ми повинні робити? Я припускаю, наприклад, що ви не маєте наміру дозволити програму, яка вибирає між двома жорстко кодованими виходами навмання, як це дослівно читає правила, які зараз є.
Пітер Тейлор

Відповіді:


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

До показаного коду я додав нові рядки та відступи для читабельності.


Я думаю, що ти виграєш цього ;-) немає ніякого способу я міг би так скоротити шахту
Kae Verens

Мені дуже сподобалося змагання :-) Я трохи здивований, що ми все ще залишаємося єдиними відповідями. Я очікував, що сценарій з гольфу чи подібне вже било нас обох.
Sir_Lagsalot

Так чи інакше, простий шлях, що не має вил або вузлів рішення, не здається справжнім лабіринту. Спробуйте додати кілька сліпих алей.
DavidC

@David Carraher Алгоритм генерує тупики та шляхи розгалуження, як показано у зразку. Не дозволяючи новій точці з'єднати дві вже існуючі гілки, просто перешкоджає численним рішенням або циклам у лабіринті.
Sir_Lagsalot

@Sir_Lagsalot Дякую за уточнення
DavidC

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, окрім ініціатора), поки не буде більше можливі доповнення.

якщо будь-який новий 0 знаходиться поруч із точкою виходу (x * y * z == 48), ми відкриваємо вихід.

гольф

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

Математика: Справжній лабіринт (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

Ось той самий лабіринт, вставлений у 5х5х5 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 char, Створено шлях, але не справжній лабіринт чи лабіринт)

Уявіть собі великий твердий куб розміром 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

Я не надто знайомий з matlab, але чи можете ви зробити щось на кшталт FindShortestPath, додати зміщення проти кожного вузла найкоротшим шляхом, а потім знову запустити FindShortestPath з урахуванням зміщення, щоб уникнути вузлів у найкоротшому рішенні? Це можна зробити ітераційно. Мені було б цікаво подивитися, який тип шляху буде виробляти.
Sir_Lagsalot

@Sir_Lagsalot Я опублікував це як запитання до групи Mathematica SE ( mathematica.stackexchange.com/questions/4084/… )
DavidC
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.