Нескінченні лабіринти


35

Фон

Ви учень потужного майстра, і ваш господар зараз розробляє заклинання для створення міжвимірного лабіринту, щоб захопити своїх ворогів. Він хоче, щоб ви запрограмували його комп’ютер на паровій основі для аналізу можливих макетів. Програмування цієї диявольської машини вкрай небезпечно, тому вам потрібно буде зберегти код якомога коротше.

Вхідні дані

Ваш вхід - це двовимірна сітка періодів .і хесів #, що означають порожній простір і стіни, задані у вигляді рядка з обмеженою лінією. Завжди буде принаймні один .і один #, і ви можете вирішити, чи є новий чистий новий рядок чи ні.

Ця сітка - це план нескінченного лабіринту, який виготовляється шляхом вирівнювання нескінченно багатьох копій сітки один до одного. Лабіринт розділений на порожнини , які з'єднані компонентами порожніх просторів (діагонально суміжні простори не з'єднані). Наприклад, сітка

##.####
...##..
#..#..#
####..#
##...##

призводить до наступного лабіринту (триває нескінченно у всіх напрямках):

##.######.######.####
...##.....##.....##..
#..#..##..#..##..#..#
####..#####..#####..#
##...####...####...##
##.######.######.####
...##.....##.....##..
#..#..##..#..##..#..#
####..#####..#####..#
##...####...####...##
##.######.######.####
...##.....##.....##..
#..#..##..#..##..#..#
####..#####..#####..#
##...####...####...##

Цей конкретний лабіринт містить порожнину нескінченної області. З іншого боку, цей креслення призводить до лабіринту з лише кінцевими порожнинами:

##.####
##..###
####...
..####.
#..####

Вихідні дані

Вихід має бути правдоподібним, якщо лабіринт містить нескінченну порожнину, а помилкове значення - якщо ні. Зауважте, що лабіринт може містити як кінцеву, так і нескінченну порожнини; у цьому випадку результат повинен бути правдоподібним.

Правила

Ви можете написати повну програму або функцію. Виграє найменший кількість байтів, а стандартні лазівки заборонені.

Додаткові випробувальні випадки

Нескінченні порожнини:

.#

#.#
...
#.#

#.###.#.###.#
#.#...#...#.#
#.#.#####.#.#
..#.#...#.#..
###.#.#.#.###
#...#.#.#...#
#.###.#.###.#

##.###
#..###
..##..
###..#
##..##

..#..#..#..#..#..#
.#..#..#..#..#..#.
#..#..#..#..#..#..

#.####.###.###.####
#...#..#...###..###
###.#..#.######..##
....####.#######...
###..###...########
##########.##....##
..###......##.##...
#.........##..#####
###########..###..#
#...........####..#
#.###########.##..#
#.##....##.....####
#.####.###.###.####

Кінцеві порожнини:

###
#.#
###

.#
#.

####
.#..
####

#.#.#
..#..
#####
..#..
#.#.#

#.#.#.#.#.#
..#...#.#..
###.###.###
..#.#......
#.#.#######
#.#.......#
#.#######.#
#.#.....#.#
#.#.#.#.#.#

##....#####
.#..#...##.
.##.#..#...
..###.###..
#..##.#####
#...##....#
#.#.#####.#
###..####.#
....####...
###...#####

###....##.#########
####...##....#...##
..####.#######.###.
....##..........##.
###..#####.#..##...
####..#..#....#..##
..###.####.#.#..##.
..###...#....#.#...
..####..##.###...##
#.####.##..#####.##
####...##.#####..##


###########
........#..
#########.#
..........#
.##########
.#.........
##.########
...#.......

Чи є задні символ нового рядка?
FUZxxl

@FUZxxl Це залежить від вас.
Згарб

Чи може нескінченний лабіринт бути прямою, що йде до нескінченності.

1
@Neil Я не впевнений, що ти маєш на увазі. Перший і другий нескінченні приклади мають нескінченні рядки, але на вході є принаймні один .і один #.
Згарб

1
Приємний виклик, складніше, ніж здається
edc65

Відповіді:


2

JavaScript (ES6), 235 253

Той самий метод, який використовує @mac. Для кожної вільної комірки я пробую рекурсивне заповнення, позначаючи використані комірки координатою, яку я використовую (що може бути за межами шаблону початкових елементів). Якщо під час заповнення я під’їжджаю до комірки, яка вже позначена, має іншу координату, я перебуваю у нескінченному шляху.

Виверткий спосіб обробки по модулю в JS це дуже дратує.

L=g=>(
  g=g.split('\n').map(r=>[...r]),
  w=g[0].length,h=g.length,
  F=(x,y,t=((x%w)+w)%w,u=((y%h)+h)%h,v=g[u][t],k=0+[x,y])=>
    v<'.'?0:v>'.'?v!=k
    :[0,2,-3,5].some(n=>F(x+(n&3)-1,y+(n>>2)),g[u][t]=k),
  g.some((r,y)=>r.some((c,x)=>c=='.'&&F(x,y)))
)

Тест на консолі Firefox / FireBug

