パスを見つけてください!


10

プログラムまたは関数を記述する必要があります。

入力は数値の「マップ」です。マップを改行文字(\n)付きの文字列または文字列の2D配列のいずれかとして選択できます。

すべてのマップは5文字x 5文字で、文字は常に0より大きい数字かスペースです。

これが地図の例です:

12 45
11233
  233
    1
2 899

あなたの仕事は、マップで接続されたコンポーネントを見つけることです。有効なコンポーネントは、水平または垂直(斜めではなく)に接続された少なくとも3つの一連の同一の数字(スペースではない)です。次に、有効な接続コンポーネントの文字をxs に置き換え、その結果を印刷または返す必要があります。

したがって、上記の例の出力は次のようになります。

x2 45
xx2xx
  2xx
    1
2 899

これは別のテストケースです(Martin Enderに感謝):

Input:
2   3
    4
 1  5
111 6
11  7

Output:
2   3
    4
 x  5
xxx 6
xx  7

これはコードゴルフなので、バイト単位の最短コードが勝ちます!



ビルトインは許可されていますか?
Ioannes

@Joannes、ええ。
ダニエル

回答:


1

JavaScriptの(ES6)、171 161 139 137の 136 133 132バイト

f=(a,i=0)=>(F=i=>" "<c&&a[i]===c&&(a[i]=n,1+F(i-1)+F(i+1)+F(i-6)+F(i+6)),n=1,c=a[i],n=F(i)>2?"x":c,c=1,F(i),i>28?a:f(a,++i+(i%6>4)))
<!-- this HTML included just for testing --><textarea rows=5 cols=6 oninput="document.querySelector`pre`.innerHTML=this.value.length==29?f([...this.value]).join``:'invalid input'">12 45&#10;11233&#10;  233&#10;    1&#10;2 899</textarea><br/><pre></pre>

これは私のPythonの回答の翻訳です。文字配列としてのI / O。

残念ながら効率的な方法はありませんsum...


5

Python 3、238 237 200 199 192 181バイト

def f(a,i=0):F=lambda i,n,c:29>i>=0!=" "!=a[i]==c!=n and(a.__setitem__(i,n)or-~sum(F(i+j,n,c)for j in[-1,1,-6,6]));j=i+i//5;F(j,[a[j],"x"][2<F(j,1,a[j])],1);i>23or f(a,i+1);return a

