MおよびS文字で構成されたASCIIアートウィンドウを検出する


28

ウィンドウは、奇数の辺の長さが少なくとも3のASCIIアートの正方形で、エッジの周りに1文字の境界線があり、中央に垂直および水平のストロークがあります。

#######
#  #  #
#  #  #
#######
#  #  #
#  #  #
#######

MSウィンドウは、境界線が文字Mとのみで構成されるウィンドウSです。あなたの仕事は、文字列を取り、入力が有効なMSウィンドウであれば真理値を出力し、そうでなければ偽値を出力するプログラム(または関数)を書くことです。

仕様書

  • 入力は、改行で区切られた文字列または各行を表す文字列の配列として取得できます。
  • MSウィンドウの境界線には、M文字とS文字が混在している場合がありますが、内部は常にスペースで構成されます。
  • 末尾の改行があるウィンドウのみを検出するか、末尾の改行がないウィンドウのみを検出するかを選択できますが、両方は検出できません。

テストケース

真実:

MMM
MMM
MMM

SMSMS
M M S
SMSMM
S S M
SMSMS

MMMMMMM
M  S  M
M  S  M
MSSSSSM
M  S  M
M  S  M
MMMMMMM

偽:

Hello, World!

MMMM
MSSM
MS M
MMMM

MMSMM
M S.M
sSSSS
M S M
MMSMM

MMMMMMM
M  M  M
MMMMMMM
M  M  M
MMMMMMM

MMMMMMM
M M M M
MMMMMMM
M M M M
MMMMMMM
M M M M
MMMMMMM

MMSSMSSMM
M   M   M
S   S   S
S   S  S
MMSSMSSMM
S   S   S
S   S   S
M   M   M
MMSSMSSMM

3
これは、特定の構造を検出するための決定問題であるASCIIアートの大きなひねりです。
-xnor

4
@xnorこのようなリバースASCIIアートには別のタグが必要になると思います。
エソランジングフルーツ

2
アスキーアートに固有ではありませんが、パターンマッチングは新しいタグの良い選択かもしれません
Destructible Lemon

文字列が長方形の配列を形成しないテストケースまたは2つを追加できますか?
グレッグマーティン

1
@マスト、あなたはまったく正しいです!たぶん、課題を明確にする必要があります
クリスM

回答:


1

Pyke、34 31バイト

lei}t\Mcn+it*i\M*+s.XM"QJ\S\M:q

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

lei                              -         i = len(input)//2
   }t                            -        (^ * 2) - 1
     \Mc                         -       "M".center(^)
        n+                       -      ^ + "\n"
          it*                    -     ^ * (i-1)
                 +               -    ^ + V
             i\M*                -     "M"*i
                  s              -   palindromise(^)
                   .XM"          -  surround(^, "M")
                               q - ^ == V
                       QJ        -   "\n".join(input)
                         \S\M:   -  ^.replace("S", "M")


7

グライム39 38バイト

1バイトを節約してくれたZgarbに感謝します。

e`BB/BB/W+ W/+
B=W|B/W\ * W/\ /*
W=[MS

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

再帰的な非ターミナルを使用するよりも、個々のウィンドウコンポーネントのアスペクト比を強制する簡単な方法があるかどうかはわかりませんが、これは非常にうまく機能しているようです。

説明

プログラムは下から順に読むのが最善です。

W=[MS

これは単にWMまたはS]行の末尾に暗黙的なものがあります)のいずれかに一致する非終端記号(長方形に一致するサブルーチンと考えることができます)を定義します。

B=W|B/W\ * W/\ /*

これはB、出力の約4分の1に一致する非ターミナル、つまり、左と上の境界線を持つ1つのウィンドウパネルを定義します。このようなもの:

MSM
S  
M  

このウィンドウパネルが正方形になるように、B再帰的に定義します。これは、どちらかのウィンドウの文字だW、またはそれはだB/W\ * W/\ /*から右へと下に一つの層を追加しています。これがどのように行われるかを見るために、いくつかの構文糖を削除しましょう。

(B/W[ ]*)(W/[ ]/*)

これは同じです。水平連結はまたはのいずれABA Bで記述できますが、後者は垂直連結よりも優先順位が低く、前者は優先順位/が高いためです。だから、B/W[ ]*あるBウィンドウの文字と下のスペースの行で。そしてW/[ ]/*、スペースの列を持つウィンドウ文字である水平方向に追加します。

最後に、これらの非ターミナルを最終的なウィンドウ形状に組み立てます。

BB/BB/W+ W/+

それBは、ウィンドウ文字の行とウィンドウ文字の列が続く4つのウィンドウパネルです。4つのウィンドウパネルが同じサイズであるという明示的な主張はしていませんが、そうでない場合、それらを長方形に連結することは不可能です。

最後e`に、最初は単純に、入力全体がこのパターンに一致することを確認するようにグライムに指示する構成です(印刷する0か、1それに応じて)。


5

JavaScript(ES6)、115 113バイト

