Machen Sie einen Snake Parser!

14

Schlangen sehen so aus:

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

Die Schlange kann sich wie folgt kreuzen:

 @
 ^
>^>v
 ^<<

Damit eine Frequenzweiche gültig ist, müssen sich die Zeichen auf beiden Seiten in dieselbe Richtung bewegen. Der Fall von

 @
>^v
 ^<

kann als unklar und ungültig angesehen werden.

Die Ausgabe ist eine Zeichenfolge, WASDdie den Übergang vom Kopf zum Schwanz ( @) darstellt.

Können Sie bei einer Schlange, die nicht rückwärts läuft und nicht mehrdeutig ist, ein Programm schreiben, das die Folge von Zügen ausgibt, die die Schlange ausführt?

Das ist Code-Golf, also gewinnt die kürzeste Antwort!

Testfälle:

(Hinweis: Das @kann durch ein beliebiges Zeichen ersetzt werden, das nicht in enthalten ist. v^<>)

Eingang:

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

Ausgabe: ddddssaassdddddww


Eingang:

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

Ausgabe: dddsssaaawww


Eingang:

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

Ausgabe: dddsssddddsddddwww


Eingang:

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

Ausgabe: ssaaaassddwwwwaa


Eingang:

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

Ausgabe: ssawwasssawww

CAD97
quelle
1
Muss die Eingabe ein einzelner String sein oder können wir einen String [] nehmen? Ist jede Zeile der Eingabe mit der gleichen Länge aufgefüllt oder müssen wir mit unregelmäßiger Zeilenlänge umgehen?
CAD97
2
Dies gibt mir schreckliche Rückblicke auf den Weg einer Ameise in einer Rubiks-Cube-Frage.
Matt
Befindet sich das erste Segment immer in Zeile 0, Zeichen 0 oder müssen wir es finden?
MayorMonty
1
@SpeedyNinja Testfälle 2 und 4 haben beide Starts nicht bei (0,0), und Testfall 0 (Schlangen sehen so aus) startet ODER endet nicht bei (0,0).
CAD97
1
@ CAD97 Oh, das ist devlish;)
MayorMonty

Antworten:

7

Java, 626 539 536 529 Bytes

-87 Bytes durch Speichern einiger weniger an vielen Stellen. Vielen Dank an Herrn Public für den Hinweis.

-3 Bytes, da ich nicht in der Lage bin, alle Leerzeichen zu entfernen (danke mbomb007)

+8 Bytes für diesen Fall zu beheben:

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

-15 Bytes durch Frontloading-Variablendeklaration

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

Lesbare Version:

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

Nimmt einen String wie v @\n>>>^. Erstellt einen Pfad, der an jeder Koordinate beginnt, und gibt dann den längsten zurück. Der für die überlappenden Pfade erforderliche Vorausblick war der schwierigste Teil.

CAD97
quelle
2
Ich bin sehr beeindruckt. Ich hatte nicht erwartet , dass es jemand versucht hätte. Und du bist der erste. +1. (2016 Bytes ist in Ordnung, und noch besser für 2016: D)
Entferne alle Leerzeichen, Namen usw., dann werde ich +1 geben. Ich stimme nicht ab, bis es richtig golfen ist.
mbomb007
2
Oder haben Sie zwei Code-Schnipsel, eines der vollwertigen, eines der gut lesbaren Beispiele.
Mr Public
@ mbomb007 Ich habe das logische Golfen beendet, hier ist also die richtig golfene Version!
CAD97
2
@ CAD97 Für diese Herausforderung würde ich sagen, dass dies ein ausgezeichnetes Golfspiel in Java ist.
Mr Public
1

Ruby, 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}

Dies beginnt am @und geht rückwärts, wobei nach Nachbarn gesucht wird, die auf die aktuelle Position zeigen ( z). Um an Kreuzungen mit vier Richtungen den richtigen Weg zu wählen, werden Nachbarn bevorzugt, die in dieselbe Richtung zeigen ( max_by{...}). Wenn keine unmittelbaren Nachbarn gefunden werden, wird davon ausgegangen, dass ein Crossover stattgefunden hat, und es wird jeweils eine Ebene nach der anderen erreicht, bis ein ( until nund c+=1) gefunden wird. Dieser Vorgang wiederholt sich für die Anzahl der Körpersegmente (ohne Kopf) ( .scan(/\w/){...}).

Der Testfall, den ich zu dem Puzzle hinzugefügt habe, hat mich immer wieder aus der Fassung gebracht, also bin ich von 182 Zeichen auf 218 übergegangen. Diese zusätzlichen Charaktere haben alle dafür gesorgt, dass meine horizontalen Züge nicht in die nächsten / vorherigen Zeilen eingingen. Ich frage mich, ob ich besser damit umgehen kann.

Ungolfed:

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
}
Nicht dieser Charles
quelle
Sie sollten in der Lage sein, Ihre Logik etwas zu vereinfachen, da Ihr hinzugefügter Fall als nicht beabsichtigt eingestuft wurde.
CAD97