Нескінченний

['##.###\n#..###\n..##..\n###..#\n##..##'
,'#.#\n...\n#.#'
,'#.###.#.###.#\n#.#...#...#.#\n#.#.#####.#.#\n..#.#...#.#..\n###.#.#.#.###\n#...#.#.#...#\n#.###.#.###.#'
,'##.###\n#..###\n..##..\n###..#\n##..##'
,'#.####.###.###.####\n#...#..#...###..###\n###.#..#.######..##\n....####.#######...\n###..###...########\n##########.##....##\n..###......##.##...\n#.........##..#####\n###########..###..#\n#...........####..#\n#.###########.##..#\n#.##....##.....####\n#.####.###.###.####'
].forEach(g=>console.log(g,L(g)))

Вихідні дані

"##.###
#..###
..##..
###..#
##..##" true

"#.#
...
#.#" true

"#.###.#.###.#
#.#...#...#.#
#.#.#####.#.#
..#.#...#.#..
###.#.#.#.###
#...#.#.#...#
#.###.#.###.#" true

"##.###
#..###
..##..
###..#
##..##" true

"#.####.###.###.####
#...#..#...###..###
###.#..#.######..##
....####.#######...
###..###...########
##########.##....##
..###......##.##...
#.........##..#####
###########..###..#
#...........####..#
#.###########.##..#
#.##....##.....####
#.####.###.###.####" true

Скінченний

['###\n#.#\n###', '.#\n#.', '####\n.#..\n####'
,'#.#.#\n..#..\n#####\n..#..\n#.#.#'
,'#.#.#.#.#.#\n..#...#.#..\n###.###.###\n..#.#......\n#.#.#######\n#.#.......#\n#.#######.#\n#.#.....#.#\n#.#.#.#.#.#'
,'##....#####\n.#..#...##.\n.##.#..#...\n..###.###..\n#..##.#####\n#...##....#\n#.#.#####.#\n###..####.#\n....####...\n###...#####'
,'###....##.#########\n####...##....#...##\n..####.#######.###.\n....##..........##.\n###..#####.#..##...\n####..#..#....#..##\n..###.####.#.#..##.\n..###...#....#.#...\n..####..##.###...##\n#.####.##..#####.##\n####...##.#####..##'
].forEach(g=>console.log(g,L(g)))

Вихідні дані

"###
#.#
###" false

".#
#." false

"####
.#..
####" false

"#.#.#
..#..
#####
..#..
#.#.#" false

"#.#.#.#.#.#
..#...#.#..
###.###.###
..#.#......
#.#.#######
#.#.......#
#.#######.#
#.#.....#.#
#.#.#.#.#.#" false

"##....#####
.#..#...##.
.##.#..#...
..###.###..
#..##.#####
#...##....#
#.#.#####.#
###..####.#
....####...
###...#####" false

"###....##.#########
####...##....#...##
..####.#######.###.
....##..........##.
###..#####.#..##...
####..#..#....#..##
..###.####.#.#..##.
..###...#....#.#...
..####..##.###...##
#.####.##..#####.##
####...##.#####..##" false

Так, дафтовий модуль був болем і в C #, але я думаю, що я знайшов спосіб добре використати його в своїй робочій копії з кодом спрямування (я повторно публікую повідомлення лише тоді, коли зможу отримати 10% зменшення або краще): (j%4-1)%2дає приємний повторюваний зразок.
VisualMelon

Я вважаю, що неназвані функції є допустимими, і, отже, якщо функція не включає виклик до себе (здавалося б, не), допустимо не вважати кількість L=байтів.
SuperJedi224

@ SuperJedi224 ви, мабуть, праві, але це досить коротко, як це врешті
edc65

21

C # - 423 375 байт

Повна програма C #, приймає введення через STDIN, виводить "True" або "False" в STDOUT, якщо це необхідно.

Мені не вдалося залишити ту Лінку там ... на щастя, її видалення окупилося! Тепер він відслідковує побачені та відвідувані клітини в масиві (враховуючи, що так чи інакше, вони все одно переглядають кінцеву кількість). Я також переписав код спрямованості, усунувши потребу в лямбда і взагалі зробивши код більш неможливим для розуміння (але з істотною економією байтів).

using C=System.Console;struct P{int x,y;static void Main(){int w=0,W,k=0,o,i,j;P t;string D="",L;for(;(L=C.ReadLine())!=null;D+=L)w=L.Length;for(i=W=D.Length;i-->0&k<W;){k=1;P[]F=new P[W];for(F[j=0].x=i%w+W*W,F[0].y=i/w+W*W;D[i]>35&j<k;)for(t=F[j++],o=1;o<5&k<W;t.y+=(o++&2)-1){t.x+=o&2;if(D[--t.x%w+t.y%(W/w)*w]>35&System.Array.IndexOf(F,t)<0)F[k++]=t;}}C.WriteLine(k>=W);}}

