Labyrinthes Infinis

35

Contexte

Vous êtes l'apprenti d'un puissant sorcier et votre maître élabore actuellement un sortilège pour créer un labyrinthe interdimensionnel dans lequel piéger ses ennemis. Il souhaite que vous programmiez son ordinateur alimenté à la vapeur pour analyser les configurations possibles. La programmation de cette machine diabolique est très dangereuse, vous voulez donc garder le code aussi court que possible.

Contribution

Votre entrée est une grille bidimensionnelle de points .et de hachages #, représentant des espaces vides et des murs, présentée sous la forme d'une chaîne délimitée par des lignes. Il y en aura toujours au moins un .et un #et vous pourrez décider s'il y a ou non une nouvelle ligne.

Cette grille est le modèle d'un labyrinthe infini, qui consiste à aligner une infinité de copies de la grille les unes à côté des autres. Le labyrinthe est divisé en cavités , qui sont des composants connectés d'espaces vides (les espaces adjacents en diagonale ne sont pas connectés). Par exemple, la grille

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

résultats dans le labyrinthe suivant (continué indéfiniment dans toutes les directions):

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

Ce labyrinthe contient une cavité de surface infinie. D'autre part, ce plan aboutit à un labyrinthe composé uniquement de cavités finies:

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

Sortie

Votre sortie doit être une valeur de vérité si le labyrinthe contient une cavité infinie, sinon une valeur de fausseté. Notez que le labyrinthe peut contenir des cavités finies et infinies; dans ce cas, le résultat doit être la vérité.

Règles

Vous pouvez écrire un programme complet ou une fonction. Le nombre d'octets le plus faible gagne et les failles standard sont interdites.

Cas de test supplémentaires

Cavités infinies:

.#

#.#
...
#.#

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

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

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

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

Cavités finies:

###
#.#
###

.#
#.

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

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

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

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

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


###########
........#..
#########.#
..........#
.##########
.#.........
##.########
...#.......
Zgarb
la source
Y a-t-il un caractère de fin de ligne?
FUZxxl
@FUZxxl C'est à vous de décider.
Zgarb
Le labyrinthe infini peut-il être une ligne droite allant à l'infini?
1
@ Neil, je ne suis pas sûr de ce que tu veux dire. Les premier et deuxième exemples infinis ont des lignes infinies, mais il y en a au moins un .et un #dans l'entrée.
Zgarb
1
Beau défi, plus difficile qu'il n'y parait
edc65

Réponses:

2

JavaScript (ES6), 235 253

Même méthode utilisée par @mac. Pour chaque cellule libre, j'essaie un remplissage récursif, en marquant les cellules utilisées avec la coordonnée que j'utilise (qui peut être en dehors du modèle original). Si, pendant le remplissage, j'arrive dans une cellule déjà marquée avec une coordonnée différente, je suis sur un chemin infini.

La façon bizarre de manipuler le modulo dans JS est assez énervante.

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

Testez dans la console Firefox / FireBug

Infini

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

Sortie

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

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

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

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

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

Fini

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

Sortie

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

".#
#." false

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

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

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

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

"###....##.#########
####...##....#...##
..####.#######.###.
....##..........##.
###..#####.#..##...
####..#..#....#..##
..###.####.#.#..##.
..###...#....#.#...
..####..##.###...##
#.####.##..#####.##
####...##.#####..##" false
edc65
la source
Ouais, Daft Modulo était un problème en C # également, mais je pense avoir trouvé un moyen de l'utiliser à bon escient dans ma copie de travail avec le code directionnel (je ne re-posterai que si je peux obtenir 10% réduction ou mieux): (j%4-1)%2donne un motif répétitif agréable.
VisualMelon
Je crois que les fonctions non nommées sont permises, et donc, à moins que la fonction n'inclue un appel à lui-même (il semblerait que non), il est permis de ne pas compter le L=nombre d'octets.
SuperJedi224
@ SuperJedi224 tu as probablement raison, mais c'est assez court comme
ça
21

C # - 423 375 octets

Programme complet en C #, accepte les entrées via STDIN, les sorties "True" ou "False" sont envoyées à STDOUT selon le cas.

Je ne pouvais pas laisser de côté cette Linq ... heureusement, son déménagement a porté ses fruits! Il garde maintenant une trace des cellules vues et visitées dans un tableau (étant donné qu'il n'en regarde de toute façon qu'un nombre fini d'entre elles). J'ai également réécrit le code directionnel, supprimant ainsi le besoin d'un Lambda et rendant généralement le code plus difficile à comprendre (mais avec une économie substantielle d'octets).

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

C’est une recherche approfondie en profondeur (non pas que cela compte) qui continue jusqu’à ce qu’elle soit bloquée dans une cavité finie, ou bien elle décide que la caverne est assez grande pour être infiniment grande (quand elle a autant de cellules que le rectangle d’origine, cela signifie qu’il doit exister un chemin d’une cellule à une autre, que nous pouvons continuer à suivre pour toujours).

Code non limité:

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
    }
}
VisualMelon
la source
1
Probablement la première fois que je vois une C#réponse en tant que gagnant des votes ici.
Michael McGriff
1
Main () dans la structure, maintenant c'est mignon.
2
10

Python 2 - 258 210 244 octets

Vérifiez récursivement les chemins, si le dépassement de pile retourne 1 (vérité) sinon rien ne retourne (falsey).

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])
Kyle Gullion
la source
1
Vous pouvez enregistrer des octets en utilisant ;pour les lignes p, car vous les obtiendrez sur la même ligne avec if.
PurkkaKoodari
11
"Si le dépassement de
capacité de la
3
Je ne suis pas convaincu que cette approche soit valable. L'utilisation de débordements de pile pour détecter une région "infinie" produira des faux positifs. La spécification du problème n'énonce aucune limite sur les plages d'entrée, mais quelque chose comme un labyrinthe 300x300 ne semble pas déraisonnable et pourrait englober de très longs chemins finis.
JohnE
4
Presque tous les labyrinthes finis provoqueraient également un débordement de pile. Ce n'est pas un programme valide.
PyRulez
@johne Mis à jour, la limite de récursivité est donc dans l'ordre de la taille des labyrinthes. Ajout de 34 octets malheureusement mais cela devrait être correct maintenant (du moins aussi correct qu’un bidouillage comme celui-ci).
Kyle Gullion
5

Python 2 - 297 286 275 octets

Choisit une cellule "ouverte" sur laquelle commencer un remplissage. Le labyrinthe est infini si, pendant le remplissage, nous revisitons une cellule que nous avons déjà visitée, mais ses coordonnées sont différentes de celles de la visite précédente. Si l'inondation remplit toute la région sans trouver une telle cellule, essayez une autre région. Si une telle région est introuvable, le labyrinthe est fini.

Prend le fichier à traiter en ligne de commande, retourne le code de sortie 1pour infini et 0pour fini.

Renvoie les résultats corrects pour tous les cas de 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)
Mac
la source
1
Vous ne pouvez pas présumer que n'importe quelle cellule appartiendra à une caverne infinie, vous pouvez facilement avoir des cavernes infinies et finies.
VisualMelon
2
@VisualMelon: désolé, la description n'est pas tout à fait correcte. En réalité, le code vérifie toutes les régions possibles des cellules interconnectées, et non une seule (comme cela est actuellement supposé). C'est à cela que sert la dernière boucle while: sélectionner des régions à vérifier tant qu'il reste des cellules non vérifiées.
Mac