文字列のスネーク解除


58

通常の文字列は次のようになります。

Hello,IAmAStringSnake!

そして、ストリングスネークは次のようになります:

Hel         
  l      rin
  o,IAmASt g
           S
       !ekan

あなたのタスク

文字列蛇は危険なので、文字列蛇を入力として受け取り、通常の文字列として出力するプログラムを作成する必要があります。

仕様書

  • 入力は、複数行の文字列または文字列の配列にすることができます。
  • 入力の各行にはスペースが埋め込まれ、長方形のグリッドが形成されます。
  • ヘビのキャラクターは、ゲームのスネークのように、上下左右に隣接するキャラクターにのみ接続できます。彼らは斜めに行くことはできません。
  • ヘビのキャラクターはヘビの別の部分に隣接することはなく、接続されたキャラクターのみが隣接します。
  • 文字列の最初の文字は、入力グリッドの左上隅からマンハッタン距離が最短の終了文字です(つまり、ヘビが終了文字から左上に直接移動するために必要な移動の最小数)コーナー)。両端が同じ距離になることはありません。
  • 文字列には、コードポイント33〜126の間のASCII文字を含めることができます(スペースや改行は使用できません)。
  • 文字列の長さは2〜100文字です。
  • バイト単位の最短コードが優先されます。

テストケース

(入力グリッド、その後に出力文字列)

Hel         
  l      rin
  o,IAmASt g
           S
       !ekan

Hello,IAmAStringSnake!

----------

Python

Python

----------

P  ngPu  Code 
r  i  z  d  G 
o  m  z  n  o 
gram  lesA  lf

ProgrammingPuzzlesAndCodeGolf

----------

   ~ zyx tsr XWVUTSR
   }|{ wvu q Y     Q
!          p Z `ab P
"#$ 6789:; o [ _ c O
  % 5    < n \]^ d N
('& 432  = m     e M
)     1  > lkjihgf L
*+,-./0  ?         K
         @ABCDEFGHIJ

!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~

----------

  tSyrep    
  r    p    
  in Sli    
   g    Sile
   Snakes  n
Ser      ylt
a eh   ilS  
fe w   t    
   emo h    
     Sre    

SlipperyStringSnakesSilentlySlitherSomewhereSafe

20
おもしろ情報:リンクされたウィキペディアの記事によると、マンハッタン距離はヘビ距離としても知られています!
user81655

hastebin.com/asugoropin.vbsのような入力は正しいでしょうか?
FliiFe

@FliiFeいいえ、ヘビの部分は互いに隣接することはできません。これが起こると、ヘビがどこに向かっているのかを常に知ることができないためです(そして、チャレンジがずっと難しくなります)。これを説明するために仕様に行を追加しました。
-user81655

入力は2次元配列(つまり、各文字を要素として)にできますか?
FliiFe

29
確かにこのパズルにはpythonで答えが必要ですか?
16

回答:


11

APL、55バイト

{⍵[1↓(⊂0 0){1<⍴⍵:⍺,∆[⊃⍋+/¨|⍺-∆]∇∆←⍵~⍺⋄⍺}(,⍵≠' ')/,⍳⍴⍵]}

この関数は、文字列snakeを含む文字マトリックスを受け取ります。

例:

      s1 s2 s3
┌────────────┬──────────────┬────────────────────┐
│Hel         │P  ngPu  Code │   ~ zyx tsr XWVUTSR│
│  l      rin│r  i  z  d  G │   }|{ wvu q Y     Q│
│  o,IAmAst g│o  m  z  n  o │!          p Z `ab P│
│           S│gram  lesA  lf│"#$ 6789;: o [ _ c O│
│       !ekan│              │  % 5    < n \]^ d N│
│            │              │('& 432  = m     e M│
│            │              │)     1  > lkjighf L│
│            │              │*+,-./0  ?         K│
│            │              │         @ABCDEFGHIJ│
└────────────┴──────────────┴────────────────────┘
      ↑ {⍵[1↓(⊂0 0){1<⍴⍵:⍺,∆[⊃⍋+/¨|⍺-∆]∇∆←⍵~⍺⋄⍺}(,⍵≠' ')/,⍳⍴⍵]} ¨ s1 s2 s3 
Hello,IAmAstringSnake!                                                                        
ProgrammingPuzzlesAndCodeGolf                                                                 
!"#$%&'()*+,-./0123456789;:<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefhgijklmnopqrstuvwxyz{|}~

説明:

  • (,⍵≠' ')/,⍳⍴⍵:すべての非スペースの座標を取得
  • (⊂0 0):(0,0)から始まる(無効な座標)
  • {... }:ヘビを追跡し、位置とヘビを指定します。
    • 1<⍴⍵::残っている要素が複数ある場合:
      • ∆←⍵~⍺:ヘビから現在の位置を削除して保管します。
      • +/¨|⍺-∆:現在の位置とヘビの残りの各点の間の距離を見つける
      • ∆[⊃⍋...] `:ヘビに最も近い点を取得します
      • :最も近い点を新しい現在の点として、短縮された蛇を新しい蛇として、関数を再度実行します。
      • ⍺,:その結果に現在の位置を追加します
    • ⋄⍺:それ以外の場合、単に現在の位置を返す
  • 1↓:結果から最初のアイテムをドロップします((0,0)位置)
  • ⍵[... ]:これらの要素を⍵から順番に取得します

24

JavaScript(ES6)+ SnakeEx、176バイト

a=b=>snakeEx.run("s{A}:<+>([^ ]<P>)+",b).reduce((c,d)=>(e=c.marks.length-d.marks.length)>0?c:e?d:c.x+c.y>d.x+d.y?d:c).marks.reduce((c,d,e,f)=>e%2?c+b.split`\n`[d][f[e-1]]:c,"")

SnakeExを覚えていますか?いいです、私もだからです!ゴルフの提案を歓迎します。


19

MATL、80バイト

修正してくれた@LevelRiverStに感謝

32>2#fJ*+X:4Mt1Y6Z+l=*2#fJ*+ttXjwYj+K#X<)wt!"tbb6#Yk2#)yw]xxvtXjwYjqGZy1)*+Gw)1e

入力は、行がで区切られたcharの2D配列です;。この形式のテストケースは次のとおりです。

['Hel         ';'  l      rin';'  o,IAmASt g';'           S';'       !ekan']
['Python']
['P  ngPu  Code ';'r  i  z  d  G ';'o  m  z  n  o ';'gram  lesA  lf']
['   ~ zyx tsr XWVUTSR';'   }|{ wvu q Y     Q';'!          p Z `ab P';'"#$ 6789:; o [ _ c O';'  % 5    < n \]^ d N';'(''& 432  = m     e M';')     1  > lkjihgf L';'*+,-./0  ?         K';'         @ABCDEFGHIJ']
['  tSyrep    ';'  r    p    ';'  in Sli    ';'   g    Sile';'   Snakes  n';'Ser      ylt';'a eh   ilS  ';'fe w   t    ';'   emo h    ';'     Sre    ']