a=>(l=a.length)&a.every((b,i)=>b.length==l&b.every((c,j)=>(i&&l+~i-i&&l+~i&&j&&l+~j-j&&l+~j?/ /:/[MS]/).test(c)))

入力を文字の配列の配列として受け取り(文字列の配列に5バイトを追加)、1またはを返します0。高さが奇数であることを確認した後、すべての行をチェックして配列が正方形であることを確認し、すべての文字が特定の位置にあると予想される文字の1つであることを確認します。編集:@PatrickRobertsのおかげで2バイトを保存しました。


1バイトを保存する(...).includes(c)よう~(...).search(c)に変更できます
パトリックロバーツ

1
実際には、(...?/ /:/[MS]/).test(c)1だけではなく2バイトを節約するように変更できます
パトリックロバーツ

@PatrickRobertsかわいい、ありがとう!
ニール

5

Perl、 124 123 119 95 93 84

次のPerlスクリプトは、標準入力から1つの候補MSウィンドウを読み取ります。次に、候補がMSウィンドウの場合はゼロの終了ステータスで終了し、そうでない場合はゼロ以外の終了ステータスで終了します。

2つの正規表現を生成します。1つは上、中、下の行に、もう1つは他のすべての行に、入力をチェックします。

ありがとう、@ Dada。そしてまた。

map{$s=$"x(($.-3)/2);$m="[MS]";($c++%($#a/2)?/^$m$s$m$s$m$/:/^${m}{$.}$/)||die}@a=<>

終了ステータスが許可されているため、結果を提供するかどうかはわかりません(関連するメタ投稿を探す時間はありません)。とにかく、数バイト節約できます@a=<>;$s=$"x(($.-3)/2);$m="[MS]";map{$a[$_]!~($_%($./2)?"$m$s$m$s$m":"$m${m}{$.}")&&die}0..--$.
ダダ

@ダダ:ありがとう!これは印象的な改善です。24文字です。(コードに漂遊する「$ m」があったので、最初に見たよりもさらに短いです。)終了コードで結果を報告することが一般的に許可されているかどうかはわかりませんでしたが、または機能)」として、この特定のケースで結果が返される方法に柔軟に対応できるようにします。終了コードは、実際には* nix環境の関数の戻り値です。:
nwk

26文字にします。
-nwk

1
実際、$.2回使用することを避けるために最後にデクリメントしています$.-1(特に最初から($.-1)/2追加の括弧が必要だったので)ので、$min $m${m}{$.}は間違いではありません。また、私はちょうど今実現しますが、regexsがで囲む必要があります^...$(最後にその余分な文字またはそれらが失敗始まるメイク)、または短い:使用neの代わりに!~
ダダ

決して気にせず、明らかにあなたはne代わりに使用することはできません!~(たった15分間起きているときにメッセージを書くべきではありません!)。だからあなたは^...$私が恐れている正規表現の両方で使用する必要があります。
ダダ

2

Mathematica、166バイト

