数一下ASCII hamantaschen!


18

今天是普im节(Purim),一种习俗是散发出带有馅料的三角形饼干hamantaschen(单数:hamantasch)。另一种习惯是大量饮酒。

我不是最完美的面包师。。。我有很多不规则尺寸的hamantaschen可供分发,还有很多朋友可以给他们!如果我给您发送了一张我的饼干的照片,您能告诉我我有多少个大小和馅料吗?但是因为是普im节,而且我太醉了,无法阅读太多代码,所以它必须尽可能地小。

定义

尺寸

hamantasch可以是任何大小。最小的hamantasch是1号,看起来像这样:

/\  --
--  \/

有时,多个hamantaschen可能会重叠。以下形状算作两个hamantaschen(一个尺寸1,一个尺寸2):

 /\
/\ \
----

一些hamantaschen 充满了。这将通过用字符填充内部的所有空白来表示。请注意,尺寸1的hamantaschen不能填充。

我们将根据馅料和大小来命名 hamantaschen。让我们使用格式<filling> <size>,如果没有填充,- <size>可以使用空格代替-,但markdown并不是这样)。

这是一个. 2,一个. 4和一个- 3

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

这些是@ 3,a . 2和a - 4

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

这里有些困难。看看& 2由于重叠的倾斜而导致的填充量比您预期的要少- 3吗?它具有a - 1& 2a - 3和a & 4

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

输入值

您将获得一个文本文件或hamantaschen的单个字符串(可选的尾随换行符和可选的尾随空白填充为偶数)。

限度

  • 您可以期望该字符串是有效的 -也就是说,每个非空白字符都构成了美味的甜蜜hamantasch(为什么要浪费面团?)。
  • 您也可以期望它被正确填写或不-也就是每个hamantasch将完全充满一致的ASCII字符-用于填充ASCII 32,或填充(不包括任何32..127 /\-)。
  • 这些hamantaschen 不在 3空间中堆叠。全部/并且\将可见。所有-未受阻/\将可见的东西。填充到最后。
  • 所有hamantaschen将至少具有其水平线(向上舍入)的一半
  • 任何连续的填充只会填充围绕它的最小的hamantasch

输出量

返回符合以上条件的所有hamantaschen的“名称”列表。输出可以是您想要的任何形式(字符串,哈希,stdout等)。

测试用例

测试用例#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好,完成。但是,我只是将其放在文本中,这是2空格。我们将始终看到/\ -并将始终胜过填充。
并非查尔斯

2
@EasterlyIrk还有其他重要的地方-阅读《以斯帖记》(向坏人嘘声),向穷人致敬-以及诸如穿衣服之类的基本事情。
并非查尔斯

1
再次相关!
downrep_nation

1
基于初始列零,除以外的所有顶点列(1,0)都被禁用+1。不过,我知道您的意思,但我不同意。有什么指示是(2, 2)a的顶部中心,- 2而不仅仅是两个上- 1s 的顶部和左侧?我看不到。同样的逻辑也适用于(3, 2)。除非您想添加一条规则以假设最大可能的危险...
Michael Plotke

Answers:


4

C#,496452字节

编辑:发现了一个带有边界检查的错误...但是也剥离​​了被迫理解我自己代码的字节负载。展开本地功能有所帮助,并删除了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;}}}

在线尝试

完整的程序,期望将带空格的输入输入到标准输入,将输出输出到标准输出。输出是每行一个条目,并带有尾随换行符。Cookies以大小递增的顺序输出,最左上角。我花了一些时间来理解规则,但我认为它可以通过所有提供的示例。

它通过在整个网格中反复搜索有效的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#的紧凑程度感到惊讶!做得好!
并不是查尔斯(Charles)

唯一有效的答案!我有一些功能差不多,但有一些错误(但我还是不会将自己设置为赢家)
并不是查理
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.