オンラインでお試しください!

説明

各非スペース文字の座標は、複素数で表されます。現在の各文字について、次のものが最も近いものとして取得されます(それらの複素座標の最小絶対差)。

最初の文字を決定するには、2つのエンドポイントを見つける必要があります。これは次のように行われます。エンドポイントは、スペース以外の隣人を1つだけ持つ非スペース文字です。近傍の数は、適切なマスクを使用した2D畳み込みによって取得されます。初期点は、複素数座標の実数部と虚数部の合計が最小の端点です。つまり、マンハッタン距離で複素数0に最も近いか、左上隅の複素座標である1 + 1jに相当します。

32>      % Take input as 2D char array. Compute 2D array with true for nonspace,
         % false for space
2#f      % Arrays of row and column indices of nonspaces
J*+      % Convert to complex array. Real part is row, imaginary part is column
X:       % Convert to column array
4Mt      % Push arrays of zeros and ones again. Duplicate
1Y6      % Push array [0 1 0; 1 0 1; 0 1 0]. Used as convolution mask to detect
         % neighbours that are nonspace
Z+       % 2D convolution with same size as the input
1=       % True for chars that have only one neighbour (endpoints)
*        % Multiply (logical and): we want nonspaces that are endpoints
2#fJ*+   % Find complex coordinates (as before)
ttXjwYj  % Duplicate. Take real and imaginary parts
+        % Add: gives Manhattan distance to (0,0)
K#X<     % Arg min. Entry with minimum absolute value has least Manhattan
         % distance to (0,0), and thus to (1,1) (top left corner)
)        % Apply as an index, to yield complex coordinate of initial endpoint
wt!      % Swap, duplicate, transpose.
         % The stack contains, bottom to top: complex coordinates of initial
         % endpoint, column array with all complex coordinates, row array of all
         % coordinates. The latter is used (and consumed) by the next "for"
         % statement to generate that many iterations
"        % For loop. Number of iterations is number of nonspaces
  tbb    %   Duplicate, bubble up twice (rearrange is stack)
  6#Yk   %   Find which of the remaining points is closest to current point. This
         %   is the next char in the string
  2#)    %   Remove the point with that index from the array of complex
         %   coordinates. Push that point and the rest of the array
  yw     %   Duplicate extracted point, swap
]        % End for
xx       % Delete top two elements of the stack
v        % Concatenate all stack contents into a column array. This array
         % contains the complex coordinates of chars sorted to form the string
tXjwYj   % Extract real part and imaginary part
GZy1)    % Number of rows of input. Needed to convert to linear index
*+       % Convert rows and columns to linear index
Gw       % Push input below that
)        % Index to get the original chars with the computed order
1e       % Force the result to be a row array (string). Implicitly display

説明が近づいていると思いますか?
マット

@Matt Sure ...後日:-)
ルイスメンドー

@Mattの説明を追加
ルイスメンドー

The initial point is the endpoint whose complex coordinate has the least absolute value注意:ユークリッド距離!=マンハッタン距離。たとえば、ポイント7 + 7jのユークリッド距離は9.8994、マンハッタン距離14です。10jはユークリッド距離だけ離れていますが、マンハッタン距離はかなり近いです。それ以外は素晴らしいコンセプトです!
レベルリバーセント

@LevelRiverStありがとう!修正済み
ルイスメンドー

14

C 198 190 179 180 181バイト

編集:user81655によるヒントを使用し、三項演算子の括弧を削除しました、ありがとう!また、より適切な(そしてより短い!)S%2の均一性のための扱いにくい(S&1)テストを変更しました。

Edit2:* aアドレッシングスタイルを多用することで、Sの定義における明白な最適化、つまり*(a + m)をa [m]などに置き換えることを知らなくなりました。その後、S自体をTに置き換えました。 Sが行うことの半分。また、コードはputcharの戻り値を利用しています。

Edit3:最初から存在していたバグを修正しました。マンハッタン検索の停止条件a <b + mは、aが既に減少している場合にのみ正しいです。これにより2バイトが追加されますが、mの定義をグローバルにすることで1バイトに戻ります。

Edit4:私のゴルフは最低限を超えており、間違った方向に進んでいます。マンハッタン検索に関連する別のバグ修正。私はもともとインバウンドチェックを行っていましたが、それらがないと、配列bを超える大きな入力配列(50x50の周り)の検索が続行されます。したがって、その配列は前のサイズの少なくとも2倍に拡張する必要があり、もう1バイト追加されます。

#define T(x)+x*((a[x]>32)-(a[-x]>32))
m=103;main(){char b[m<<8],*e=b,*a=e+m;while(gets(e+=m));for(e=a;(T(1)T(m))%2**a<33;a=a<b+m?e+=m:a)a-=m-1;for(;*a;a+=T(1)T(m))*a-=putchar(*a);}

ゴルフをしていないと説明:

/* T(1)T(m) (formerly S) is used in two ways (we implicitly assume that each cell has
   one or two neighbors to begin with):
   1. (in the first for-loop) T(1)T(m) returns an odd (even) number if cell a has one (two)
      neighbors with ASCII value > 32. For this to work m must be odd.
   2. (in the second for-loop) at this stage each cell a in the array at which T(1)T(m) is
      evaluated has at most one neighboring cell with ASCII value > 32. T(1)T(m) returns the
      offset in memory to reach this cell from a or 0 if there is no such cell.
      Putting the + in front of x here saves one byte (one + here replaces two
      + in the main part)

#define T(x)+x*((a[x]>32)-(a[-x]>32))

  /* A snake of length 100 together with the newlines (replaced by 0:s in memory) fits
     an array of size 100x101, but to avoid having to perform out-of-bounds checks we
     want to have an empty line above and the array width amount of empty lines below
     the input array. Hence an array of size 202x101 would suffice. However, we save
     a (few) bytes if we express the array size as m<<8, and since m must be odd
     (see 1. above), we put m = 103. Here b and e point to the beginning of the (now)
     256x103 array and a points to the beginning of the input array therein */

m=103;
main()
{

  char b[m<<8],*e=b,*a=e+m;

  /* This reads the input array into the 256x103 array */

  while(gets(e+=m));

  /* Here we traverse the cells in the input array one
     constant-Manhattan-distance-from-top-left diagonal at a time starting at the top-left
     singleton. Each diagonal is traversed from bottom-left to top-right since the starting point
     (memory location e) is easily obtained by moving one line downwards for each diagonal
     (+m) and the stopping point is found by comparing the present location a to the input array
     starting position (b+m). The traversal is continued as long as the cell has either
     an ASCII value < 33 or it has two neighbors with ASCII value > 32 each (T(1)T(m)
     is even so that (T(1)T(m))%2=0).
     Note that the pointer e will for wide input arrays stray way outside (below) the
     input array itself, so that for a 100 cell wide (the maximum width) input array
     with only two occupied cells in the bottom-right corner, the starting cell
     will be discovered 98 lines below the bottom line of the input array.
     Note also that in these cases the traversal of the diagonals will pass through the
     right-hand side of the 103-wide array and enter on the left-hand side. This, however,
     is not a problem since the cells that the traversal then passes have a lower
     Manhattan distance and have thereby already been analyzed and found not to contain
     the starting cell. */

  for(e=a;(T(1)T(m))%2**a<33;a=a<b+m?e+=m:a)a-=m-1;

  /* We traverse the snake and output each character as we find them, beginning at the
     previously found starting point. Here we utilize the function T(1)T(m), which
     gives the offset to the next cell in the snake (or 0 if none), provided that
     the current cell has at most one neighbor. This is automatically true for the
     first cell in the snake, and to ensure it for the rest of the cells we put the
     ASCII value of the current cell to 0 (*a-=putchar(*a)), where we use the fact
     that putchar returns its argument. The value 0 is convenient, since it makes the
     stopping condition (offset = 0, we stay in place) easy to test for (*a == 0). */

  for(;*a;a+=T(1)T(m))
    *a-=putchar(*a);
}

1
この答えは素晴らしいです。
16

+1これは素晴らしい。私の答えに説明を追加したいのですが、あなたのソリューションと比較してバイトを絞った場所を示していますが、大丈夫ですか?
ミリバイト

mIllIbyte-コメントを自由に追加してください。それが新しいアイデアへの道です。
ズンガ

user81655-ヒントのおかげで、6バイト削減されました。実際、昨日、(S&1)の代わりにS%2を使用して試してみましたが、偶数テストではさらに2バイト削りましたが、何らかの理由で(私のコードはどこかにバグがありました)適切に動作しませんでした。しかし、今ではすべてが問題ないようです。
ズンガ

非常に素晴らしい。などでさらに保存しa[1]、グローバルにします- 。a[-m]mm=103;main()
-ugoren

9

C、272バイト

#define E j+(p/2*i+1)*(p%2*2-1)
#define X(Y) a[Y]&&a[Y]-32
char A[999],*a=A+99;j,p,t;i;main(c){for(;gets(++j+a);j+=i)i=strlen(a+j);for(c=j;j--;){for(t=p=4;p--;)t-=X(E);t==3&&X(j)?c=c%i+c/i<j%i+j/i?c:j:0;}for(j=c;c;){putchar(a[j]),a[j]=0;for(c=0,p=4;!c*p--;)X(E)?c=j=E:0;}}

@Zungaのソースを見てください。今私のものを見てください。余分な91バイトをどのように取得したか知りたいですか?
ゴルフをしていない:

#define E j+(p/2*i+1)*(p%2*2-1)
#define X(Y) a[Y]&&a[Y]-32  //can be more concise, see @Zunga's
  //and then doesn't need the define
char A[999],*a=A+99;j,p,t;i;
main(c){for(;gets(++j+a);j+=i)
i=strlen(a+j); //we don't need to know the length of a line
  //in @Zunga's solution, lines are spaced a constant distance apart
for(c=j;j--;){
for(t=p=4;p--;)t-=X(E);  //a ton of bytes can be saved with determining 
  //the neighbors, see @Zunga's source
t==3&&X(j)?
c=c%i+c/i<j%i+j/i?c:j:0;}  //we search for ends of the snake, 
  //and compute the Manhattan distance
for(j=c;c;){putchar(a[j]),a[j]=0;
for(c=0,p=4;!c*p--;)  //determining the neighbors again
X(E)?c=j=E:0;}}

5

Python(2および3)、640 624 604 583 575 561 546 538バイト

私はまだゴルフn00bですので、これは少し大きいです。

編集:提案のため@porglezompに感謝します!Python 3が壊れる可能性があるため、「and」演算子をすべて削除しませんでした。

Edit2:isspace()についてのコメントをくれた@Aleksi Torhamoに感謝します。結果の削減は、私が入れたバグ修正を補います。また、構文の強調表示については匿名のおかげです!

Edit3:数バイト追加してくれた@ mbomb007に感謝します。

import sys;s=sys.stdin.read().split('\n');m={};q=[];o=len;j=o(s);r=range;g='!'
for y in r(j):
 v=s[y];f=o(v);d=y+1
 for x in r(f):
  n=[];a=n.append;U=s[y-1]
  if v[x]>=g:j>=y>0==(U[x]<g)<=x<o(U)and a((x,y-1));j>y>=0==(v[x-1]<g)<x<=f and a((x-1,y));j>y>-1<x+1<f>(v[x+1]<g)<1and a((x+1,y));j>d>-1<x<o(s[d])>(s[d][x]<g)<1and a((x,d));m[x,y]=[v[x],n];o(n)-1or q.append((x,y))
