Labirinti infiniti


35

sfondo

Sei l'apprendista di un potente mago e il tuo padrone sta attualmente sviluppando un incantesimo per creare un labirinto interdimensionale in cui intrappolare i suoi nemici. Vuole che tu programmi il suo computer a vapore per analizzare i possibili layout. La programmazione di questa diabolica macchina è estremamente pericolosa, quindi ti consigliamo di mantenere il codice il più breve possibile.

Ingresso

Il tuo input è una griglia bidimensionale di punti .e hash #, che significa spazio vuoto e muri, dato come una stringa delimitata da una nuova riga. Ce ne saranno sempre almeno uno .e uno #e potrai decidere se esiste una nuova riga finale o meno.

Questa griglia è il modello di un labirinto infinito, che viene realizzato allineando infinitamente copie della griglia una accanto all'altra. Il labirinto è diviso in cavità , che sono componenti collegati di spazi vuoti (gli spazi diagonalmente adiacenti non sono collegati). Ad esempio, la griglia

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

risulta nel seguente labirinto (continuato all'infinito in tutte le direzioni):

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

Questo particolare labirinto contiene una cavità di area infinita. D'altra parte, questo progetto si traduce in un labirinto con solo cavità finite:

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

Produzione

La tua produzione deve essere un valore veritiero se il labirinto contiene una cavità infinita e un valore falso in caso contrario. Si noti che il labirinto può contenere sia cavità finite che infinite; in tal caso, l'output deve essere veritiero.

Regole

È possibile scrivere un programma completo o una funzione. Vince il conteggio di byte più basso e non sono consentite scappatoie standard.

Casi di prova aggiuntivi

Cavità infinite:

.#

#.#
...
#.#

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

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

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

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

Cavità finite:

###
#.#
###

.#
#.

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

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

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

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

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


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

Esiste un personaggio newline finale?
FUZxxl

@FUZxxl Dipende da te.
Zgarb,

L'infinito labirinto può essere una linea retta che va all'infinito?

1
@Neil non sono sicuro di cosa intendi. Il primo e il secondo esempio infinito hanno linee infinite, ma ce n'è almeno uno .e uno #nell'input.
Zgarb,

1
Bella sfida, più difficile di quanto sembri
edc65

Risposte:


2

JavaScript (ES6), 235253

Stesso metodo utilizzato da @mac. Per ogni cella libera, provo un riempimento ricorsivo, contrassegnando le celle usate con la coordinata che sto usando (che può essere al di fuori del modello originale). Se durante il riempimento arrivo a una cella già contrassegnata con coordinate diverse, mi trovo in un percorso infinito.

Il modo bizzarro di gestire il modulo in JS è piuttosto fastidioso.

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

Test nella console di Firefox / FireBug

Infinito

['##.###\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)))

Produzione

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

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

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

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

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

Finito

['###\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)))

Produzione

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

".#
#." false

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

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

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

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

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

Sì, daft modulo è stato un problema anche in C #, ma penso di aver trovato un modo per usarlo nella mia copia di lavoro con il codice direzionale (ripubblicherò solo se riesco a ottenere un 10% riduzione o migliore): (j%4-1)%2dà un bel motivo ripetuto.
VisualMelon

Credo che siano ammesse funzioni senza nome e, quindi, a meno che la funzione non includa una chiamata a se stessa (sembrerebbe non farlo) è lecito non contare il L=verso del conteggio dei byte.
SuperJedi224,

@ SuperJedi224 probabilmente hai ragione, ma è abbastanza corto come lo è dopo tutto
edc65

21

C # - 423 375 byte

Programma C # completo, accetta input tramite STDIN, invia "True" o "False" a STDOUT come appropriato.

Non potevo permettermi di lasciare quel Linq lì dentro ... per fortuna la sua rimozione ha dato i suoi frutti! Ora tiene traccia delle celle viste e visitate in un array (dato che comunque ne osserva solo un numero limitato). Ho anche riscritto il codice direzionale, eliminando la necessità di una Lambda e in generale rendendo il codice più impossibile da capire (ma con un notevole risparmio di byte).

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

È una prima ricerca (non che conta) che continua solo fino a quando non si blocca in una caverna finita, o decide che la caverna è abbastanza grande da essere infinitamente grande (quando ha tante celle quante rettangolo originale, questo significa che deve esserci un percorso da una cella a se stessa da qualche altra parte, che possiamo continuare a seguire per sempre).

Codice non tagliato:

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
Probabilmente la prima volta che ho visto una C#risposta come il migliore dei voti qui.
Michael McGriff,

1
Main () in struct, ora è carino.
PTwr

10

Python 2 - 258 210 244 byte

Controlla ricorsivamente i percorsi, se lo overflow dello stack restituisce 1 (verità) altrimenti restituisce Nessuno (falsa).

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
È possibile salvare alcuni byte utilizzando ;per le linee in p, in quanto li otterrai sulla stessa linea con il if.
PurkkaKoodari,

11
"Se lo overflow dello stack ritorna vero" - Mi piace quella condizione di fine ricorsione :)
schnaader

3
Non sono convinto che questo sia un approccio valido. L'uso di overflow dello stack per rilevare una regione "infinita" produrrà falsi positivi. Le specifiche del problema non indicano alcuna limitazione sugli intervalli di input ma qualcosa come un labirinto 300x300 non sembra irragionevole e potrebbe racchiudere percorsi finiti molto lunghi.
Giovanni

4
Quasi tutti i labirinti finiti causerebbero anche un overflow dello stack. Questo non è un programma valido.
PyRulez,

@johne Aggiornato in modo che il limite di ricorsione sia all'ordine delle dimensioni dei labirinti. Purtroppo sono stati aggiunti 34 byte, ma ora dovrebbe essere corretto (almeno come può essere un hack come questo).
Kyle Gullion,

5

Python 2 - 297 286 275 byte

Seleziona una cella "aperta" arbitraria da cui iniziare un riempimento. Il labirinto è infinito se durante il riempimento visitiamo nuovamente una cella che abbiamo già visitato, ma ha una coordinata diversa rispetto alla visita precedente. Se il riempimento dell'inondazione riempie l'intera regione senza trovare una cella del genere, prova un'altra regione. Se tale regione non può essere trovata, il labirinto è finito.

Prende il file per l'elaborazione dalla riga di comando, restituisce il codice di uscita 1per infinito e 0per finito.

Restituisce risultati corretti per tutti i casi di test.

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
Non puoi presumere che alcune celle siano membri di una caverna infinita, puoi facilmente avere sia caverne infinite che finite.
VisualMelon

2
@VisualMelon: scusa, la descrizione non è del tutto corretta. Il codice controlla effettivamente ogni possibile regione di celle interconnesse, non solo una (come è attualmente implicito). Ecco a cosa serve il ciclo while finale: selezionare le regioni da controllare mentre ci sono ancora celle non controllate.
Mac
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.