Union[(l=Length)/@data]=={d=l@#}&&{"M","S"}~(s=SubsetQ)~(u=Union@*Flatten)@{#&@@(p={#,(t=#~TakeDrop~{1,-1,d/2-.5}&)/@#2}&@@t@#),p[[2,All,1]]}&&{" "}~s~u@p[[2,All,2]]&

入力として文字のリストのリストを取り、Trueまたはを返す名前のない関数False。以下はゴルフの少ないバージョンです。

(t = TakeDrop[#1, {1, -1, d/2 - 0.5}] &; 
Union[Length /@ data] == {d = Length[#1]}
  &&
(p = ({#1, t /@ #2} &) @@ t[#1];
SubsetQ[{"M", "S"}, Union[Flatten[{p[[1]], p[[2, All, 1]]}]]]
  && 
SubsetQ[{" "}, Union[Flatten[p[[2, All, 2]]]]])) &

最初の行は、tdさのリストを2つの部分に分ける関数を定義します。最初の部分はリストの最初、中間、および最後のエントリで、2番目は残りすべてです。2行目は、入力が最初に正方配列かどうかをチェックします。四行目が使用tすることになっている文字を分離するために、二度、入力自体に、一度の入力で文字列のすべての*に一度、"M"または"S"空白ことになっている文字からを。次に、5行目と7行目で、それらが本来あるべきものであるかどうかを確認します。


2

JavaScript(ES6)、108 106バイト

入力:文字列の配列/出力:0または1

s=>s.reduce((p,r,y)=>p&&r.length==w&(y==w>>1|++y%w<2?/^[MS]+$/:/^[MS]( *)[MS]\1[MS]$/).test(r),w=s.length)

テストケース


2

JavaScriptの(ES6)、140の 138 141 140バイト

私はこれが勝利バイト数ではないことを知っています(-3のパトリック・ロバーツのおかげで、M / Sの代わりに1の偽陽性を投げたことに気付きました:+ 3)が、私はそれを少し違った方法でやりました、私はこれは初めてで、楽しかった...

各行に1つずつ、文字列の配列を受け入れ、trueまたはfalseを返します。わかりやすくするために改行が追加されました(バイトカウントには含まれません)。

f=t=>t.every((e,i)=>e.split`S`.join`M`==[...p=[b='M'.repeat(s=t.length),
...Array(z=-1+s/2|0).fill([...'MMM'].join(' '.repeat(z)))],...p,b][i])

一般化されたパターンに対して入力をチェックする代わりに、同じサイズの「M」ウィンドウを作成し、入力でSをMに置き換えて、2つを比較します。

非ゴルフ

f = t => t.every( // function returns true iff every entry in t
                  // returns true below
  (e, i) => e.split`S`.join`M` // replace all S with M
                                 // to compare to mask
  == [ // construct a window of the same size made of Ms and
       // spaces, compare each row 
      ...p = [ // p = repeated vertical panel (bar above pane)
               // which will be repeated
              b = 'M'.repeat(s = t.length),
                  // b = bar of Ms as long as the input array
              ...Array(z = -1 + s/2|0).fill([...'MMM'].join(' '.repeat(z)))],
              // z = pane size; create enough pane rows with
              // Ms and enough spaces
      ...p, // repeat the panel once more
      b][i] // finish with a bar
)

console.log(f(["111","111","111"]))

console.log(f(["MMMMM","M S M","MSSSM","M S M","MSSSM"]))

テストケース

f=t=>t.every((e,i)=>e.split`S`.join`M`==[...p=[b='M'.repeat(s=t.length),
...Array(z=-1+s/2|0).fill([...'MMM'].join(' '.repeat(z)))],...p,b][i])


truthy=`MMM
MMM
MMM

SMSMS
M M M
SMSMS
M M M
SMSMS

MMMMMMM
M  S  M
M  S  M
MSSSSSM
M  S  M
M  S  M
MMMMMMM`.split('\n\n')

falsey=`Hello, World!

MMMM
MSSM
MS M
MMMM

MMSMM
M S.M
sSSSS
M S M
MMSMM

MMMMMMM
M  M  M
MMMMMMM
M  M  M
MMMMMMM

MMMMMMM
M M M M
MMMMMMM
M M M M
MMMMMMM
M M M M
MMMMMMM`.split('\n\n')

truthy.forEach(test=>{
  console.log(test,f(test.split('\n')))
})

falsey.forEach(test=>{
  console.log(test,f(test.split('\n')))
})


1
将来の参照のために、関数が再帰的でない限り、f=バイトカウントに含める必要はないため、これは実際には138バイトの送信です。
パトリックロバーツ

に置き換えz=-1+s/2|0z=(s-3)/21バイトを節約できます
パトリックロバーツ

に置き換えe.replace(/S/g,'M')==...e.split`S`.join`M`==...別のバイトを保存することもできます
パトリックロバーツ

ありがとう!z=-1+s/2|0s == 1および偶数sに対して正の整数を返すためにあります。つまり、関数はArray()がクラッシュすることなくfalseを返します。それ以外の場合、必要なロジックにより長くなりました。分割/結合のすばらしいヒント、ありがとう
クリスM

s=1私の無効な正規表現は単に黙って失敗するので、私はケースを考慮しませんでした。
パトリックロバーツ

1

JavaScript(ES6)、109 107 106 105 99バイト

s=>!s.split`S`.join`M`.search(`^((M{${r=s.search`
`}})(
(M( {${w=(r-3)/2}})M\\5M
){${w}}))\\1\\2$`)

編集:おっ、アーナウルドはに変更s.split`\n`.lengthすることで私に6バイトを節約しましたs.search`\n`!ありがとう!

これは、単一の複数行文字列を受け取りRegExp、入力文字列の長さを使用して-ベースの検証を構築します。trueまたはを返しますfalse。有効なウィンドウが前提としている 必要はありません末尾の改行を。

デモ

f=s=>!s.split`S`.join`M`.search(`^((M{${r=s.search`
`}})(
(M( {${w=(r-3)/2}})M\\5M
){${w}}))\\1\\2$`);
`MMM
MMM
MMM

SMSMS
M M M
SMSMS
M M M
SMSMS

MMMMMMM
M  S  M
M  S  M
MSSSSSM
M  S  M
M  S  M
MMMMMMM

Hello, World!

MMMM
MSSM
MS M
MMMM

MMSMM
M S.M
sSSSS
M S M
MMSMM

MMMMMMM
M  M  M
MMMMMMM
M  M  M
MMMMMMM

MMMMMMM
M M M M
MMMMMMM
M M M M
MMMMMMM
M M M M
MMMMMMM`.split`

`.forEach(test=>{console.log(test,f(test));});


素敵なアプローチ!r=s.search('\n')代わりに使用できますsplit / lengthか?
アーナルド

@Arnauld素晴らしい提案、ありがとう!
パトリックロバーツ

s=>!s.split`S`.join`M`.search([...])構文エラーを引き起こすことなく、括弧を削除できます。
イスマエルミゲル

@IsmaelMiguelは正しいが、その後、文字列はテンプレートとして渡され、暗黙の無効になりますRegExp
パトリックロバーツ

吸う...私は本当にそれを期待して波平...
イスマエルミゲル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.