f(a)入力を文字の配列として受け取り、変更された同じ配列を返す関数を定義します。(文字の配列はデフォルトで文字列として受け入れられます。

説明なしのゴルフ

変更されたコードは再帰的ですが、同じように機能します。

# The main function; fills all continuous nonempty areas of size >= 3 in array
# with x's. Both modifies and returns array.
def findpaths(array):
    # Fills a continuous area of curr_char in array with new_char, starting
    # from index. Returns the number of cells affected.
    def floodfill(index, new_char, curr_char):
        if (0 <= index < 29                   # Check that the position is in bounds
                and (index + 1) % 6 != 0      # Don't fill newlines
                and array[index] != " "       # Don't fill empty cells
                and array[index] == curr_char # Don't fill over other characters
                and curr_char != new_char):   # Don't fill already filled-in cells
            array[index] = new_char # Fill current position
            return (1 # Add neighboring cells' results, plus 1 for this cell
                    + floodfill(index + 1, new_char, curr_char)  # Next char
                    + floodfill(index - 1, new_char, curr_char)  # Previous char
                    + floodfill(index + 6, new_char, curr_char)  # Next line
                    + floodfill(index - 6, new_char, curr_char)) # Previous line
        return 0 # Nothing was filled. The golfed solution returns False here,
                 # but that's coerced to 0 when adding.

    for i in range(25): # Loop through the 25 cells
        i += i // 5 # Accommodate for newlines in input
        curr_char = array[i] # Get the cell's contents
        # Fill the area from the cell with dummies
        area_size = floodfill(i, 1, curr_char)
        # Convert dummies to "x" if area was large enough, back to original otherwise
        fill_char = "x" if 2 < area_size else curr_char
        floodfill(i, fill_char, 1)
    return array

mathematicaソリューションを打ち負かすために2バイトオフ...
FlipTack

1
@FlipTackうん。今日は起こっていないと思いますが、これをJSに翻訳しています。
PurkkaKoodari 2017年

3

Ruby、304バイト

def b(s,i)
  @v=[]
  b2(s,i,s[i])
end
def b2(s,i,c)
  if(0...s.size)===i&&s[i]==c&&!@v[i]
    @v[i]=s[i]='x'
    [1,-1,6,-6].each{|j|b2(s,i+j,c)}
  end
  s
end
def f(s)
  z = s.dup
  ps = ->(i){b(z.dup,i).scan('x').size}
  (0...s.size).each{|i|b(s, i)if ![' ',"\n"].include?(s[i])&&ps.call(i)>2}
  s
end

使用例:

puts f(File.read("map.txt"))

コードは 'blot'メソッドを再利用してパスの長さを計算します。

変数/メソッド:

  • f(s):マップ文字列を変換する関数。'x 'を含む新しいマップを返します
  • ps(i):マップインデックスiからのパスサイズ(x = i%6、y = i / 6)
  • s:入力文字列、「\ n」で区切られたマップ行
  • z:入力文字列のコピー
  • b(s、i): 'blot'関数:パス上のマップインデックスiから 'x'を書き込みます
  • @v: 'visited'配列

より詳細な説明を試みてください:

入力文字列のコピーを作成します。これは、マップ内の任意のポイントからのパスの長さを見つけるために使用します。

z = s.dup

マップインデックスiを引数として取る「ps」(パス長)無名関数(ラムダ)を定義します。そのポイントからのパスの長さを返します。これは、 'b'(ブロット)メソッドを呼び出して元のマップのコピーにxを挿入し、返された文字列内のxの数を数えることによって行われます。

  ps = ->(i){b(z.dup,i).scan('x').size}

次の部分は、マップ内の各文字(インデックスi、文字s [i])を反復処理します。位置iからのパスの長さが2より大きい場合、およびスペースまたは改行文字でない場合は、マップ位置iで「b」(ブロット)関数を呼び出します。

  (0...s.size).each { |i|
     b(s, i) if ![' ',"\n"].include?(s[i]) && ps.call(i) > 2
  }

b(ブロット)関数は、マップ文字列とインデックスを引数として受け取ります。@v(visited array)を初期化し、b2ヘルパー関数を呼び出します。

def b(s,i)
  @v=[]
  b2(s,i,s[i])
end

b2関数は、マップ文字列、マップ位置(i)、および現在のパス内の文字(c)を受け取ります。自分自身を再帰的に呼び出して、数字の接続されたセクションを「x」文字に置き換えます。入力文字列を返します(これにより、ps関数は戻り値に対してscan()を呼び出すことができます)。

このifステートメントは、指定されたマップ位置(i)が文字列(0 ... s.size)の境界内にあり、s [i]の文字が開始文字と同じであることを確認しています。また、@ v [i]は無限再帰を回避するためにチェックされます。

if(0...s.size) === i && s[i] == c && !@v[i]

これは、インデックス(i)の文字を「x」文字に置き換えるビットです。また、そのインデックスを訪問済みとしてマークします。

@v[i] = s[i] = 'x'

これは、b2がパスを再帰的に検索して呼び出す場所です。i + 1は右に1文字、i-1は左に1文字、i + 6は1行下(5桁+ 1改行= 6文字)、i-6は1行上です。

[1,-1,6,-6].each { |j| b2(s, i+j, c) }

1

C(Ansi)、243 233 179 188バイト

ゴルフ:

#define O o[1][l]
x,n,l,L;r(o,l)char**o;{if(!(l>L|l<0|O<47|O!=x))n++,O++,r(o,l-1),r(o,l+6),r(o,l-6),r(o,l+1),n>2?O='x':O--;}main(g,o)char**o;{for(;(L=30)>l;l++)n=0,x=O,r(o,l);puts(o[1]);}

注釈付き:

#define O o[1][l]
x,n,l,L;      /*-------------------------- Globals*/
r(o,l)char**o;{ /*------------------------ Recursive Function*/
    if(!(l>L|l<0|O<47|O!=x)) /*----------- if this cell is valid(in
                                              range, is a number, is the 
                                              same as the parent number*/
    n++,     /*--------------------------- Increment count*/
    O++,     /*--------------------------- Increment character to mark*/
    r(o,l-1),  /*------------------------- Recurse left*/
    r(o,l+6),  /*------------------------- Recurse down*/
    r(o,l-6),  /*------------------------- Recurse down*/
    r(o,l+1),  /*------------------------- Recurse right*/
    n>2?O='x':O--;  /*---------------------If greater than 3, replace with x, else decrement character*/ 
}          /*----------------------------- Return*/

main(g,o)char**o;{ /*--------------------- Main*/
    for(;l<(L=30);l++){ /*---------------- For entire string and set L*/
        n=0;
        x=O;        /*-------------------- set counter to 0*/
        r(o,l); /*------------------------ Recurse*/
    } /*---------------------------------- End While*/
    puts(o[1]); /*------------------------ Print*/

}

入力:

文字列の最初と最後に改行が必要です。

入力例:

./findPaths "
12 45
11233
  233
    1
2 899
"

出力例:

x2 45
xx2xx
  2xx
    1
2 899

更新

グリッドを固定すると、60バイト近くを削ることができました。


これをフィックスマップサイズに変更すると、22文字程度節約できると思います。変更したいものがあれば、変更します
dj0wns

1

Mathematica、180バイト

(f=Flatten@#;p=Partition)[If[Tr[1^VertexComponent[r~Graph~Cases[##&@@p[#,2,1]&/@Join[g=p[r,5],g],{a_,b_}/;(A=f[[a]])==f[[b]]&&A!=" ":>a<->b],#]]<3,f[[#]],"x"]&/@(r=Range@25),5]&

説明:

(f=Flatten@#;p=Partition)[
  If[
    Tr[1^VertexComponent[
        r~Graph~Cases[
          ##&@@p[#,2,1]&/@Join[g=p[r,5],g],
          {a_,b_}/;(A=f[[a]])==f[[b]]&&A!=" ":>a<->b
        ],
        #
      ]]<3,
    f[[#]],
    "x"
  ]&/@(r=Range@25),
  5
]&

5x5配列を受け付ける純粋な関数。後置転置演算子を表す3バイトの私用文字です。U+F3C7\[Transpose]です。

(f=Flatten@#;p=Partition):入力リストをフラット化してに保存しfます。設定p = Partitionして返します。

g=p[r,5]:配列{{1,2,3,4,5}, ..., {21,22,23,24,25}}(これはrに設定されるためですRange@25)。

Join[g=p[r,5],g]:の行と列のリストg

p[#,2,1]&:リストを重複する#長さのサブリストに分割する純粋な関数。つまり、の隣接ペアのリスト。21#

##&@@p[#,2,1]&:を返すことを除いて、上記と同じSequenceです。

##&@@p[#,2,1]&/@Join[g=p[r,5],g]:の行と列の前の関数をマッピングしてg、の隣接するすべてのエントリのリストを取得しますg。私の直感はこれを行うためのより短い方法があると言います。

r~Graph~Cases[...]:頂点が整数で1, ..., 25あり、エッジが隣接するエントリ間のエッジgであり、入力配列に対応する同じエントリがある(ただし、" "

{a_,b_}/;(A=f[[a]])==f[[b]]&&A!=" ":(入力配列の同じ値){a,b}などに一致f[[a]] == f[[b]]し、に等しくないパターン" "。バイトA = f[[a]]を保存するように設定し1ます。

...:>a<->b:すべての一致をaからbの無向エッジで置き換えます。

VertexComponent:最初の引数(グラフ)の2番目の引数(頂点)の接続コンポーネントを返します。

Tr[1^VertexComponent[...]]:接続されているコンポーネントのサイズ。1からバイトを保存しますLength@VertexComponent[...]

If[Tr[...]<3,f[[#]],"x"]&:エントリー取るピュア機能#ではg。接続されているコンポーネントのサイズがより小さい場合3は、入力の対応するエントリに置き換えます。それ以外の場合は、"x"ます。

(f=Flatten@#;p=Partition)[...,5]:最後に、結果を5x5配列に再形成します。


0

Clojure、188バイト

これはかなり圧倒的です:D

#(apply str(map-indexed(fn[i v](if((set(flatten(for[m(range 30)](let[n(for[p[-1 -6 1 6]:when(=(get %(+ m p)0)((set"123456789")(% m)))](+ m p))](if(< 1(count n))(conj n m)[])))))i)\x v))%))

このように呼び出されます(文字の1Dベクトルが必要です):

(def f #(apply str(...))

(print (str "\n" (f (vec (str "12 45\n"
                              "11233\n"
                              "  233\n"
                              "    1\n"
                              "2 899\n")))))

(print (str "\n" (f (vec (str "2   3\n"
                              "    4\n"
                              " 1  5\n"
                              "111 6\n"
                              "11  7\n")))))

それをアンゴルフするのは面倒ですが、基本的にfor[m(range 30)]各インデックスを訪問し、各インデックスに対して内部let[n(for[p[-1 -6 1 6]...(+ m p))]は0から4の要素のリストを作成し、中央の場所と同じ値(1-9)を持つ場所をリストします。複数のネイバーが中間ピースと一致する場合、これらすべてがクラスターを形成しているため、これらの場所がで使用されるセットに追加され(if((set(flatten(...)))i)ます。iセットからインデックスが見つかった場合は出力され、\xそうでない場合は元の値が出力されます。それ:when( ... )はとても興味深いです...

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