Faites un analyseur de serpent!


14

Les serpents ressemblent à ceci:

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

Le serpent peut se croiser comme dans ce cas:

 @
 ^
>^>v
 ^<<

Pour qu'un crossover soit valide, les personnages de chaque côté doivent se déplacer dans la même direction. L'affaire de

 @
>^v
 ^<

peut être considéré comme peu clair et invalide.

La sortie est une chaîne de WASDreprésentation allant de la tête à la queue ( @).

Étant donné un serpent qui ne revient pas en arrière et n'est pas ambigu, pouvez-vous écrire un programme qui produira la chaîne de mouvements que le serpent prend?

C'est le golf de code, donc la réponse la plus courte l'emporte!

Cas de test:

(Remarque: le @peut être remplacé par n'importe quel caractère absent v^<>)

Contribution:

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

Production: ddddssaassdddddww


Contribution:

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

Production: dddsssaaawww


Contribution:

>>>v
   v       @
   v       ^
   >>>>v   ^
       >>>>^

Production: dddsssddddsddddwww


Contribution:

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

Production: ssaaaassddwwwwaa


Contribution:

@v<v
^v^v
^v^<
^<

Production: ssawwasssawww


1
L'entrée doit-elle être une seule chaîne ou pouvons-nous prendre une chaîne []? Est-ce que chaque ligne de l'entrée est rembourrée pour avoir la même longueur ou devons-nous faire face à une longueur de ligne irrégulière?
CAD97

2
Cela me donne d'horribles retours en arrière sur le chemin d'une fourmi sur une question de cube rubiks.
Matt

Le segment de début sera-t-il toujours sur la ligne 0, caractère 0, ou devrons-nous le trouver?
MayorMonty

1
Les cas de test @SpeedyNinja 2 et 4 ont tous deux un début non à (0,0), et le cas de test 0 (les serpents ressemblent) ne commence pas ou ne se termine pas à (0,0).
CAD97

1
@ CAD97 Oh, c'est diabolique;)
MayorMonty

Réponses:


7

Java, 626 539 536 529 octets

-87 octets en enregistrant quelques-uns dans beaucoup d'endroits. Merci à M. Public de l'avoir signalé.

-3 octets car je n'arrive pas à supprimer tous les espaces du premier coup (merci mbomb007)

+8 octets à corriger pour ce cas:

@v<v
^v^v
^v^<
^<

-15 octets par déclaration de variable à chargement frontal

s->{String o="",t;String[]p=s.split("\n");int h=p.length,w=p[0].length(),y=0,x,b=0,a,n,m;char[][]d=new char[h][w];for(;y<h;y++)for(x=0;x<w;x++){d[y][x]=p[y].charAt(x);if(d[y][x]=='@')d[y][x]=' ';}for(;b<h;b++)for(a=0;a<w;a++){t="";x=a;y=b;n=0;m=0;while(!(y<0|y>h|x<0|x>w||d[y][x]==' ')){if(y+m>=0&y+m<h&x+n>=0&x+n<w&&d[y+m][x+n]==d[y-m][x-n])d[y][x]=d[y-m][x-n];n=m=0;switch(d[y][x]){case'^':t+="W";m--;break;case'<':t+="A";n--;break;case'v':t+="S";m++;break;case'>':t+="D";n++;}x+=n;y+=m;}o=t.length()>o.length()?t:o;}return o;}

Version lisible:

static Function<String,String> parser = snake -> {
    // declare all variables in one place to minimize declaration overhead
    String output = "", path;
    String[] split = snake.split("\n");
    int h=split.length, w=split[0].length(), y=0, x, startY=0, startX, dx, dy;
    char[][] board = new char[h][w];
    // setup char[][] board
    for (; y<h; y++)
        for (x=0; x<w; x++) {
            board[y][x]=split[y].charAt(x);
            if(board[y][x]=='@')board[y][x]=' ';
        }
    // find the longest possible path
    for (; startY<h; startY++)
        for (startX=0; startX<w; startX++) {
            path = "";
            x=startX; y=startY; dx=0; dy=0;
            while (!(y<0 | y>h | x<0 | x>w || board[y][x] == ' ')) {
                if (y + dy >= 0 & y + dy < h & x + dx >= 0 & x + dx < w
                        && board[y + dy][x + dx] == board[y - dy][x - dx]) {
                    board[y][x] = board[y - dy][x - dx];
                } dx = dy = 0;
                switch(board[y][x]) {
                    case '^':path+="W";dy--;break;
                    case '<':path+="A";dx--;break;
                    case 'v':path+="S";dy++;break;
                    case '>':path+="D";dx++;break;
                }
                x+=dx; y+=dy;
            }
            output = path.length()>output.length()?path:output;
        }
    return output;
};

Prend une chaîne comme v @\n>>>^. Crée un chemin commençant à chaque coordonnée, puis renvoie le plus long. L'anticipation requise pour les chemins qui se chevauchent était la partie la plus difficile.


2
Je suis vraiment impressionné. Je ne m'attendais pas à ce que quelqu'un essaie même cela. Et tu es le premier. +1. (2016 octets est correct, et encore mieux pour 2016: D)

Supprimez tous les espaces, noms, etc., puis je +1. Je ne vote pas tant qu'il n'a pas été joué correctement.
mbomb007

2
Ou, ayez deux extraits de code, l'un de la version entièrement golfée, l'un des exemples lisibles de travail.
Mr Public

@ mbomb007 J'ai terminé la logique du golf alors voici la version correctement jouée!
CAD97

2
@ CAD97 Pour ce défi, je dirais que c'est un excellent golf à Java.
Mr Public

1

Rubis, 217

->a{r=''
z=a.index ?@
a.tr!('<^>v',b='awds').scan(/\w/){c=0
e,n=[a[z,c+=1][?\n]?p: c,d=c*a[/.*
/].size,a[z-c,c][?\n]?p: -c,-d].zip(b.chars).reject{|i,k|!i||a[v=i+z]!=k||0>v}.max_by{|q|q&[a[z]]}until n
z+=e
r=n*c+r}
r}

Cela commence à @et recule, à la recherche de voisins qui pointent vers la position actuelle ( z). Afin de choisir la bonne voie aux intersections à 4 voies, il privilégie les voisins pointant dans la même direction ( max_by{...}). Si aucun voisin immédiat n'est trouvé, il suppose qu'il doit y avoir eu un croisement et atteint un niveau à la fois jusqu'à ce qu'il en trouve un (until n et c+=1). Ce processus se répète pour le nombre de segments du corps (sans la tête) (.scan(/\w/){...} ).

Le cas de test que j'ai ajouté au puzzle ne cessait de me faire trébucher, alors je suis passé de 182 caractères à 218. Ces personnages supplémentaires faisaient tous en sorte que mes mouvements horizontaux n'entrent pas dans les lignes suivantes / précédentes. Je me demande si je peux mieux gérer cela.

Non golfé:

f=->a{
  result=''
  position=a.index ?@ # start at the @
  a.tr!('<^>v',b='awds') # translate arrows to letters
  a.scan(/\w/){           # for each letter found...
    search_distance=0
    until distance
      search_distance+=1
      neighbors = [
        a[position,search_distance][?\n]?p: search_distance,  # look right by search_distance unless there's a newline
        width=search_distance*a[/.*\n/].size,   # look down (+width)
        a[position-search_distance,search_distance][?\n]?p: -search_distance, # look left unless there's a newline
        -width                  # look up (-width)
      ]
      distance,letter = neighbors.zip(b.chars).reject{ |distance, letter_to_find|
        !distance || # eliminate nulls
         a[new_position=distance+position]!=letter_to_find || # only look for the letter that "points" at me
         0>new_position # and make sure we're not going into negative indices
       }.max_by{ |q| 
        # if there are two valid neighbors, we're at a 4-way intersection
        # this will make sure we prefer the neighbor who points in the same 
        # direction we're pointing in.  E.g., when position is in the middle of 
        # the below, the non-rejected array includes both the top and left.
        #   v
        #  >>>
        #   v
        # We want to prefer left.
        q & [a[position]] 
        # ['>',x] & ['>'] == ['>']
        # ['v',x] & ['>'] == []
        # ['>'] > [], so we select '>'.
       }
    end
    position+=distance
    result=(letter*search_distance)+result # prepend result
  }
  result # if anyone has a better way of returning result, I'm all ears
}

Vous devriez être en mesure de simplifier quelque peu votre logique car votre cas ajouté a été jugé hors de la portée prévue.
CAD97
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.