ASCIIハマンタッシェンを数えてください!


18

今日のプリムでは、1つの習慣として、hamantaschen(単数形:hamantasch)と呼ばれるフィリング付きの三角形のクッキーを配ります。別の習慣は、大量に飲むことです。

私は最も完璧なパン屋ではありません。...配る不規則なサイズのハマンタッシェンはたくさんありますし、配る友達もたくさんいます!クッキーの写真を送った場合、どのサイズと詰め物をいくつ持っているか教えてもらえますか?しかし、それはPurimであり、私はあまりにも多くのコードを読むにはあまりにも酔っているので、できる限り小さいコードである必要があります。

定義

サイズ

ハマンタッシュのサイズは任意です。最小のハマンタッシュはサイズ1で、次のようになります。

/\  --
--  \/

時には、複数のハマンタッシェンが重なることがあります。以下の形状は、2つのハマンタッシェンとしてカウントされます(1サイズ1、1サイズ2):

 /\
/\ \
----

一部のハマンタッシェンには詰め物があります。これは、内部のすべての空白を文字で埋めることによって示されます。サイズ1のhamantaschenには詰め物がないことに注意してください。

私たちはします名前充填およびサイズに基づいてhamantaschenを。この形式<filling> <size>を使用して、埋められていない場合- <size>は、の代わりにスペースを使用できます-が、マークダウンはそれを好みません。

以下がa . 2、a . 4、およびa - 3です。

          /\
         /./\
 ----   /./  \
 \../  /./    \
  \/   --------

これらは、a @ 3、a、. 2およびa - 4です。

          /\
         / /\
  /\    / /@@\
 /..\  / /@@@@\
 ----  --------

これはもっと難しいことです。& 2オーバーラップからの傾斜のために、予想よりも充填量が少ない方法を参照してください- 3?それはあり- 1& 2A - 3& 4

--------
\   \/&/
 \  /\/
  \/&/
   \/

入力

テキストファイルまたは単一の文字列のhamantaschenが与えられます(オプションの末尾の改行とオプションで偶数になるように末尾の空白を埋め込みます)。

制限

  • 文字列が有効であると期待できます。つまり、空白文字以外のすべての文字が、おいしい甘いハマンタッシュに貢献します(なぜ生地を無駄にしますか?)。
  • また、それができることを期待することができ、適切に満たされたかどうか-つまり、それは完全に一致ASCII文字で埋められます各ハマンタッシェン-未充填のためのASCII 32、または何か32..127を満たした(除くために/\-)。
  • これらのハマンタッシェンは3空間に積み重ねられいません。すべて/\表示されます。すべて-によってブロックされない/\表示されます。充填は非常に最後です
  • すべてのハマンタッシェンには、水平線の少なくとも半分(切り上げ)が表示されます。
  • 連続した充填ブロックは、それを囲む最小のハマンタッシュのみ充填します。

出力

上記の条件を満たすすべてのhamantaschenの「名前」のリストを返します。出力は、任意の形式(文字列、ハッシュ、標準出力など)にすることができます。

テストケース

テストケース#1

