Détection de boucle - pas ce genre!


24

Le but de ce défi est de trouver la direction et la zone délimitée par une boucle.

Contribution:

Une grille rectangulaire composée entièrement de ces caractères: ^v<>

(Facultativement, vous pouvez également recevoir les dimensions de la grille avant la grille elle-même en décimal avec un caractère préfixe, suffixe et séparateur de votre choix.)

Une boucle dans la grille est un ensemble des caractères susmentionnés tels que l'un pointe vers le suivant, pointant vers le suivant, pointant éventuellement vers le premier caractère. Par exemple:

<>>v>     >>v 
^^<>v     ^ >v
>^<<<     ^<<<
>^<v>         

La grille de gauche est l'échantillon d'entrée; la grille de droite est la boucle isolée.

La grille d'entrée ne contiendra aucune boucle ou une seule boucle; vous n'avez pas à vous soucier des cas dans lesquels la grille contient plus d'une boucle.

Sortie:

Si la grille ne contient pas de boucle, sortez X.

Si la grille contient deux flèches pointant l'une vers l'autre, sortez 0.

Si la grille contient une boucle dans le sens antihoraire, comptez les caractères entourés par la boucle, y compris la bordure. Sortez ce nombre.

Si la grille contient une boucle dans le sens horaire, suivez le même processus pour la boucle dans le sens antihoraire, mais sortez le négatif de ce nombre. Par exemple, la grille d'entrée ci-dessus aurait une sortie de -11: 10 provenant de la boucle elle-même et 1 du caractère entouré par la boucle.

C'est du . Le code le plus court gagne.

Cas de test:

<<^
^>v
^v<

Sortie X.

<<<<
><<<
>>^>

Sortie 0.

<>^^<
>>>v>
<^^>v
<^>>v
>^<<<

Sortie -15.

v<<<<
>v>>^
v<^<<
>>>>^

Sortie 20.


4
Pourquoi les downvotes? La question me va bien.
xnor

Comment déterminez-vous si une boucle est dans le sens horaire ou non? Par exemple, recherchez «dédale à double spirale» sur Google Images. Comment déterminez-vous la façon dont le chemin s’exécute? Voici un exemple.
ghosts_in_the_code

@ghosts_in_the_code Cela ne forme pas une boucle fermée.
Martin Ender

@ MartinBüttner Imaginez que les deux extrémités extérieures se connectent l'une à l'autre.
ghosts_in_the_code

4
@ghosts_in_the_code Ensuite, l'une des extrémités devrait se retourner pour rencontrer l'autre. Dans ce cas, vous obtenez une boucle libre d'intersection qui peut être dépliée en cercle pour indiquer si elle va dans le sens horaire ou antihoraire. Un test simple consiste à regarder le point le plus bas de la boucle et à vérifier s'il va à gauche ou à droite (dans le cas de la grille, ce point n'est pas unique, mais vous pouvez regarder la cellule la plus en bas à droite de la boucle et vérifiez si ça va vers la gauche ou vers le haut).
Martin Ender

Réponses:


4

C #, 604 octets

Programme complet, accepte les entrées (disposition délimitée par des lignes, pas de dimensions) de STDIN, les sorties vers STDOUT.

using C=System.Console;class P{static void Main(){int w=0,W,i,j,t,k,l,c;string D="",L;for(;(L=C.ReadLine())!=null;D+=L)w=L.Length;var R=new[]{-1,0,1,w,-w};L="X";for(W=i=D.Length;i-->0;){var M=new int[W];for(k=j=i;i>0;){M[j]=++k;t=j+R[c=D[j]%5];if(t<0|t>=W|c<3&t/w!=j/w|c>2&t%w!=j%w)break;j=t;if((l=M[j])>0){var J=new int[W+1];System.Func<int,int>B=null,A=s=>J[s]<0?0:J[k=B(s)]=k==W?k:i;B=x=>J[x]==x?x:B(J[x]);for(i=J[W]=W;i>0;)J[--i]=M[i]<l?i%w<1|i%w>w-2|i<w|i>W-w?W:i:-1;for(;i<W;)if(J[++i]<0)l=D[i]%5/2-1;else{A(i-1);if(i>w)A(i-w);}for(c=W;i-->0;L=""+(c>2?c:0)*l)c-=J[i]<0?0:B(i)/W;}}}C.WriteLine(L);}}

Le programme fonctionne en lisant d'abord la mise en page, inutile de le dire, puis en itérant sur chaque cellule. Nous exécutons ensuite un «serpent» à partir de chaque cellule, qui suit les flèches jusqu'à ce qu'il coule sur le bord ou se jette dans lui-même. Si elle se heurte à elle-même, alors nous savons que nous avons trouvé une boucle (ou l'une de ces "> <" choses), et elle sait également combien de serpent est dans la boucle.