Це пошук на ширину (не що це має значення), який просто триває, поки він або не застрягне в кінцевій печері, або не вирішить, що печера є достатньо великою, що вона повинна бути нескінченно великою (коли в ній стільки клітин, скільки оригінальний прямокутник, це означає, що має бути шлях від однієї клітини до себе десь ще, яку ми можемо продовжувати слідувати назавжди).

Небезпечний код:

using C=System.Console;

struct P
{
    int x,y;

    static void Main()
    {
        int w=0, // w is the width
        W, // W is the length of the whole thing
        k=0, // k is visited count
        o, // o is offset, or something (gives -1,0 0,-1 +1,0 0,+1 t offset pattern)
        i, // i is the start cell we are checking currently
        j; // j is the F index of the cell we are looking at

        P t; // t is the cell at offset from the cell we are looking at

        string D="", // D is the map
        L;

        for(;(L=C.ReadLine())!=null; // read a line, while we can
            D+=L) // add the line to the map
            w=L.Length; // record the width

        for(i=W=D.Length;i-->0&k<W;) // for each cell
        {
            k=1;

            P[]F=new P[W]; // F is the list of visited cells,

            for(F[j=0].x=i%w+W*W,F[0].y=i/w+W*W; // there are reasons (broken modulo)
                D[i]>35&j<k;) // for each cell we've visited, until we've run out
                for(t=F[j++], // get the current cell
                    o=1; // o is just a counter which we use to kick t about
                    o<5& // 4 counts
                    k<W; // make sure we havn't filled F
                    t.y+=(o++&2)-1) // kick and nudge y, inc o
                {
                    t.x+=o&2; // kick x
                    if(D[--t.x%w+t.y%(W/w)*w]>35 // nudge x, it's a dot
                       &System.Array.IndexOf(F,t)<0) // and we've not seen it before
                        F[k++]=t; // then add it
                }
        }

        C.WriteLine(k>=W); // result is whether we visited lots of cells
    }
}

1
Напевно, я вперше побачив C#відповідь як найкращий одержувач голосів тут.
Майкл Макгріф

1
Головна () у структурі, тепер це мило.
PTwr

10

Python 2 - 258 210 244 байт

Рекурсивно перевіряйте контури, якщо стек переповнення return 1 (truthy) else return None (фальси).

import sys
def k(s):
 a=len(s);m=[[c=='.'for c in b]*999for b in s.split('\n')]*999;sys.setrecursionlimit(a)
 for x in range(a*a):
  try:p(m,x/a,x%a)
  except:return 1
def p(m,x,y):
 if m[x][y]:m[x][y]=0;map(p,[m]*4,[x,x,x+1,x-1],[y+1,y-1,y,y])

1
Ви можете зберегти деякі байти, скориставшись ;рядками в p, так як ви отримаєте їх у тому ж рядку з if.
PurkkaKoodari

11
"Якщо переповнення стека повернеться справжнім" - мені подобається, що стан рекурсії закінчується :)
schnaader

3
Я не переконаний, що це правильний підхід. Використання переповнення стека для виявлення "нескінченної" області призведе до помилкових позитивних результатів. Специфікація проблеми не містить жодних обмежень на діапазони введення, але щось на зразок лабіринту 300x300 не здається необґрунтованим і може містити дуже довгі обмежені шляху.
JohnE

4
Майже всі кінцеві лабіринти також спричинили б переповнення стека. Це не дійсна програма.
PyRulez

@johne Оновлено, щоб межа рекурсії була в порядку порядку розмірів лабіринтів. Додано 34 байти, на жаль, але це має бути правильним зараз (принаймні, таким же правильним, як і хак, як це може бути).
Кайл Гулліон

5

Python 2 - 297 286 275 байт

Вибирає довільну "відкриту" клітинку, щоб почати заливку. Лабіринт нескінченний, якщо під час заповнення ми повторно відвідуємо осередок, який ми вже відвідали, але він має іншу координату до попереднього відвідування. Якщо заливна заливка заповнює весь регіон, не знаходячи такої комірки, спробуйте інший регіон. Якщо такої області неможливо знайти, лабіринт є кінцевим.

Знімає файл для обробки в командному рядку, повертає вихідний код 1нескінченно та 0нескінченно.

Повертає правильні результати для всіх тестових випадків.

import sys
e=enumerate
C=dict([((i,j),1)for i,l in e(open(sys.argv[1]))for j,k in e(l)if'.'==k])
while C:
 d={}
 def f(r,c):
  n=(r%(i+1),c%j)
  if n in d:return(r,c)!=d[n]
  if C.pop(n,0):d[n]=(r,c);return any(map(f,[r-1,r,r+1,r],[c,c+1,c,c-1]))
 if f(*C.keys()[0]):exit(1)

1
Ви не можете припустити, що якась клітина буде членом нескінченної печери, ви можете легко мати як нескінченні, так і кінцеві печери.
VisualMelon

2
@VisualMelon: вибачте, опис не зовсім правильний. Код фактично перевіряє всі можливі області взаємопов'язаних комірок, а не лише одну (як це зараз мається на увазі). Ось для чого і завершальний цикл - вибір регіонів для перевірки, поки залишилися незафіксовані комірки.
Мак
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.