t=min(q,key=sum);w=sys.stdout.write;w(m[t][0]);c=m[t][1][0]
while o(m[c][1])>1:
 b=m[c][1];w(m[c][0])
 for k in r(o(b)):
  if b[k]!=t:t=c;c=b[k];break
print(m[c][0])

これが私のゴルフ前のバージョンです

import sys

lines = sys.stdin.read().split('\n')
startend = []
mydict = {}
for y in range( 0, len(lines)):
  for x in range( 0, len(lines[y])):
    if not lines[y][x].isspace():
      neighbors = []
      if x>=0 and x<len(lines[y-1]) and y-1>=0 and y-1<len(lines):
        if not lines[y-1][x].isspace():
          neighbors.append( (x,y-1) )
      if x-1>=0 and x-1<len(lines[y]) and y>=0 and y<len(lines):
        if not lines[y][x-1].isspace():
          neighbors.append( (x-1,y) )
      if x+1>=0 and x+1<len(lines[y]) and y>=0 and y<len(lines):
        if not lines[y][x+1].isspace():
          neighbors.append( (x+1,y) )
      if x>=0 and x<len(lines[y+1]) and y+1>=0 and y+1<len(lines):
        if not lines[y+1][x].isspace():
          neighbors.append( (x,y+1) )
      mydict[(x,y)] = [ lines[y][x], neighbors ]

      if len( neighbors ) == 1:
        startend.append( (x,y) )

startend.sort( key=lambda x : x[0]*x[0] + x[1]*x[1] )

last = startend[0]
sys.stdout.write( mydict[ last ][0] )
current = mydict[last][1][0]
while len( mydict[current][1] ) > 1:
  sys.stdout.write( mydict[current][0] )
  for k in range( 0, len( mydict[current][1] ) ):
    if mydict[current][1][k] != last:
      last = current
      current = mydict[current][1][k]
      break

print(mydict[current][0])

1
私が導入して12のバイトを保存S=lambda s:s.isspace()してから行ってS(s)代わりにs.isspace()
-porglezomp

1
副作用(比較チェーンの短絡)の点と同じであり、とにかく比較の結果を無視しているので、すべてをand toに変更することもできると思います。<f() < g() < h()g = g(); f() < g and g < h()
-porglezomp

1
m[(x,y)]=短いと同じですm[x,y]=
-porglezomp

2
@porglezomp:言うのはもっと短いですS=str.isspace
アレクシトルハモ

1
すべてのオカレンスで削除Sして代わりに使用<'!'すると、同じ長さになり、さらに節約できる可能性があります。たとえば、に変更if 1-S(v[x]):if(v[x]<'!')<1:ます。そして、後の比較でそのようにすることでいくつかの括弧を削除できるかもしれません。
mbomb007

4

JavaScript(ES6)、195

テストスニペット内の説明を参照してください

s=>[...s].map((c,i)=>{if(c>' '&([n=-1,1,o=-~s.search('\n'),-o].map(d=>n+=s[i+d]>' '&&!!(e=d)),n<1)&m>(w=i/o+i%o|0))for(m=w,r=c,p=i+e;r+=s[i=p],[e,o/e,-o/e].some(d=>s[p=i+(e=d)]>' '););},m=1/0)&&r

テスト

f=s=>[...s].map((c,i)=>{if(c>' '&([n=-1,1,o=-~s.search('\n'),-o].map(d=>n+=s[i+d]>' '&&!!(e=d)),n<1)&m>(w=i/o+i%o|0))for(m=w,r=c,p=i+e;r+=s[i=p],[e,o/e,-o/e].some(d=>s[p=i+(e=d)]>' '););},m=1/0)&&r

// Less golfed

u=s=>(
  o = -~s.search('\n'), // offset between lines
  m = 1/0, // current min manhattan distance, init at infinity
  // scan input looking for the 2 ends of the string
  [...s].map((c,i)=>{ // for each char c at position i
     if(c > ' ' // check if part of the string
        & ( [-1,1,o,-o] // scan in 4 directions and count neighbors
             .map(d=> n+=s[i+d]>' '&&!!(e=d), n=0), // remember direction in e
          n < 2) // if at end of string will have exactly 1 neighbor
        & (w = i/o + i%o |0) < m) // manhattan distance in w, must be less than current min
       // found one of the ends, follow the path and build the string in r
       for(m = w, r = c, p = i+e; 
           r += s[i=p], 
           [e,o/e,-o/e] // check 3 directions, avoiding to go back
           .some(d=>s[p=i+(e=d)]>' '); // save candidate position and direction in p and e
          ); // empty for body, all the work is inside the condition
  }),
  r
)  

console.log=x=>O.textContent+=x+'\n'

;[`Hel         
  l      rin
  o,IAmASt g
           S
       !ekan`,
 `   ~ zyx tsr XWVUTSR
   }|{ wvu q Y     Q
!          p Z \`ab P
"#$ 6789:; o [ _ c O
  % 5    < n \\]^ d N
('& 432  = m     e M
)     1  > lkjihgf L
*+,-./0  ?         K
         @ABCDEFGHIJ`].forEach(t=>{
  console.log(t+'\n\n'+f(t)+'\n')
  })
<pre id=O></pre>


セミコロンは););}必要ですか?
シーズティマーマン

1
@CeesTimmermanはい。1つ目はfor、2つのコロンが必要なヘッダー内です。2番目はfor体の
デリミターです-edc65

3

Lua、562 535 529 513 507 504 466 458バイト

現時点で私の最も大規模なゴルフでは、100バイトを切り捨てることができると思いますが、これには努力しますが、すでに時間がかかっているので回答として投稿します:)。私は正しかった、私は100バイト以上を削減しました!改善の余地はあまりないと思います。

この関数は、セルごとに1文字を含む2D配列で呼び出す必要があります。

彼のおかげで、@ KennyLauでの作業中に40バイトを節約できました!

やったー!500未満!