Une fois que nous savons que nous avons une boucle, nous savons quelles cellules sont sur la boucle, et nous créons une carte de chaque cellule (+1, pour des raisons) à elle-même, -1(signifie qu'elle est sur la boucle), ou W(toute la largeur) s'il est sur le bord (ou le +1 (qui est à l'index W) pour simplifier encore les choses).

Pendant que nous faisons cela, nous trouvons également la direction du «dernier» élément de la boucle (c'est-à-dire le dernier élément de la boucle sur la dernière ligne qui contient des éléments de la boucle). Cet élément doit être un "<" ou un "^", ce qui nous indique la fréquence d'horloge (CW / CCW) de la boucle (traduite en -1 / + 1).

Nous effectuons ensuite une passe d'ensemble disjoint, qui affecte tous les éléments qui sont en dehors de la boucle à l' Wensemble. Nous soustrayons ensuite leur nombre Wpour obtenir le nombre contenu sur et dans la boucle. Si ce nombre est inférieur à 3, nous le remplaçons par 0. Nous le multiplions par la fréquence d'horloge, le définissons comme résultat, et échappons en quelque sorte aux boucles for, où le résultat est sorti.

Si, cependant, la plupart des éléments ci-dessus ne se produisent jamais (car aucun serpent ne se retrouve jamais), le résultat reste alors "X", et cela est émis.

using C=System.Console;

class P
{
    static void Main()
    {
        int w=0, // width
        W, // full length
        i, // used for iterating over all the cells
        j, // keeps track of where the snake as got to
        t, // t is next j
        k, // how far along the snake we are, kind of
        // later on, k is used as temp for A
        l, // stores a threshold for how far along the snake the loop starts
        // later on, l stores the last seen pointer - this tells us the clockness
        c; // the translated direction
        // later on, c is a backwards-count

        string D="", // D is the map
        L; // used for reading lines, and then storing the result

        // might not be the best yay of doing this
        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

        var R=new[]{-1,0,1,w,-w}; // direction table (char%5) - might be able to replace this array with some bit bashing/ternary

        L="X"; // can't seem to fit this in anywhere... (don't strictly need to re-use L)
        for(W=i=D.Length;i-->0;) // for each cell, we send a 'snake' to try to find the loop from that cell
        {
            var M=new int[W]; // stores how far along the snake this point is

            for(k=j=i; // k's value doesn't really matter, as long as it's not stupidly big
                i>0;) // the i>0 check is just for when we return (see comment at the end of the code)
            {
                M[j]=++k; // store snake point and advance distance

                t=j+R[c=D[j]%5]; // t is position after move (translate <>v^ to 0234 (c is direction))
                //c=D[j]%5; // translate <>v^ to 0234 (c is direction)
                //t=j+R[c]; // t is position after move
                if(t<0|t>=W|c<3&t/w!=j/w|c>2&t%w!=j%w)
                    break; // hit an edge - will always happen if we don't find a loop - give up on this snake
                j=t; // move to new position

                if((l=M[j])>0) // we've been here before...
                {
                    // disjoint sets (assign all the edges to one set, assign all the ones on the line to another set, do adjacent disjoint, return size-outteredge (minus if necessary)
                    var J=new int[W+1]; // looks like we can reuse M for this

                    System.Func<int,int>B=null,
                    // whatever s points at should point to i, unless s points to W, in which case it should keep point to W
                    A=s=>J[s]<0?0:J[k=B(s)]=k==W?k:i;
                    // read the value this points to
                    B=x=>J[x]==x?x:B(J[x]);

                    for(i=J[W]=W;i>0;)
                        J[--i]=M[i]<l? // if we are not part of the loop
                            i%w<1|i%w>w-2|i<w|i>W-w? // if we are on the edge
                                W: // on the edge
                                i: // not on the edge
                             -1; // this is on the loop

                    // now fill in
                    // we don't have to worry about wrapping, the important bit being an un-wrapping closed loop
                    // i = 0
                    for(;i<W;)
                        if(J[++i]<0) // we are on the loop
                            l=D[i]%5/2-1; // last one must be ^(4) or <(0)
                        else{ // can probably crush this into an l returning l assigning term (with if above)
                            A(i-1);
                            if(i>w)
                                A(i-w);
                        }

                    // now count the number of non-edges
                    for(c=W; // assume everything is a non-edge
                        i-->0;
                        L=""+(c>2?c:0)*l) // set output to be number of non-edges * clockness (or 0 if too few)
                        c-=J[i]<0?0:B(i)/W; // subtract 1 if an edge (B(i) is W), othewise 0

                    // at this point, i is 0, so we will fall out of all the loops
                }
            }
        }

        C.WriteLine(L); // output result
    }
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.