爱丽丝的第一个代码审查


20

爱丽丝是一家公司的实习生,该公司使用Brainfuck作为客户端和服务器端开发的主要语言。爱丽丝(Alice)刚刚编写了她的第一个代码,在为第一次代码审查做准备时,她有点紧张。

爱丽丝(Alice)希望使代码正确格式化并看起来不错,但是她没有时间阅读328页的公司代码样式指南,因此她决定将其格式化为一个完美的正方形。code,代码长度可能不足以形成正方形,因此她决定在中间留一个矩形间隙。间隙必须完全居中,并尽可能接近正方形

例子

++++++         +++++         +++++         +++++         +++++         +++++
++++++         +++++         +++++         +  ++         ++ ++         +++++
++++++         ++ ++         +   +         +  ++         +   +
++++++         +++++         +++++         +++++         ++ ++         +++++
++++++         +++++         +++++         +++++         +++++         +++++

Perfect         OK         Acceptable   Unacceptable    No way!        Nope.

编写程序或函数来帮助Alice。给定Alice的代码作为输入字符串,请尽可能输出如下所述的格式正确的代码。如果无法格式化,请输出哭泣的表情符号:~(

这是因此答案以字节计分,目标是减少字节数。

约束条件

  1. 您的程序或函数应将单个字符串作为输入并输出一行或多行文本(如果实现函数,则返回多行字符串或字符串数​​组)。
  2. 输入字符串可以包含任何ASCII字符,包括空格。
  3. 输入中的所有空格都必须忽略。它们不应该计算代码长度,也不应该在输出中使用。
  4. 输入字符串包含至少一个非空白字符。
  5. 格式化的代码必须具有与输入代码相同的顺序的相同非空格字符。
  6. 格式化的代码必须是一个完美的正方形,即所有行应具有相同的长度,行数应等于行的长度。
  7. 格式化的代码可能在中间包含一个空格。
  8. 间隙中只能使用空格字符(ASCII代码32)。
  9. 间隙(如果有)必须为矩形。
  10. 格式化代码的每一行必须至少包含一个非空白字符,即,间隙宽度必须严格小于正方形宽度(对于5x5正方形,间隙5x1是不可接受的)。
  11. 间隙应为水平,即间隙宽度应大于或等于间隙高度。
  12. 间隙必须完美居中。
  13. 因此,间隙宽度和高度奇偶校验应该与正方形宽度奇偶校验相同(例如,对于5x5正方形间隙,可以为1x1、3x1或3x3)。
  14. 如果可能,输出没有任何间隙的平方。
  15. 在有多个解决方案的情况下,选择一个间隙最接近正方形的间隙,即间隙宽度和间隙高度之间的差异最小(例如:间隙10x10比8x6更可取,而8x6比6x2更可取)。
  16. 如果仍然有平局,请选择具有最小间隙面积的解决方案(例如,间隙2x2比4x4更可取)。
  17. 如果根本无法格式化代码,请输出:~(
  18. 最后一行之后的换行是可选的。
  19. [新增]您可以放心地假设任何代码低于33的字符都是空格。希望对您打高尔夫球有帮助。

测验

Input           Output      Code length     Comment

+++++++++       +++                   9     Alice is lucky, 
                +++                         her code perfectly fits a square. 
                +++


++++++++        +++                   8     Though code length isn't enough for a square, 
                + +                         a small gap fixes it.
                +++


++++++          :~(                   6     No luck, code cannot be formatted.


Hello,          Hell                 12     Input may contain any ASCII characters, 
World!          o  ,                        but whitespaces in input should be ignored.
                W  o
                rld!


+++++ + +++++   +++++                22     Gap is not required to be a square, 
+++++ + +++++   +++++                       it can be a rectangle.
                +   +
                +++++
                +++++

+++ + +++       ++++++++             28     There exists another solution: 
+++ + +++       +      +                    6x6 square with 4x2 gap, 
+++ + +++       +      +                    but in Alice's opinion square gap 
+++ + +++       +      +                    makes code more readable.
                +      +
                +      +
                +      +
                ++++++++

棘手的测试

This must be    Thism                24     7x7 with 5x5 gap looks good,
5x5 with 1x1    ustbe                       but 5x5 with 1x1 gap is better,
gap.            5x 5w                       because gap area is smaller.
                ith1x
                1gap.

+++ +++ +++     :~(                  18     In case you tried 5x5 square
+++ +++ +++                                 with 7x1 gap ;)

资源资源

为了节省空间,您可以在tio.run上找到示例代码和其他测试用例。

[新]您可以看一下接受的解决方案表,最多输入100个字符。我换了宽和高,因为它看起来更直观。

灵感来源:文字方块

变化

  • 添加了2个测试,修复了示例代码中的错误。

  • 添加了最多100个解决方案表,并添加了空格说明。


3
“如果无法格式化,则输出哭泣的表情符号”-不必要的绒毛,允许输出任何更好的IMO。
乔纳森·艾伦

1
@JonathanAllan,更好的是保证格式总是可能的。-输入验证!
毛茸茸的

1
@乔纳森·艾伦(Jonathan Allan),任何输出都太广泛,可能容易受到漏洞的影响。我考虑过使用任何虚假的值,但这会使不同语言之间的输出不一致。我还考虑过使用空字符串,但这会使运行测试用例的视觉效果降低。我还考虑了其​​他消息,例如“错误”,但决定缩短为支持全球Brainfuck开发人员的时间。
Daniil Tutubalin

1
@Shaggy,这不只是输入验证。发现没有解决方案是难题的重要组成部分:您需要找出何时停止搜索。
Daniil Tutubalin

2
@DaniilTutubalin非常常见的是确保此处仅给出某些输入。在此类“无效”输入上允许任何输出也是一种常见方法,并且避免了与挑战的核心无关的样板代码。如果您确实希望在这种情况下将某些内容作为输出不变,则建议您自己输入。我不建议您现在更改它,但这也是一个非常好的挑战!
乔纳森·艾伦

Answers:


5

C(gcc),354字节

h,i,j,k,l,m;g,v,w,d;f(char*s){for(i=l=0;s[i];l+=!isspace(s[i++]));d=g=l;for(i=0;i++<l;)if(h=i*i-l)for(j=0;j<i-++j;h>0&h%k<1&k<=m&m<i&m+~k&&m-k<g|m==k+g&(d-2*v)*(d-2*w)>h?w=(i-m)/2,v=j,g=m-k,d=i:j)k=i-2*j,m=h/k;else g=0,v=w=d=i;if(g-l)for(i=j=1;*s;j+=!i++,k=0,i%=d+1)for(putchar(i?v>=j|j>d-v|w>=i|i>d-w?k=1,*s:32:10);k;k*=isspace(*++s));else puts(":~(");}

在线尝试!


我认为制表符是“空白”,尽管我要求澄清确切的含义。
乔纳森·艾伦

我已经更新了帖子。您可以替换isspace(x)x<33
Daniil Tutubalin


4

JavaScript(ES6), 284 ... 274270 字节

@Shaggy节省了4个字节

返回字符串数组。

s=>(s=s.replace(/\s/g,''),n=s.length,o=[':~('],W=d=g=(x,w=0,h=p=0)=>4*~-x>n?o:h>w?++w>x-2?g(-~x):g(x,w):g(x,w,h+1,o=n-x*x+w*h|(w^x|h^x)&!!(w|h)|w-h>d|w-h==d&w>W?o:[...Array(x)].map((_,Y,a)=>a.map((_,X)=>2*X>=x-w&2*X<x+w&2*Y>=x-h&2*Y<x+h?' ':s[p++]).join``,d=w-h,W=w)))``

在线尝试!


做得好!尽管尝试该测试:This must be 5x5 with 1x1 gap.(24个字符)
Daniil Tutubalin

1
@DaniilTutubalin这就是为什么我删除了最初的帖子(并建议使用这种测试用例)的原因,但是现在可以正确地支持它了。
Arnauld

不能[\s\n]只是\s吗?
毛茸茸的

++w>x-2w++>=x-2w++>=x42\s

4

Stax,80 个字节

ö╦Çc▀╕╡ëé╓]µiÖ9♪`W|╣▐↑╖D┘↕♫╗╔äƒ■úφ■U`ÿ⌠%é┴☼vAú)☺@ı◄¬¶¢(îÉ┼6⌠D~♀└lfæA.I@º╤∟òîü╦(

运行并调试

它是如何工作的?

  • 考虑所有带有矩形切口的正方形。
  • 筛选出尺寸不正确的程序形状。
  • 筛选出没有匹配奇偶校验的程序形状。
  • 滤除切口太大的正方形程序形状。
  • 如果未找到,则输出失败并退出。
  • 找到最小化切口“矩形”的形状,然后通过切口尺寸。
  • 将程序形状中的每个字符替换为程序输入中的相应字符。

解压,解压并评论,它看起来像这样。

                input e.g. "big socks"
L$j$            remove whitespace from input e.g. "bigsocks"
cr{~F           copy push each remaining character to input stack in reverse order
%c              get length L of flattened input and copy e.g. 8
^r3:$           create triples [a,b,c] in range 0..n e.g. [[0,0,0], [0,0,1], ... [8,8,8]]
{E*NsJ+n=f      filter triples: require a*a-b*c=L e.g. [[3,1,1], [4,1,8], ...]
{ET>f           filter triples: a>b and a>c e.g. [[3,1,1]]
{{2%m:u_0#+f    filter triples: a%2=b%2=c%2 or b*c=0 e.g. [[3,1,1]]
":~("s|c        if there are no triples, output ":~(" and terminate
{D:s_D:*\oh     sort by [abs(b-c),b*c]; keep the first e.g. [3,1,1]
X               store the chosen triple in the X register
E               explode onto stack e.g. 3, 1, 1
z)]*            using last two values, make a rectangle of zeroes e.g. 3, [[0]]
~               this will be the cutout, push it to the input stack
c'X*]*          make a square of "X" e.g. ["XXX", "XXX", "XXX"]
xEd-h           given the dimensions in x register, calculate the centered cutout coordinates
xEsd-h          e.g. ["XXX", "XXX", "XXX"], 1, 1
,||             embed the cutout grid at the specified coordinates e.g. ["XXX", "X X", "XXX"]
m'X{,]}R        for each line, regex replace "X" with a character from the input stack

运行这个


您还可以提供解压缩版本吗?
Daniil Tutubalin

1
@DaniilTutubalin我添加了一个解释。
递归

谢谢!做得好!
Daniil Tutubalin

2

木炭,120字节

≔E⮌⪫⪪S ωιθ≔⁰ηF⊕Lθ¿⁼Lθ×ιι«≔ιη≔ιζ≔ιε»F⊘ιF⊕κF∧⁼Lθ⁻×ιι×⁻ι⊗⊕κ⁻ι⊗⊕λ∨¬η›⁻ζε⁻κλ«≔ιη≔⊕κζ≔⊕λε»¿η«UOη#JεζF›η⊗ζUO⁻η⊗ε⁻η⊗ζψUMKA⊟θ»:~(

在线尝试!链接是详细版本的代码。说明:

≔E⮌⪫⪪S ωιθ

从输入中去除空格,然后将其反转并将其拆分为字符,以便稍后可以更轻松地遍历字符。

≔⁰η

从零开始,表示尚未找到结果。

F⊕Lθ

检查所有边长,直至弦长。(当然,除法将使代码更快。)

¿⁼Lθ×ιι«≔ιη≔ιζ≔ιε»

如果结果是一个理想的正方形,则保存正方形大小,并将其设置为边框大小。

F⊘ιF⊕κ

在可能的边框高度和宽度上循环(边框宽度不大于边框高度,使间隙高度不大于间隙宽度。)

F∧⁼Lθ⁻×ιι×⁻ι⊗⊕κ⁻ι⊗⊕λ∨¬η›⁻ζε⁻κλ«≔ιη≔⊕κζ≔⊕λε»

如果边框的大小是所需的长度,并且我们还没有解决方案,或者它不像此解决方案那么方形,请使用此正方形和边框大小更新解决方案。

¿η«

如果我们有解决方案...

UOη#

绘制一个具有给定正方形大小的任意字符的矩形。

JεζF›η⊗ζUO⁻η⊗ε⁻η⊗ζψ

如果边框足够小,可以留出空隙,则可以清除该空隙。(drawing命令将向上和向左绘制负值,根本不喜欢零值。)

UMKA⊟θ

用输入中的字符替换所有(剩余)字符。

»:~(

否则输出:~(


2

果冻91 85字节

ÆDżU$<Ạa;ḂEɗʋƇṢƑƇ;€€
ḟ⁶ḟ⁷;©⁶L’²<¥Ðḟ²_ç;,`Wɗ¹?⁸ʋ€$Ẏạ/ÞḢµIH+""Rp"/ḟ@/ŒṬ€ĖP€Sị®Yµ“:~(”¹?

在线尝试!

以输入字符串为参数并返回带有格式输出或的字符串的单子链接:~(


1

Python 2中,287个 281 279字节

c=list("".join(input().split()))
l=len(c)
p=[]
for q in range(l*l):x=q%l;y=q/l;s=(l+x*y)**.5;p+=[(abs(x-y)/2,int(s),-x)]*(s%1==0)*(x<s-1>y>=s%2==x%2==y%2or x<1)
if p:d,s,x=min(p);b=(s+x)/2;Y=0;exec"c[b:b]=' '*-x*(b+d<=Y<s-b-d);print''.join(c[:s]);c=c[s:];Y+=1;"*s
else:print':~('

在线尝试!

通过使用相同的值来选择解决方案并进行打印,从而使用Python的词典列表比较。我很确定10 4 2左右的字节仍然可以减少。

说明

c=list("".join(input().split()))
l=len(c)
p=[]

通过用空格分割并与联接来删除空格"",然后将输入转换为列表以备后用。还要初始化l为实际代码的长度和p有效可能性的列表。

for q in range(l*l):x=q%l;y=q/l;s=(l+x*y)**.5;

通过从间隙大小的一切可能性环路0*0l*l。使用l代码字符和x*y空格计算正方形的边长s

p+=[(abs(x-y)/2,int(s),-x)]*(s%1==0)*(x<s-1>y>=s%2==x%2==y%2or x<1)

检查以下条件是否匹配:

  • s % 1 == 0,即会形成一个完美的正方形
  • x < s-1 > y,即xy最多s-2位于正方形内
  • s % 2 == x % 2 == y % 2,即两个xy匹配边缘的奇偶校验,并且可以居中
  • 但是如果x < 1,即x == 0忽略除平方理想以外的所有条件

如果条件匹配,请在元组中添加以下项p以找到最佳项:

  • abs(x-y)/2; 首先找到的最小差xy获得最大的平方间隙。这始终是偶数,因此我们除以2。
  • int(s); 接下来找到最小边长。由于s是整数并且随着间隙面积而增加x*y,因此按间隙面积排序。
  • -x; 接下来找到最大宽度以偏向于水平间隙。由于其开发方式,该区域位于该区域之后,但是该区域是相同的x*yy*x因此可以正常工作。
if p:d,s,x=min(p);b=(s+x)/2;Y=0

如果我们发现任何有效的布局,请如上所述找到最佳布局。计算水平边框b并将行号初始化Y为0。

exec"c[b:b]=' '*-x*(b+d<=Y<s-b-d);print''.join(c[:s]);c=c[s:];Y+=1;"*s

如果行号Y在间隙内(垂直边界是b+dd从元组开始),则在的水平边界后加上间隙宽度的空格c。(c为什么要修改它,所以我们需要将它作为一个列表。)然后打印正方形的一行并将其从中删除c。重复s次数,增加行号。

else:print':~('

如果找不到布局,则失败。


做得好!las,它不适用于多行输入。同样,它似乎不支持矩形间隙(请参见长度为22的测试)。
Daniil Tutubalin

1
@DaniilTutubalin您需要以Python字符串形式提供输入,多行实际上"some\ntext"是分隔符。(input()将一行输入评估为Python代码。)如果这是不可接受的,请告诉我。长度22也适合我。
PurkkaKoodari

哎ouch,对不起。可能我在输入时做错了。
Daniil Tutubalin

1

Pyth99 98字节

#JscQ)=QshKh|oaFtNSf!|%hT1&eT|t{%R2TgeStThT+L@+lJ*Fd2^UJ2
":~("Am/-Qd2tKW=W}~hZrG-QGJj*eKdcJ]H<~>J

在线尝试!

它使用与我的Python答案相同的算法,但是许多细节都被显着更改为在Pyth中更短。

Pyth在这里显示了它的使用期限,因为它没有根据使用期限进行更新,仅使用可打印的ASCII字符(用于代码,而不用于数据),浪费了大量空间。

有趣的是,如果Pyth使用的相同种类的基-256填料作为斯塔克斯的,这种方案可能是⌈98日志256 95⌉= 81字节长,毗邻斯塔克斯(80个字节)和果冻(85个字节)。我认为这很好地说明了高尔夫语言即使采用截然不同的范例也是如此接近。

说明(仅比代码少一些不可读)

#将所有内容都包装在while True:抑制消息并在出错时退出的。

JscQ) c将输入(Qs跳到空白处,将各个部分相加并将结果保存到中J

^UJ2使得指数的名单(U)的J,并采取了2第二笛卡尔功率(^),导致所有对[h,w]0<=h<len(J)0<=w<len(J)

+L@+lJ*Fd:对于所有(L)个这样的对d,添加(+)的平方根(@... 2)(的l的ength J加(+)的产物(*F该对)d)到该对的左侧,产生的三重态[side length, gap height, gap width]

f!|%hT1&eT|t{%R2TgeStThTf三胞胎的过滤器T在哪里

  • !|)都不:
    • 边长(hT)模1(%1)不为零
    • &)都:
      • 间隙高度(eT)非零
      • |)之一:
        • 三元组(R)模2(%...2),其中重复项({)和第一个唯一的(t)被删除,都是非空的
        • eS间隙高度和间隙宽度(tT)中的较大值()g比边长(hT)大或相等

S按字典顺序对三元组进行排序(按边长,然后按间隙高度)。oaFtN然后o通过a间隙高度和间隙宽度(tN)之间的绝对差值来搅动三联体。

在这一点上,如果我们没有有效的解决方案,请|评估其第二个参数\n":~(",它打印并返回:~(h采用最佳解决方案(":"如果没有),并将其保存在中K。然后h取其边长(":"如果没有的话)s将其强制转换为整数(如果失败则退出并退出),并将其保存(=)在Q

然后从边长()中减去(m[gap height, gap width]tK)中的每个-Q),结果除以2(/2)。结果A分配给GH

最后,我们进入一个W循环。Z从0开始,每次迭代我们都增加它,但使用旧值(~hZZ++在C中考虑)。

  • 如果(W)的旧值是({)的r安格G至(边长- G)(),-QG分配(=),以J以下情况:c一跳J在位置(]HjOIN半部与间隙宽度eK倍(*)的空间(d)。如果该值不在范围内,则返回J。如果此结果为空,则停止循环。
  • 从中删除(>)第一个Q字符,J并将~结果分配()到J。从的旧值开始J,取(<)首个Q字符并打印。

最后,#循环再次启动,错误和程序退出,因为cQ)Q含有一个数字是无效的。


老实说,我更喜欢可打印的代码。尽管二进制代码占用的空间更少,但看起来却少得多(我更喜欢将其视为十六进制转储),并且通常在使用相同语言的解决方案之间进行比较。因此,与另一个打包的Stax解决方案相比,打包的Stax解决方案更短,在将两者拆包后仍会更短。包装仅对整体Kolmogorov的复杂性有意义。
Daniil Tutubalin

@DaniilTutubalin不管通常如何进行比较,击败另一个golflang还是不错的;)
PurkkaKoodari

1

05AB1E95 89 字节

… 
    мDg©Ý3ãʒćnsP-®Q}ʒć‹P}ʒÈËyß_~}Dg_i…:~(ëΣ¦DÆÄsP‚}н©¤_iнë¬Uć᤮Ås<иs;R`X*+šXnª£®θð×ýX}ô»

肯定有几个字节可以打高尔夫球。

该程序的前三个步骤受@recursive的Stax答案的启发,因此请确保对他进行!

在线尝试验证所有测试用例

说明:

步骤1:移除所有空白:

 
                   # Push string " \n\t"
    м              # And remove those from the (implicit) input-string

步骤2:建立所有可能的三胞胎 [一种bC],在哪里 一种 是结果的维度 一种×一种 正方形和 b×C是差距的大小。为此,我们使用范围内的整数创建所有可能的三元组[0一种]。然后,我们过滤掉以下内容,其中以下所有条件对于三元组都是正确的:

  • 一种2-b×C=大号,在哪里 大号 是字符串的长度
  • 一种>b 和 一种>C
  • 一种2=b2=C2 要么 一世ñ一种b0

例如: 大号=28将导致三胞胎[[6,2,4],[6,4,2],[8,6,6]]

Dg                 # Get the length of this string (without popping by duplicating first)
  ©                # Store this length in variable `®` (without popping)
   Ý               # Create a list in the range [0,®]
    3ã             # Create all possible triplets by repeating the cartesian product 3 times
ʒ                  # Filter these triplets by:
 ć                 #  Extract head; pop and push remainder-list and head to the stack
  n                #  Square the head
   sP-             #  Take the product of the remainder, and subtract it from the squared head
      ®Q           #  And check if it's equal to the string length in variable `®`
                 # Filter the remaining triplets further by:
  ć‹P              #  Where the first integer is larger than the other two
      }          # And filter it a third time by:
  ÈË               #  Where all three are either odd or even
       ~           #  Or
    yß_            #  It does not contain any 0s

步骤3:检查是否还有剩余的三胞胎。如果没有,输出":~(";如果这样做,则通过排序并仅保留第一个来确定使用哪个。我们通过对元组进行排序一种bsb-Cb×C

例如:三胞胎[[6,2,4],[6,4,2],[8,6,6]]将被排序为[[8,6,6],[6,2,4],[6,4,2]],之后仅[8,6,6]保留。

Dg_i               # If this completely filtered list is now empty:
    …:~(           #  Push string ":~("
ë                  # Else:
 Σ                 #  Sort the triplets by:
  ¦                #   Remove the first character
   DÆÄ             #   Get the absolute difference between the remaining two integers
   sP             #   And pair it with the product of the remaining two integers
                 #  After we're done sorting: only leave the first triplet

步骤4:创建一个列表,说明如何分割字符串以插入空格。这样做是这样的:

给定 [一种bC],创建带有以下内容的列表:

  • 作为第一项: 一种-b2×一种+一种-C2
  • 作为中间 b-1个 项目: 一种-C
  • 最后一项: 一种2

例如:三元组[7,3,5]将产生list [15,2,2,35]

©                  #  Store this triplet in variable `®` (without popping)
 ¤_i               #  If the last value is 0 (which means the string is a square without gap):
    н              #   Simply keep the first value of the triplet
   ë               #  Else:
    ¬U             #   Store the first value in variable `X` (without popping)
      ć            #   Extract the first value; pop and push remainder-list and head to the stack
       α           #   Get the absolute difference of this head with the other two values
        ¤          #   Push the last value (without popping the pair itself)
         ®Ås     #   And repeat it the middle element or `®` minus 1 amount of times
       s           #   Swap to get the difference pair again
        ;          #   Halve both values
         R`        #   Push them reversed to the stack
           X*      #   Multiple the first value by `X`
             +     #   And then add it to the second value
              š    #   Prepend this in front of the repeated list
               Xnª #   And also append the square of `X`

第5步:最后,我们根据此列表拆分字符串,并将其与 C 数量的空间,将其拆分为大小的一部分 C,并通过换行符将它们合并在一起。例如:

"Alongtesttoseeifitworksasintended."根据列表拆分字符串[15,2,2,35]将导致:["Alongtesttoseei","fi","tw","orksasintended."]。然后加入C=5的空间数量"Alongtesttoseei fi tw orksasintended."。然后分成几部分一种=7为此:["Alongte","sttosee","i f","i t","w o","rksasin","tended."]。然后通过换行符将其加入到输出中。

    £              #   Then split the string into parts based on this list
     ®θð×          #   Push a string consisting of the last value of `®` amount of spaces
         ý         #   Join the list of substrings by this
          X        #   Push variable `X`
                 #  After the if-else: split the string into parts of that size
     »             #  And then join these by newlines
                   # (after which the top of the stack is output implicitly as result)
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.