入力#1:

          /\
         / /\
  /\    / /@@\
 /..\  / /@@@@\
 ----  --------
    /\
   /**\
  /*/\*\
 /*/..\*\
 --------

出力#1:

. 2
. 2
- 4
@ 3
* 4

テストケース#2

入力#2:

  /\----
 /\/\*\/
/ /\d\/
------

出力#2:

- 3
- 2
d 2
- 1    
* 2
- 1

テスト#3

入力#3:

----
\/\/
/\/\  /\
---- /::\
     ----

出力#3:

- 1
- 1
- 2
- 1
- 1
- 2
: 2

テスト#4

入力#4:

 /\/\
/ /\$\
-/--/\\
 --/--\
  /xxx/\
 /xxx/##\
 ---/----\
   /      \
   -------- 

出力#4:

$ 2
x 4
- 3
- 2
- 4
- 1
- 1
# 2

無効なテストケース#5

入力:

/\
\/

出力:

これを処理する必要はありません。


hamentaschenが重複しているが、同じ水平線がないテストケースはどうですか?他の人の水平線をさえブロックするかもしれません。
誇りに思ってhaskeller

@proudhaskeller OK、できました。ただし、これをテキストに入れただけです。これは2スペースです。私たちはします常にすべてを参照/して\ 、そして-トランプ充填常にます。
チャールズ

2
@EasterlyIrk他にも重要な部分があります-エステルの本を読んで(そして悪者にブーイングをして)貧しい人々に与えます-そして、衣装を着るなどの基本的でないこと。
チャールズ

1
再び関連しました!
downrep_nation

1
ゼロの初期列に基づいて、を除くすべての頂点列(1,0)はによってオフになり+1ます。それでも、私はあなたの意味を知っています、そして、私は同意しません。2つのアッパーの右上と左だけでなく(2, 2)、aの上部中央にどのような表示がありますか?私が見ることができるものはありません。そして、同じロジックがに適用されます。あなたは、可能な最大hamantaschenを前提とするルールを追加する場合を除き...- 2- 1(3, 2)
マイケルPlotke

回答:


4

C#、496 452バイト

編集:境界チェックでバグを発見した...しかし、自分のコードを理解することを余儀なくされたバイトの負荷も除去した。ローカル関数を展開すると少し助けになり、C#7固有のコードが削除されました。この質問はとても楽しかったです。

using C=System.Console;class P{static void Main(){string D="",L;int W=0,H=0,z=0,d,q,c,j,b;for(;(L=C.ReadLine())!=null;H+=W=L.Length)D+=L;var B=new int[H];for(d=W;(d=-d)>0||++z<H*H;)for(c=1,q=z%H;c<=z/H&q%W+c<W&q>=d&q<H+d&&D[q]==(d>0?92:47)&D[j=q+c]==(d<0?92:47);q-=d+1,c+=2){for(b=0;j>q;)b+=D[--j-d]==45?2:0;for(char h='-',e;c==z/H&b>c;C.WriteLine(h+" "+c/2))for(b=c++;b>1;j=q+=d+1,b-=2)for(;j<q+b;)B[j]=h=B[j]<1&h==45&(e=D[j++])!=47&e!=92&e>32?e:h;}}}

オンラインで試す

完全なプログラム。スペースで埋められた入力は標準入力に、出力は標準出力になります。出力は、行ごとに1つのエントリで、末尾に改行があります。Cookieはサイズの昇順で出力され、左上が最初になります。ルールを理解するにはかなり時間がかかりましたが、提供されたすべての例に合格すると思います。

有効なHamantaschenをグリッド全体で繰り返し検索し、「許可」サイズを増やして機能します。各セルの場合は、以下の、上下をチェック\し、/いずれかの側に限りそれができるよう。次の行に多くの-があり、現在のサイズが「許可された」サイズであることに気付いた場合、塗りつぶしを決定し、エントリを出力します。

詰め物は、「未使用」セルを探して、Cookieのスペース全体を探索することで検出されます。使用されていないセルが見つかると、使用済みとしてマークされ(許容サイズが大きくなるため、それを含む最小のCookieであることがわかります)、充填が記録されます。

書式設定されコメントされたコード:

using C=System.Console;

class P
{
    static void Main()
    {
        //   32
        // - 45
        // / 47
        // \ 92
        // range 32..127 (no mod for you)

        string D="", // the whole map
            L; // initally each line of the map, later each line of output

        int W=0, // width
            H=0, // length (width * height)
            z=0, // search tracker
            d, // check direction (this is backwards (1 byte saving!))
            q, // check tracker
            c, // counter (truely, this is the distance from the right to the left)
            //M, // c max (now inlined as z/H)
            j, // horiontal tracker
            b; // - count, and reverse counter

        // read map and width
        for(;(L=C.ReadLine())!=null; // read a line, while we can
                H+=W=L.Length) // record the width, and increment height
            D+=L; // add the line to the map

        var B=new int[H]; // whether this filling has been used already (0 -> false, >0 -> true)

        for(d=W; // init direction
            (d=-d)>0|| // swap direction, else increment z (this allows us to run the check for the same z twice with opposite direction)
            ++z<H*H; // for all M, for all q (z<H -> M=z/H=0 -> no valid cookies, so we can safetly skip them)
            )
            for(//M=z/H, // c allow (now inlined)
                c=1, // reset counter
                q=z%H; // note position
                c<=z/H& // counter check
                // no need for a left check: if we run off the left end, then the right check will necessarily fail
                q%W+c<W& // right check
                q>=d& // high check
                q<H+d&& // low check (short-circuit lookups)
                D[q]==(d>0?92:47)&D[j=q+c]==(d<0?92:47); // /\ or \/ check, and set j=q+c
                    q-=d+1, // move left tracker
                    c+=2) // increase counter (move right tracker)
            {
                // count the number of '-' into b
                for(b=0; // zero b
                    j>q; // for each element in the row below
                        ) // empty
                    b+=D[--j-d]==45?2:0; // add 2 to b if we tap a '-'

                // j = q

                // check valid before looking up cHaracter (so we don't mark unused stuff as taken)
                // if we are at the current max count, and we have enough -, then we are valid and should be commited
                for( // this runs either one or zero times, we only have a for here (rather than an if) so we can ditch a pair of braces
                    char h='-', // default filling
                         e; // filling we are considering
                    c==z/H&b>c;
                        C.WriteLine(h+" "+c/2)) // print filling and count
                    // continuously compute character
                    for(b=c++; // count b backwards, starting from c (add 1 to c so we can /2 in print)
                        b>1;j=q+=d+1,b-=2) // count q backwards toward z%H (where q came from), and b backwards toward 1 (for each row)
                        for(;j<q+b;) // for each cell in row
                            B[j]= // mark cell as taken (h,e > 0)
                            h= // record filling
                                B[j]<1& // check cell not already used
                                h==45& // '-'
                                (e=D[j++])!=47& // '/'
                                e!=92& // '\'
                                e>32 // ' '
                                ?e:h; // take first filling we can
                    // c runs out after this (exists both loops), so no need to action
            }
    }
}

4つのテストケースの出力:

testcase #1
. 2
. 2
@ 3
- 4
* 4

testcase #2
- 1
- 1
- 2
d 2
* 2
- 3

testcase #3
- 1
- 1
- 1
- 1
- 2
- 2
: 2

testcase #4
- 1
- 1
- 2
$ 2
# 2
- 3
x 4
- 4

私はこれがC#でどれほどコンパクトであるかに驚いています!よくやった!
チャールズ

唯一の有効な答え!ほぼ機能しているものの、いくつかのエラーがあります(ただし、勝者として自分自身を設定するつもりはありません)
チャールズ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.