function f(m)t=2u=1i=1j=1s=" "::a::if s~=m[i][j]and(i<#m and m[i+1][j]~=s)~=(j<#m[i]and m[i][j+1]~=s)~=(i>1 and m[i-1][j]~=s)~=(j>1 and m[i][j-1]~=s)then goto b end
i,t=i%t+1,#m>t and t==i and t+1or t j=j>1 and j-1or u u=u<#m[1]and j==1 and u+1or u goto a::b::io.write(m[i][j])m[i][j]=s
i,j=i<#m and s~=m[i+1][j]and i+1or i>1 and s~=m[i-1][j]and i-1or i,j<#m[i]and s~=m[i][j+1]and j+1or j>1 and s~=m[i][j-1]and j-1or j
if s==m[i][j]then return end goto b end

非ゴルフ

これをゴルフでやったら、説明が来るでしょう。とりあえず、このソースコードの読みやすいバージョンをお貸しします:Dここに説明があります!

編集:最新の修正では更新されませんが、更新前はゴルフを続けます。説明についても同じ

function f(m)                    -- declare the function f which takes a matrix of characters
  t=2                            -- initialise the treshold for i
                                 -- when looking for the first end of the snake
  u=1                            -- same thing for j
  i,j=1,1                        -- initialise i and j,our position in the matrix
  s=" "                          -- shorthand for a space
  ::a::                          -- label a, start of an infinite loop
    if m[i][j]~=s                -- check if the current character isn't a space
      and(i<#m                   -- and weither it is surrounded by exactly
          and m[i+1][j]~=s)      -- 3 spaces or not
      ~=(j<#m[i]
          and m[i][j+1]~=s)      -- (more explanations below)
      ~=(i>1 
          and m[i-1][j]~=s)
      ~=(j>1
          and m[i][j-1]~=s)
      then goto b end            -- if it is, go to the label b, we found the head
    i,t=                         -- at the same time
      i%t+1,                     -- increment i
      #m>t and t==i and t+1or t  -- if we checked all chars in the current range, t++
    j=j>1 and j-1or u            -- decrement j
    u=u>#m[1]and j==1 and u+1or u-- if we checked all chars in the current range, u++
  goto a                         -- loop back to label a

  ::b::                          -- label b, start of infinite loop
  io.write(m[i][j])                    -- output the current char
    m[i][j]=s                    -- and set it to a space
    i,j=i<#m                     -- change i and j to find the next character in the snake
          and m[i+1][j]~=s       -- this nested ternary is also explained below
            and i+1              -- as it takes a lot of lines in comment ^^'
          or i>1 
            and m[i-1][j]~=s
            and i-1
          or i,
       j<#m[i] 
         and m[i][j+1]~=s
           and j+1
         or j>1 
           and m[i][j-1]~=s 
           and j-1
         or j
    if m[i][j]==s                -- if the new char is a space
    then                         -- it means we finished
      return                  -- exit properly to avoid infinite
    end                          -- printing of spaces
  goto b                         -- else, loop back to label b
end

そこで、このプログラムがどのように機能するかについての詳細な説明があります。

まず、ラベルの付いたループを考えてみましょうa。これにより、左上隅に最も近い端を見つけることができます。終わりがない場合、それは永遠にループしますが、それは問題ではありません:D。

4x4グリッドでは、スネークの距離(左)と、それらが見られる順序(右)です。

1  2  3  4    |     1  2  4  7
2  3  4  5    |     3  5  8 11
3  4  5  6    |     6  9 12 14
4  5  6  7    |    10 13 15 16

この文字のそれぞれについて、最後に2つの条件を確認する必要があります。-スペースではない-正確に3つのスペース(または正確に1つの非スペース)に囲まれている

これらの条件は、次のコードで確認されます

r=m[i][j]~=s
    and(i<#m and m[i+1][j]~=s)
    ==not(j<#m[i] and m[i][j+1]~=s)
    ==not(i-1>0 and m[i-1][j]~=s)
    ==not(j-1>0 and m[i][j-1]~=s)
    and m[i][j]
    or r
  -- special note: "==not" is used as an equivalent to xor
  -- as Lua doesn't know what is a xor...

文字がスペースでないかどうかを確認するには、式を使用しm[i][j]~=sます。

wが1つだけの非スペースに囲まれているかどうかを確認するには、周囲の上記の条件をxor-ingすることで、次のように記述できます。

m[i+1][j]~=" "  m[i][j+1]~=" "  m[i-1][j]~=" "  m[i][j-1]~=" "

最後に、上記のすべてがtrueと評価された場合、3進数は最後のand-> を返しm[i][j]ます。それ以外の場合は、r設定を解除します:)

ヘビの頭ができたので、もう一方の端まで行きましょう!ヘビの反復は、主に次のネストされた3要素によって実現されます。

i,j=i<#m and m[i+1][j]~=s and i+1or i-1>0 and m[i-1][j]~=s and i-1or i,
    j<#m[i]and m[i][j+1]~=s and j+1or j-1>0 and m[i][j-1]~=s and j-1or j

古い値を保存するためにダミーが必要になるのを回避するために再設定するij同時に、それらは両方ともまったく同じ構造を持ち、単純な条件を使用するため、これらをネストされた形式で提示しifます。もっと簡単に。:)

i=i<#m and m[i+1][j]~=s and i+1or i-1>0 and m[i-1][j]~=s and i-1or i

以下に翻訳できます:

if(i<#m)
then
  if(m[i+1][j]~=" ")
  then
    i=i+1
  end
elseif(i-1>0)
then
  if(m[i-1][j]~=" ")
  then
    i=i-1
  end
end

試して!

これを実行するために使用するコードは次のとおりです。コピーして貼り付けてオンラインでテストできます。

function f(m)t=2u=1i=1j=1s=" "::a::if s~=m[i][j]and(i<#m and m[i+1][j]~=s)~=(j<#m[i]and m[i][j+1]~=s)~=(i>1 and m[i-1][j]~=s)~=(j>1 and m[i][j-1]~=s)then goto b end
i,t=i%t+1,#m>t and t==i and t+1or t j=j>1 and j-1or u u=u<#m[1]and j==1 and u+1or u goto a::b::io.write(m[i][j])m[i][j]=s
i,j=i<#m and s~=m[i+1][j]and i+1or i>1 and s~=m[i-1][j]and i-1or i,j<#m[i]and s~=m[i][j+1]and j+1or j>1 and s~=m[i][j-1]and j-1or j
if s==m[i][j]then return end goto b end


test1={}
s1={
"  tSyrep    ",
"  r    p    ",
"  in Sli    ",
"   g    Sile",
"   Snakes  n",
"Ser      ylt",
"a eh   ilS  ",
"fe w   t    ",
"   emo h    ",
"     Sre    ",
     }
for i=1,#s1
do
  test1[i]={}
  s1[i]:gsub(".",function(c)test1[i][#test1[i]+1]=c end)
end
f(test1)

1
Aには、言語の選択のために今のところほとんど選択肢がない長い回答のソフトスポットがあります。
マット

@Mattはサポートに感謝します!実際、私はまだこれをダウンさせる方法を見つけていますが、ますます難しくなっています!
かてんきょう

2

Lua、267バイト

Lua 5.3が必要です。

e=" "w=#arg[1]+1i=1/0q=0s=table.concat(arg,e)s=e:rep(#s)..s
m,n=i,{}for p in s:gmatch"()%g"do u=-1
for _,d in ipairs{-1,1,-w,w}do u=u+(s:find("^%S",d+p)or 0)end
n[p]=u+1m=math.min(m,p*i^(u//#s)+(p%w*w+p)*#s)end
p=m%#s repeat q,p=p,n[p]-q io.write(s:sub(q,q))until p<1

使用法:

$ lua desnakify.lua \
>    "  tSyrep    " \
>    "  r    p    " \
>    "  in Sli    " \
>    "   g    Sile" \
>    "   Snakes  n" \
>    "Ser      ylt" \
>    "a eh   ilS  " \
>    "fe w   t    " \
>    "   emo h    " \
>    "     Sre    "
SlipperyStringSnakesSilentlySlitherSomewhereSafe

2

Python 3、 245 243 241 236バイト

sは入力文字列、n出力は標準出力に出力されます。

f=s.find
w,l=f('\n')+1,len(s)
t=1,w,-1,-w
y=z=f(s.strip()[0]);n=s[y];v={y}
for i in range(l*l):
 i%=l;c=s[i]
 if c>' 'and i not in v:
  if i-y in t:y=i;n=c+n;v|={i}
  elif i-z in t:z=i;n+=c;v|={i}
if y%w+y//w>z%w+z//w:n=n[::-1]
print(n)

編集: 5バイトを保存してくれた@Cees Timmermanに感謝します!


c>' 'andそして、print nPythonの2の
CEES Timmerman

if代わりにできませんelifか?
clismique

残念ながら@ Qwerp-Derpではありません。以前に試しましたが、たとえば「!ekanSgnirtSAmAI、olleHello、IAmAStringSnake!」と出力されます。および「SlipperyStSyreppilS」。
pgks

入力形式は何ですか?
-clismique

@ Qwerp-Derp s変数は複数行の文字列です。文字列の最後の文字は改行でなければなりません(これはPythonテストケースに合格するために必要です)
pgks

1

Python、537

私の最初の解決策:

from itertools import chain, product, ifilter
from operator import add
moves = ((1,0),(0,1),(-1,0),(0,-1))
h = dict(ifilter(lambda (p,v):not v.isspace(),chain(*map(lambda (i,r):map(lambda (j,c):((i,j),c),enumerate(r)),enumerate(s)))))
n = defaultdict(list)
for m,p in product(moves, h):
    np = tuple(map(add,m,p))
    if np in h:
        n[p].append(np)
def pr(nx):
    return(lambda l:(h[l[0]], h.pop(l[0]))[0] + pr(l[0]) if l else '')([x for x in n[nx] if x in h])
(lambda y: h[y]+ pr(y))(next(x for x in n if len(n[x])==1))

少し圧縮しましたが、メソッドとして残しました:

from itertools import chain, product
from operator import add
def unsnake(s):
    (h,n) = (dict(filter(lambda (p,v):not v.isspace(),chain(*map(lambda (i,r):map(lambda (j,c):((i,j),c),enumerate(r)),enumerate(s))))),defaultdict(list))
    for m,p in product(((1,0),(0,1),(-1,0),(0,-1)), h):(lambda np: n[p].append(np) if np in h else 0)(tuple(map(add,m,p)))
    def pr(nx):return(lambda l:(h[l[0]], h.pop(l[0]))[0] + pr(l[0]) if l else '')([x for x in n[nx] if x in h])
    return(lambda y: h[y]+ pr(y))(next(x for x in n if len(n[x])==1))

1

Java 7、927 924 923バイト

import java.util.*;int l,k;char[][]z;Set p=new HashSet();String c(String[]a){int x=0,y=0,n,t,u,v,w=t=u=v=-1;l=a.length;k=a[0].length();z=new char[l][k];for(String s:a){for(char c:s.toCharArray())z[x][y++]=c;}x++;y=0;}for(x=0;x<l;x++)for(y=0;y<k;y++){n=0;if(z[x][y]>32){if(x<1|(x>0&&z[x-1][y]<33))n++;if(y<1|(y>0&&z[x][y-1]<33))n++;if(x>l-2|(x<l-1&&z[x+1][y]<33))n++;if(y>k-2|(y<k-1&&z[x][y+1]<33))n++;}if(n>2&t<0){t=x;u=y;}if(n>2&t>v){v=x;w=y;}}if(v+w>t+u){p(t,u);return n(""+z[t][u],t,u);}p(v,w);return n(""+z[v][w],v,w);}String n(String r,int x,int y){int a,b;if(x>0&&z[a=x-1][b=y]>32&q(a,b)){p(a,b);return n(r+z[a][b],a,b);}if(y>0&&z[a=x][b=y-1]>32&q(a,b)){p(a,b);return n(r+z[a][b],a,b);}if(x<l-1&&z[a=x+1][b=y]>32&q(a,b)){p(a,b);return n(r+z[a][b],a,b);}if(y<k-1&&z[a=x][b=y+1]>32&q(a,b)){p(a,b);return n(r+z[a][b],a,b);}return r;}boolean q(int x,int y){return!p.contains(x+","+y);}void p(int x,int y){p.add(x+","+y);}

一部のプログラミング言語では、配列xとyが2D配列の境界外にあるかどうかは関係ありませんが、JavaではスローArrayIndexOutOfBoundsExceptionsされるため、すべてをチェックする必要があります。

最初に開始点を決定し、次に再帰的なメソッドを使用してそこから文字列を作成します。さらに、リストを使用して、既に遭遇した調整を追跡するため、前後にループが発生することはありません(結果としてStackOverflowExceptionが発生します)。

これはおそらく私がこれまでに投稿した中で最長の回答ですが、一部のパーツはゴルフをすることができますが、この課題はJavaではそれほど短くなるとは思いません。Javaは、グリッド内のパスをたどるのには適していないだけです。:)

未ゴルフ&テストケース:

ここで試してみてください。

import java.util.*;
class M{
  static int l,
             k;
  static char[][] z;
  static Set p = new HashSet();

  static String c(String[] a){
    int x=0,
        y=0,
        n,
        t,
        u,
        v,
        w = t = u = v = -1;
    l = a.length;
    k = a[0].length();
    z = new char[l][k];
    for(String s:a){
      for(char c:s.toCharArray()){
        z[x][y++] = c;
      }
      x++;
      y = 0;
    }
    for(x=0; x<l; x++){
      for(y=0; y<k; y++){
        n = 0;
        if(z[x][y] > 32){ // [x,y] is not a space
          if(x < 1 | (x > 0 && z[x-1][y] < 33)){
            n++;
          }
          if(y < 1 | (y > 0 && z[x][y-1] < 33)){
            n++;
          }
          if(x > l-2 | (x < l-1 && z[x+1][y] < 33)){
            n++;
          }
          if(y > k-2 | (y < k-1 && z[x][y+1] < 33)){
            n++;
          }
        }
        if(n > 2 & t < 0){
          t = x;
          u = y;
        }
        if(n > 2 & t > v){
          v = x;
          w = y;
        }
      }
    }
    if(v+w > t+u){
      p(t, u);
      return n(""+z[t][u], t, u);
    }
    p(v, w);
    return n(""+z[v][w], v, w);
  }

  static String n(String r, int x, int y){
    int a,b;
    if(x > 0 && z[a=x-1][b=y] > 32 & q(a,b)){
      p(a, b);
      return n(r+z[a][b], a, b);
    }
    if(y > 0 && z[a=x][b=y-1] > 32 & q(a,b)){
      p(a, b);
      return n(r+z[a][b], a, b);
    }
    if(x < l-1 && z[a=x+1][b=y] > 32 & q(a,b)){
      p(a, b);
      return n(r+z[a][b], a, b);
    }
    if(y < k-1 && z[a=x][b=y+1] > 32 & q(a, b)){
      p(a, b);
      return n(r+z[a][b], a, b);
    }
    return r;
  }

  static boolean q(int x, int y){
    return !p.contains(x+","+y);
  }

  static void p(int x, int y){
    p.add(x+","+y);
  }

  public static void main(String[] a){
    System.out.println(c(new String[]{ "Hel         ",
      "  l      rin",
      "  o,IAmASt g",
      "           S",
      "       !ekan" }));
    p = new HashSet();
    System.out.println(c(new String[]{ "Python" }));
    p = new HashSet();
    System.out.println(c(new String[]{ "P  ngPu  Code ",
      "r  i  z  d  G",
      "o  m  z  n  o",
      "gram  lesA  lf" }));
    p = new HashSet();
    System.out.println(c(new String[]{ "   ~ zyx tsr XWVUTSR",
      "   }|{ wvu q Y     Q",
      "!          p Z `ab P",
      "\"#$ 6789:; o [ _ c O",
      "  % 5    < n \\]^ d N",
      "('& 432  = m     e M",
      ")     1  > lkjihgf L",
      "*+,-./0  ?         K",
      "         @ABCDEFGHIJ" }));
    p = new HashSet();
    System.out.println(c(new String[]{ "  tSyrep    ",
      "  r    p   ",
      "  in Sli   ",
      "   g    Sile",
      "   Snakes  n",
      "Ser      ylt",
      "a eh   ilS ",
      "fe w   t   ",
      "   emo h   ",
      "     Sre    " }));
  }
}

出力:

Hello,IAmAStringSnake!
Python
ProgrammingPuzzlesAndCodeGolf
!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
SlipperyStringSnakesSilentlySlitherSomewhereSafe

924バイト、イエス・キリスト... lol
ショーン・ワイルド

@BasicallyAlanTuring Hehe。私は単にチャレンジをして、コードゴルフをして、バイトカウントを調べました。実際に予想よりもはるかに高かったが、少なくとも1k未満です...改善するものがあれば、お知らせください。役職; 私はそれを見て興味があります。PS:現在は923バイトです。XD
ケビンCruijssen

everythigチェックする必要はありません。文字列にパディングを追加するだけです。おそらく、単一の複数行の文字列を使用することで簡単になります。JavaScriptから移植された私のC#回答を
ご覧ください

1

PHP、199の 184 182バイト

まだ少しゴルフの可能性があるかもしれません

for($w=strpos($i=$argv[1],"
");;)for($y=++$n;$y--;)if($i[$p=$y*$w+$n-1]>" ")break 2;for($p-=$d=$w++;$d&&print$i[$p+=$e=$d];)foreach([-$w,-1,1,$w,0]as$d)if($d+$e&&" "<$i[$d+$p])break;

コマンドラインから入力を複数行の文字列として受け取り、Linuxスタイルの改行が必要です。
実行php -r '<code>' '<string>'; 改行をエスケープします。

壊す

for(
    // find width
    $w=strpos($i=$argv[1],"\n")
    ;
    // find first character: initialize $p(osition)
    ;
)
    for($y=++$n             // increase distance
        ;$y--;)             // loop $y from (old)$n to 0
        if(" "<$i[$p=$y*$w+$n   // if character at $y*($width+1)+$x(=$d-$y) is no space
            -1                  // (adjust for the premature increment)
        ])
            break 2;                    // break loops

for(
    $p-=            // b) reverse the increment that follows in the pre-condition
    $d=             // a) initialize $d to anything!=0 to enable the first iteration
    $w++;           // c) increase $w for easier directions
    $d              // loop while direction is not 0 (cursor has moved)
    &&
    print$i[$p+=$e=$d]              // remember direction, move cursor, print character
    ;
)
    foreach([-$w,-1,1,$w,0]as$d)// loop through directions
        if($d+$e                    // if not opposite previous direction
            &&" "<$i[$d+$p]         // and character in that direction is not space
        )break;                     // break this loop

1

C#、310

(編集:バグ修正)

文字列を返す、複数行の文字列パラメーターを持つ関数。

要求さusingれたものをバイト数に含めます。

これは、javascriptの回答の移植です。

using System.Linq;
string f(string s){int o=-~s.IndexOf('\n'),m=99;var r=new string(' ',o);(s=r+s+r).Select((c,i)=>{int n=2,e=0,p,w=i%o+i/o;if(c>' '&w<m&&new[]{-1,1,o,-o}.All(d=>(s[i+d]>' '?(e=d)*--n:n)>0))for(m=w,r=""+c+s[p=i+e];new[]{e,o/e,-o/e}.Any(d=>s[p+(e=d)]>' ');)r+=s[p+=e];return i;}).Max();return r;}

イデオンでテストする

スペースあり

    string f(string s)
    {
        int o = -~s.IndexOf('\n');
        var r = new string(' ', o);
        var m = 99;
        (s = r + s + r).Select((c, i) =>
        {
            int n = 2, e = 0, p, w = i % o + i / o;
            if (c > ' ' & w < m & new[] { -1, 1, o, -o }.All(d => (s[i + d] > ' ' ? (e = d) * --n : n) > 0))
                for (m = w, r = "" + c + s[p = i + e]; 
                     new[] { e, o / e, -o / e }.Any(d => s[p + (e = d)] > ' '); 
                     ) 
                   r += s[p += e];
            return i;
        }
        ).Max();
        return r;
    }

1

Python 2、251バイト

w=s.find('\n')+1;q=' ';p=q*w+'\n';s=list(p+s+p);d=-w,1,w,-1
def r(x):c=s[x];s[x]=q;v=[c+r(x+o)for o in d if s[x+o]>q];return v[0]if v else c
e=[x for x in range(len(s))if s[x]>q and sum([s[x+o]>q for o in d])<2]
print r(e[e[0]/w+e[0]%w>e[1]/w+e[1]%w])

または、テストケースの先頭の改行が必要な場合、257バイト:

w=s.find('\n',1);q=' ';p=q*-~w+'\n';s=list(p+s[1:]+p);d=-w,1,w,-1
def r(x):c=s[x];s[x]=q;v=[c+r(x+o)for o in d if s[x+o]>q];return v[0]if v else c
e=[x for x in range(len(s))if s[x]>q and sum([s[x+o]>q for o in d])<2]
print r(e[e[0]/w+e[0]%w>e[1]/w+e[1]%w])

すべてのテストケースに合格します。

s="""
  tSyrep    
  r    p    
  in Sli    
   g    Sile
   Snakes  n
Ser      ylt
a eh   ilS  
fe w   t    
   emo h    
     Sre    
"""

結果:

SlipperyStringSnakesSilentlySlitherSomewhereSafe

3
私はあなたが交換することができると思うb.append(...)b+=[...]def n(x,y):return ...n=lambda x,y:...
acrolith

1
の変数を作成します' '
パチョリク

1
~-x代わりx-1に使用する場合、括弧を使用する必要はありません。
パチョリク

0

Japt -P、106バイト

K=U·ÌÊÄ ç iU ¬mx T=[-KJ1K]
ËÊ*Tm+E è@gX
[]V£YÃf@gXÃrQ@WpQ Tm+Q kW fZ Ì}V£[XYuK YzK]ÃkÈv ÉÃñx v rÈ+Y*K
W£gX

オンラインでお試しください!

それは...ええと...憎むべきものです。

開梱と仕組み

K=UqR gJ l +1 ç iU q mx
  UqR gJ l +1            Split the input by newline, take last item's length +1
K=                       Assign to K
              ç iU       Generate a string of K spaces, and append to U
                   q mx  Split into chars, and trim whitespaces on each item
                         Implicit assign to U

T=[-KJ1K]  Assign an array [-K, -1, 1, K] to T (this represents 4-way movement)
           I could use implicit assignment, but then 4-argument function below is broken

UmDEF{Dl *Tm+E èXYZ{UgX
UmDEF{                   Map over the list of one- or zero-length strings...
      Dl *                 If the length is zero, return zero
          Tm+E             Add the index to each element of T
               èXYZ{UgX    Count truthy elements at these indices
                         The result is an array of 0(space/newline), 1(start/end), or 2(body)
                         Implicit assign to V

[]  Implicit assign to W

VmXYZ{Y} fXYZ{UgX} rQXYZ{WpQ Tm+Q kW fZ gJ }
VmXYZ{Y}                                      Map V into indices
         fXYZ{UgX}                            Filter the indices by truthiness of U's element
                   rQXYZ{                     Reduce on the indices... (Q=last item, Z=array)
                         WpQ                    Push Q to W
                             Tm+Q               Take 4-way movements from Q
                                  kW fZ gJ }    Exclude visited ones, take last one in Z

VmXYZ{[XYuK YzK]} kXYZ{Xv -1} ñx v rXYZ{X+Y*K  Starting point of reduce
VmXYZ{[XYuK YzK]}                              Convert elements of V to [elem, col, row]
                  kXYZ{Xv -1}                  Take the ones where elem(popped)=1
                              ñx v             Sort by row+col and take first one
                                   rXYZ{X+Y*K  Convert [row,col] back to the index

WmXYZ{UgX  Map indices back to chars

-P  Join with empty string

注目すべき点の1つは、JSで割り当て演算子とコンマ演算子の間に演算子の優先順位を使用して、いくつかの行を詰め、ショートカット@XYZ{)を使用できるようにすることです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.