【问题标题】:Code Golf: The wave代码高尔夫:浪潮
【发布时间】:2009-09-03 21:29:55
【问题描述】:

挑战

从输入字符串生成波形的按字符计数的最短代码。

通过提升 (line-1) 较高的字符和降低 (line+1) 较低的字符来生成波浪。相同的字符保持在同一行(不进行提升或降级)。

输入仅由小写字符和数字组成,字母被认为高于数字。

测试用例:

Input:
    1234567890qwertyuiopasdfghjklzxcvbnm

Output:
                                 z
                                l x v n
                               k   c b m
                              j
                             h
                            g
                   y   p s f
                  t u o a d
               w r   i
            9 q e
           8 0
          7
         6
        5
       4
      3
     2
    1

Input:
    31415926535897932384626433832795028841971693993751058209749445923078164062862

Output:
                9 9   8 6 6
         9 6   8 7 3 3 4 2 4  8   9   88
    3 4 5 2 5 5     2       33 3 7 5 2  4 9   9 99 7
     1 1     3                  2   0    1 7 6 3  3 5   8              8 6
                                            1        1 5 2 9      9 3 7 1 4 6 8
                                                      0   0 7 9  5 2 0     0 2 6
                                                             4 44               2

代码计数包括输入/​​输出(即完整程序)。

【问题讨论】:

  • 只是好奇罗塞塔石与这有什么关系?
  • 来自另一个问题的评论:“如果你想要尽可能多的答案,尽可能多的语言,你可以添加标签 [rosetta-stone]”
  • @jdelator,这意味着欢迎提交并寻求尽可能多的语言。指的是原始的“罗塞塔石碑”,而不是 Apple 对同名代码的实现。
  • 这取自这里:golf.shinh.org/p.rb?wave+line 检查该网站,寻找解决这些相对业余的黑客工作的解决方案。
  • 当然,其中一些 shinh.org 浪潮很小。有两个 Ruby Wave 都获得了令人印象深刻的低于 80 字节的分数。然而,每一个至少有两个问题,一个甚至产生错误的输出。我的可能是 122 字节,但我认为这肯定不是业余黑客工作。你知道,因为它,嗯,有效?

标签: language-agnostic code-golf rosetta-stone


【解决方案1】:

x86 机器码(37 字节)

十六进制转储:

6800B807BF8007BE8200B40EAC3C0D741338D8740A720481EF400181C7A000AB86C3EBE8C3

在带有 50 行控制台的 MS-DOS 中运行,输入来自命令行。

例如

wave.com 1234567890qwertyuiopasdfghjklzxcvbnm

Download binary here

更新:感谢jrandomhacker,减少了三个字节

【讨论】:

  • @Jonas Gulle:有些人不喜欢别人碰他们的条目。
  • @LiraNuna:没错,但那些人可能不属于这里。 ;)
  • 测量二进制长度不是作弊吗?如果你要测量汇编源的长度,那会长很多。
  • @P Daddy:我认为这很公平;我认识的人已经记住了足够的 8086 指令,能够直接以十六进制读取和写入程序集。 OTOH,这只能通过 DOS+COM 实现;我敢打赌,在 Linux/i386+ELF 中同样的东西肯定至少是 300kB。也许我会试一试...
  • "而一个字节的编译/汇编二进制文件与一个字符源不同。"两件事:(1)为什么,因为你这么说? (2)谁说的有关来源?不是OP。 (但顺便说一句,CPU 是解释器,机器码是它的源代码。)
【解决方案2】:

J

54 个字符,如果您让解释器处理输入/输出。

e=:|:@((#&' '@],[)"0[:(-<./)0,[:+/\[:(}:(>-<)}.)a.i.])

65 显式读取标准输入并写入标准输出。

(|:((#&' '@],[)"0[:(-<./)0,[:+/\[:(}:(>-<)}.)a.&i.)~1!:1[3)1!:2[4
e '1234567890qwertyuiopasdfghjklzxcvbnm' z l x v n k c b m j H G 是的 t u o d 我 9 q e 8 0 7 6 5 4 3 2 1 e '31415926535897932384626433832795028841971693993751058209749445923078164062862' 9 9 8 6 6 9 6 8 7 3 3 4 2 4 8 9 88 3 4 5 2 5 5 2 33 3 7 5 2 4 9 9 99 7 1 1 3 2 0 1 7 6 3 3 5 8 8 6 1 1 5 2 9 9 3 7 1 4 6 8 0 0 7 9 5 2 0 0 2 6 4 44 2
注意。 查找 ASCII 码 ord =: 一个。一世。 ] ord 'p4ssw0rd' 112 52 115 115 119 48 114 100 注意。 上涨? 向上 =: }: 0 1 0 1 0 1 0 注意。 要下去吗? 向下 =: }: > }。 down ord 'p4ssw0rd' 1 0 0 0 1 0 1 注意。 组合得到±1 updown =: }: (> - 1 _1 0 _1 1 _1 1 注意。 从 0 开始,然后是部分和 总和 =: 0 , +/\ sum updown ord 'p4ssw0rd' 0 1 0 0 _1 0 _1 0 注意。 减去最小值得到碱基为 0 的序列 修复 =: - <. sum updown ord> 1 2 1 1 0 1 0 1 注意。 为方便起见,命名这个函数链 d =: [: fix [: sum [: updown ord 注意。 在字符前留空格 push =: (#&' ' @ ] , [)"0 d 推“p4ssw0rd” p 4 s s w 0 r d 注意。 把它翻过来 |: push 'p4ssw0rd' 写 p ss 0 天 4 注意。 合并成一个命名函数…… e =: |: @推送 注意。 ...并内联所有内容 e =: |:@((#&' '@],[)"0[:(-<.>-

【讨论】:

  • 我真的很想解释那个程序...我根本不认识 J。我什至无法猜测它在做什么。
  • 这甚至不像 yosemite sam 对 bugs bunny 大喊大叫的语言。
  • 看起来你只是在制作一堆笑脸。让我试试 J::(:[[[:(:o:pO_O&i-:)$$。我做了一个程序吗?
  • @rmeador:J 有点深奥,所以我通常会在有时间的时候添加解释。它现在在那里。 @Alex:不,(: 不是合法词。
  • 我认为这就是所谓的 orgicon(表情狂欢)。
【解决方案3】:

按字符数计算的最短代码,用于从输入字符串中打印“wave”。

Console.WriteLine("来自输入字符串的'wave'。");

【讨论】:

  • @strager:不开玩笑,它比我的回答要长(如果你只计算代码而不是样板)。
  • 这个问题本身就是一个笑话,没有完全偏离主题的回应。
  • +1:迄今为止最短的答案。 -1:puts "a 'wave' from the input string."
  • 习惯上把语言和字符计数。如果这是 C#,那么 (a) 这将无法编译(因为它不在类中),并且 (b) 仅比实际解决问题的 J 解决方案短一个字符。 :-)
  • Console.Write("a 'wave' from the input string."); ;)
【解决方案4】:

Perl(94 个字符)

144 个字符由 barnaba 原创:

chop($_=&lt;&gt;);$l=length;push(@a," "x$l)for(1..$l*2);$l+=(ord $p&lt;=&gt;ord $_),substr($a[$l],$r++,1)=$p=$_ for(split //);/^\s+$/||print "$_\n" for(@a)

Chris Lutz 优化的 121 个字符:

$_=&lt;&gt;;chop;$a[@a]=" "x$l for 1..($l=length)*2;$l+=$p cmp$_,substr($a[$l],$r++,1)=$p=$_ for split//;/\S/&amp;&amp;print"$_\n"for@a

进一步优化的 94 个字符:

$_=&lt;&gt;;@a=($"x($l=y///c).$/)x(2*$l);s/./substr$a[$l+=$"cmp$&amp;],"@-",1,$"=$&amp;/ge;/\S/&amp;&amp;print for@a

请注意,在传统的 Perl 高尔夫中,通常会增加开关的数量和代码的长度(这在此处会有所帮助),但这里我们使用的是没有开关的独立程序。

【讨论】:

  • 其中一些括号和空格可以很容易地删除。
  • 感谢您的编辑。干得好,我学到了一些关于 perl 的东西 :-)
  • 没问题。你没有太多要学的东西——甚至在我们优化你的方法之前,你的方法就比我的要短。我希望我们可以使用另一种方法来缩短它,因为如果 Ruby 解决方案变得更小,我们将无法赶上。
  • 太棒了,A. Rex!我不知道为什么我忘记了$" 和朋友们。
  • 我使用高尔夫技巧对其进行了更多优化:y///c 而不是 length$" 而不是 " ",列出上下文 x 而不是第一个 for 循环,四参数版本substr, $" 再次避免空格,s/.//ge 替换split// 并避免chop
【解决方案5】:

VT100 终端上的 C(76 个字符)

这适用于我在 FreeSBIE 上的测试:

o;main(c){for(;(c=getchar())-10;o=c)printf("\33[1%c%c",c<o?66:c>o?65:71,c);}

但是为了清楚地看到输出,你必须用这样的方式运行它:

clear ; printf "\n\n\n\n\n" ; echo the quick brown fox jumps over the lazy dog | ./a.out ; printf "\n\n\n\n\n"

这算不算?

【讨论】:

  • 大多数 Unices 都有一个printf 命令,所以你可以直接使用printf "\n\n\n\n\n"
  • 用另一种语言可能会更短,我不肯定。
【解决方案6】:

Python(161 个字符)

v,s="",raw_input()
m=n=len(s)
r=[' ']*n
q=[r[:]for i in range(2*n)]
for j,i in enumerate(s):
 m+=(i<v)-(i>v)
 q[m][j],v=i,i
for i in q:
 if i!=r:print''.join(i)

我还没有做太多压缩它。现在通过宇宙飞船操作员将其移植到某物上。

【讨论】:

  • 不认为空间很重要。没有空格的 166 个字符。
  • 这是因为否则你不会将苹果与苹果进行比较。
【解决方案7】:

Ruby:99 字节

r,a,q,i=[],"",99,0
gets.chars{|x|t=r[q+=a<=>x]||=""
a=x
r[q]+=" "*(i-t.size)+x
i+=1}
puts r.compact

未压缩:

r,a,q,i = [],"",99,0
gets.chars { |x|
  t = r[q+=a<=>x] ||= ""
  a = x
  r[q] += " "*(i-t.size)+x
  i += 1
}
puts r.compact

【讨论】:

  • 用 >>r[q]||="">r[q]=""if r[q].nil? 保存 10 个字节
  • 是的,我想出了一些东西,包括第一个并将其降至 109,出于某种原因,我将其作为第二个答案发布在下面。我不认为我理解社区 wiki 的含义或什么。您对“”当然是正确的,它确实不需要两次第一个字符串字符,这意味着我们也可以杀死 s 。干得好。
  • 还通过在下标中碰撞 q 节省了 2 个字节,所以现在
【解决方案8】:

PHP(138 个字符)

<?for($lc=$i=$h=0;"\n"!=$c=fgetc(STDIN);$o[$h]=sprintf("%- {$i}s%s",@$o[$h],$lc=$c),$i++)$h+=$c<$lc?-1:$c>$lc;krsort($o);echo join($c,$o);

'可读'版本:

<?
for (
    $last_ch = $i = $level = 0;
    "\n" != $ch = fgetc(STDIN);
    $out[$level] = sprintf("%- {$i}s%s", @$out[$level], $last_ch = $ch), $i++
    )
    $level += $ch < $last_ch ? -1 : $ch > $last_ch;
krsort($out);
echo join($ch,$out);

【讨论】:

  • (我删除了我之前的评论)——我不知道结束?> 是可选的!每天学习新东西... :-)
  • 不仅结束符 ?> 是可选的,最后一个分号也是可选的。
  • 我认为你只能省略 = ... ?> 短标签中的分号;但如果你这样做,你就不能省略结束 ?> 反正。但是,我可以通过使用 $l 而不是 $lc.. 使解决方案变成 134 个字符,从而再减少 4 个字符。
【解决方案9】:

Python 2.x,现在减少到 156 个字符:

s=raw_input()
R=range(len(s))
m=[0]
for i in R[1:]:m+=[m[-1]-cmp(s[i],s[i-1])]
for x in range(min(m),max(m)+1):print''.join(m[i]==x and s[i]or' 'for i in R)

【讨论】:

    【解决方案10】:

    Haskell,215 个字符。我发布这个是因为我根本不喜欢 Khoth 的版本。仅仅通过以合理的功能风格编写,我最终得到了一个更短且 IMO 更具可读性的程序。除了变量名和间距之外,我实际上并没有试图让它变短。破坏性地更新数组可能会比复制空间更短。

    import Char    
    import List    
    main=getLine>>=(putStr.p)    
    p s=unlines$transpose[z++(y:x)|(m,y)<-zip n s,let(x,z)=splitAt m$replicate(maximum n)' ']
        where o=map ord s
        n=scanl(+)0$map signum$zipWith(-)(tail o)o
    

    【讨论】:

    • 不适用于321(putStr.p)(y:x) 不需要括号。
    【解决方案11】:

    C89(151 个字符)

    l[999][999];p;v=500;r;main(c){for(;(c=getchar())>0;
    )l[v+=c>p,v-=c<p][++r]=*l[v]=p=c;for(v=999;v--;)for
    (c=0;c++<=r;)*l[v]&&putchar(c<=r?32|l[v][c]:10);}
    

    【讨论】:

    • 用c89编译,写了点东西,按回车,就想往下写一行,还在程序里。我错过了什么吗? (必须在最后删除 //)
    • @Liran:您可能需要按 Ctrl-D(在类 UNIX 平台上)或 Ctrl-Z(在类 Windows 平台上)触发 EOF,以便 getchar() 返回 NUL。
    • 当然,鉴于要给出的字符范围有限,(c=getchar())&amp;' ' 也是防止换行符进入混合的一种简单方法。
    • 基本上我假设输入来自文件,而不是终端。是的,您需要输入 EOF 才能工作。此外,您输入的任何换行符都将成为 wave 的一部分。
    • 您可以将putchars 与putchar(c&lt;r?32|l[v][c]:10) 合二为一(将++ 移动到for 循环中,如下所示:for(c=0;c++&lt;r;)。然后您可以去掉花括号对于if 块。实际上,您可以完全摆脱if,使用*l[v]?putchar(c&lt;r?32|l[v][c]:10):0;v 循环不需要与0 的comarison。它可以只是for(v=999;v--;)。而且我发现v=+c&gt;p,v-=c&lt;pv+=(c&gt;p)-(c&lt;p) 短一个字符。所有这些更改可以使您的代码减少到150 个字符。我验证它仍然有效。
    【解决方案12】:

    C#:

    using System;
    static class A
    { 
        static void Main(string[] a)
        {
            var s=a[0];var r="";
            int i=1,h=0,d=0,c=0,n=s.Length;
            var m=new int[n];
            m[0]=0;
            for(;i<n;i++)
            {
                c+=Math.Sign(s[i]-s[i-1]);
                h=(c>h)?c:h;
                d=(c<d)?c:d;
                m[i]=c;
            }
            for(;h>=d;h--)
            {    
                for (c=0;c<n;c++)
                    r+=(m[c]==h)?s[c]:' ';  
                 r+="\n";
            }
           Console.Write(r);
        }
    }
    

    压缩后的重量为 287。

    【讨论】:

    • 需要 I/O 以符合规范。
    • 是的,我刚刚看到了。多么奇怪的要求:通常您只希望该函数删除有损流程的愚蠢样板代码。无论如何,在接下来的几次编辑中将其扼杀。
    • 我的意思是:如果我想使用 javascript 怎么办?你会怎么做那里的“IO”?你想让我用文本输入构建一个完整的 html 文档吗?
    • 乔尔,您可以在 Javascript 中使用 prompt()。此外,在某些语言中,I/O 代码可能会根据要求而变化,并且在所有语言中都有它们比在某些语言中出现或在其他语言中不出现更公平。
    • 不,最公平的方式就是请求一个函数。
    【解决方案13】:

    Perl,85 个字符带开关,96 个不带

    使用 -F// -an 开关调用

    $q=$"x($n=@F);$,=$/;for(@F){/
    /&&print@O;substr($O[$n+=$*cmp$_]|=$q,$i++,1)=$_;$*=$_}
    

    第二个和第三个斜线字符之间有一个换行符。没有开关你可以做

    $q=$"x($n=@C=split//,<>);$,=$/;for(@C){/
    /&&print@O;substr($O[$n+=$*cmp$_]|=$q,$i++,1)=$_;$*=$_}
    

    【讨论】:

      【解决方案14】:

      Haskell(285 个字符):

      heightDiff x y | x == y = 0
                 | x < y = -1
                 | True = 1
      
      heights h (x:y:z)= (x,h):(heights (h+(heightDiff x y) ) (y:z))
      heights h [y] = [(y,h)]
      
      makech ((x,h):xs) i = (if i==h then x else ' '):makech xs i
      makech [] _ = []
      
      printAll xs = mapM_ (putStrLn . (makech xs)) [(minimum $ map snd xs)..(maximum $ map snd xs)]
      
      main = getLine >>= (printAll . heights 0)
      

      一些压缩(260 个字符):

      a x y|x==y=0
           |x<y= -1
           |True=1
      c h (x:y:z)=(x,h):(c(h+(a x y))(y:z))
      c h [y]=[(y,h)]
      d ((x,h):xs)i=(if i==h then x else ' '):d xs i
      d [] _=[]
      p xs = mapM_ (putStrLn .(d xs)) [(minimum $ map snd xs)..(maximum $ map snd xs)]
      main = getLine >>= (p . c 0)
      

      【讨论】:

      • (x&gt;y)-(x&lt;y) 是一种比较高程的简短方法。
      • (x>y)-(x
      • 海拔是向下 (-1)、无 (0) 或向上 (+1),所以是的。
      • 您可以将| 移动到自己的行以缩短代码(在a 中)。
      • heightDiff x y = signum $ x-y,或a x=signum.(x-)。你可以通过内联来保存字符。
      【解决方案15】:

      Perl,88 个字符

      现在,编辑为 88 个字符:

      $_=<>;
      s/.(?=(.))/($"x40).$&.$"x(39+($1cmp$&))/ge;
      @_=/.{80}/g;
      {say map{chop||die}@_;redo}
      

      曾经:

      $_=<>;
      s/.(?=(.))/$&.$"x(79+($1cmp$&))/ge;
      s/^.{40}|.{80}/$&\n/g;
      print $& while /.$/gm || s/.$//gm * /\n/;
      

      97 个字符(省略空格)。它不是那么短,但我想知道是否有更多 PERL 经验的人可以进一步缩短它。并发现任何错误。第二行使用空格在 80 宽的环绕屏幕上形成垂直而不是水平下降的波浪。第三行插入换行符。最后一行翻转 X/Y 轴。

      我最初想知道最后两行是否可能类似于 interleave(s/.{80}/g) ,其中 interleave 交错一个字符串数组。但似乎没有我希望的那个功能。 (或者图书馆里有吗?)

      【讨论】:

      • 不错!不过,我没有看到输出中的最后一个字符。我的系统是否需要使用"\r\n" 样式的换行符,或者say --> {local $/="\n";print} 翻译中丢失了某些内容(对于我的 v5.8)?
      • 谢谢。我不知道。我认为它肯定依赖于在输入字符串的末尾有一个或两个不是'\n'的空白字符,但我还没有考虑清楚。它可能取决于确切的输入字符串,最后一个字符是打印在第一个字符的上方还是下方。 (或者甚至错过更多字符——我没有正确测试它。)在第一个正则表达式末尾添加 's' 标志可以在某些情况下修复它,其中有一个尾随 '\n',但理想情况下它应该可以工作,即使没有尾随输入。
      【解决方案16】:

      C# 中的第一次大喊。输入必须作为第一个命令行参数提供。

      using System;
      using C = System.Console;
      
      static class P
      {
          static void Main(string[] a)
          {
              var b = a[0];
              var l = b.Length;
      
              int y = 0, z = 0;
              for (int i = 0; i < l - 1; i++)
              {
                  y += Math.Sign(b[i] - b[i + 1]);
                  z = Math.Min(y, z);
              }
      
              y = 0;
              for (int i = 0; i < l - 1; i++)
              {
                  C.SetCursorPosition(i, y - z);
                  C.Write(b[i]);
      
                  y += Math.Sign(b[i] - b[i + 1]);
              }
          }
      }
      

      这会产生 280 字节的压缩数据。

      using System;using C=System.Console;static class P{static void Main(string[]a){var b=a[0];var l=b.Length;int y=0,z=0;for(int i=0;i&lt;l-1;i++){y+=Math.Sign(b[i]-b[i+1]);z=Math.Min(y,z);}y=0;for(int i=0;i&lt;l-1;i++){C.SetCursorPosition(i,y-z);C.Write(b[i]);y+=Math.Sign(b[i]-b[i+1]);}}}

      用不同的方法尝试第二个。

      using System;
      using System.Collections.Generic;
      
      static class P
      {
          static void Main(string[] a)
          {
              var b = a[0] + "$";
              var l = new List<string>();    
              var y = -1;
      
              for (int i = 0; i < b.Length - 1; i++)
              {
                  if ((y == -1) || (y == l.Count))
                  {
                      y = y < 0 ? 0 : y;
                      l.Insert(y, b.Substring(i, 1).PadLeft(i + 1));
                  }
                  else
                  {
                      l[y] = l[y].PadRight(i) + b[i];
                  }
                  y += Math.Sign(b[i] - b[i + 1]);
              }
      
              foreach (var q in l) Console.WriteLine(q);
          }
      }
      

      可以进一步重写循环以使用 try/catch 块。

      for (int i = 0; i < b.Length - 1; i++)
      {
          try
          {
              l[y] = l[y].PadRight(i) + b[i];
          }
          catch
          {
              y = y < 0 ? 0 : y;
              l.Insert(y, b.Substring(i, 1).PadLeft(i + 1));
          }
      
          y += Math.Sign(b[i] - b[i + 1]);
      }
      

      这会产生稍微修改和压缩的 321 字节 - 比第一次尝试多一点,但更健壮。

      using System;static class P{static void Main(string[]a){var b=a[0]+"$";var r=new System.Collections.Generic.List&lt;string&gt;();var y=-1;for(int i=0;i&lt;b.Length-1;i++){try{r[y]=r[y].PadRight(i)+b[i];}catch{y=y&lt;0?0:y;r.Insert(y,b[i].ToString().PadLeft(i+1));}y+=Math.Sign(b[i]-b[i+1]);}foreach(var l in r)Console.WriteLine(l);}}

      【讨论】:

      • 不将P设为静态可以节省7个字符。
      【解决方案17】:

      PowerShell

      我确信这可以用更少的代码来完成,如果有人想编辑那将是极好的。我让它可读。

      $v = (Read-Host).ToCharArray()
      $r = @(0)
      for($i = 1; $i -lt $v.length; $i++) {
          $p = $i - 1
          $r += $r[$p] + [System.Math]::Sign($v[$i] - $v[$p])
          $t = [System.Math]::Max($t, $r[$i])
          $b = [System.Math]::Min($b, $r[$i])
      }
      for($i = $t; $i -ge $b; $i--) {
          for($x = 0; $x -lt $r.length; $x ++) {
              if($r[$x] -eq $i) {
                  $o += $v[$x]
              }
              else {
                  $o += " "
              }
          }
          $o += "`n"
      }
      $o
      

      【讨论】:

        【解决方案18】:

        F#,242 个字符:

        let F(s:string)=(fun L->let a=Array.init(L*3)(fun _->Array.create L ' ')in Seq.fold(fun(r,p,c)n->let r=r+sign(int p-int n)in a.[r].[c]<-n;r,n,c+1)(L,s.[0],0)s;for r in a do if Array.exists((<>)' ')r then printfn"%s"(new string(r)))s.Length
        

        为了便于阅读,添加了空格

        let F(s:string) = 
           (fun L->
            let a = Array.init (L*3) (fun _ -> Array.create L ' ') in 
            Seq.fold (fun (r,p,c) n ->
                    let r = r + sign(int p-int n) in 
                    a.[r].[c]<-n;
                    r, n, c+1)
                (L, s.[0], 0)
                s;
            for r in a do 
                if Array.exists ((<>) ' ') r then 
                    printfn "%s" (new string(r))
           ) s.Length
        

        【讨论】:

          【解决方案19】:

          C(157 个字符)

          我暂时被困在那里。我认为C不会在这一点上击败J。不过,感谢 strager 帮助修剪 8 个字符。

          char*p,a[999][80];w,x,y=500;main(c){for(gets(memset(p=*a,32,79920));*p;
          a[y][x++]=c=*p++)y+=*p<c,y-=*p>c;for(;++w<998;strspn(p," ")-79&&puts(p))
          79[p=a[w]]=0;}
          

          格式化:

          char *p,         /* pointer to current character (1st) or line (2nd) */
               a[999][80]; /* up to 998 lines of up to 79 characters */
          
          w, x, y = 500;   /* three int variables. y initialized to middle of array */
          
          main(c){
              for(gets(memset(p=*a, 32, 79920));
              /* 999 * 80 = 79920, so the entire array is filled with space characters.
               * memset() returns the value of its first parameter, so the above is
               * a shortcut for:
               *
               *     p = *a;
               *     memset(p, 32, 79920);
               *     gets(p);
               *
               * Incidentally, this is why I say "up to 998 lines", since the first
               * row in the array is used for the input string.
               *
               * **** WARNING: Input string must not be more than 79 characters! ****
               */
          
              *p;a[y][x++] = c = *p++)  /* read from input string until end;
                                         * put this char in line buffer and in prev
                                         */
                  y += *p < c,          /* if this char < prev char, y++ */
                  y -= *p > c;          /* the use of commas saves from using { } */
          
              for(;++w < 998;         /* will iterate from 1 to 998 */
              strspn(p, " ") - 79 &&
              /* strspn returns the index of the first char in its first parameter
               * that's NOT in its second parameter, so this gets the first non-
               * space character in the string.  If this is the NULL at the end of
               * the string (index 79), then we won't print this line (since it's blank).
               */
              puts(p))  /* write the line out to the screen (followed by '\n') */
                  79[p = a[w]] = 0;    /* same as "(p = a[y])[79] = 0",
                                        * or "p = a[y], p[79] = 0", but shorter.
                                        * Puts terminating null at the end of each line
                                        */
          }
          

          我懒得支持超过 79 个字符的输入,因为这会在大多数终端上造成混乱的换行。

          【讨论】:

          • 如果您不支持超过 79 个输入字符,为什么要支持 999 个位置?它们一次只能增加一个,因此范围不能大于 80。将垂直宽度设置为 99 可以为您节省大量字符,并且虽然不安全或严格正确,但对于大多数输入来说都是“可行的”。
          • 大部分,但不是全部。我必须支持 79 上和 79 下,加上中心,加上输入行,使它成为 160。我想,为了效率,我可以把它设为 160,但是 999 占用相同数量的字符并且占用更少深谋远虑。不过,您是对的,将高度设为 99 将支持 most 输入并节省 4 个字符。
          • 开头可以写char*p,...,而不是char a[999]...。您可以在memset 调用中编写p=*a,然后将memset 调用放在第一个for 的第一部分。您的代码中根本不使用 x (我认为),那么为什么不将它用作循环变量呢? (y=0 占用的字节数比 x; 多。)在 for 循环中,将 ?: 部分放在 for 循环的第三部分以保存一个字节。
          • 我不得不说,虽然你的代码很短,但它是非标准的,因为它传递了int,其中一些库调用需要一个指针。我将不得不采用您在我自己的答案中使用的一些技术来减少它。 ;P +1 仍然。
          • @strager:哦!你有一些很好的收获。谢谢。我确实使用x (a[y][x++]=c=*p),但你说得对,声明另一个变量比将我已经拥有的变量清零便宜。 将 ?: 部分放入 for 循环中”: 我曾考虑将循环体移动到 for 循环的第三部分,但它实际上并没有保存任何东西,因为我for 之后仍然必须有一个分号。所以我选择了相同大小的较少混淆。“它是非标准的”: 哦,这太可怕了!不过,它没有摩尔斯电码挑战那么可怕,我想。
          【解决方案20】:

          一个 Java 解决方案,没有特别压缩(现在修改为从标准输入读取)。

          public class W
          { 
           public static void main(String[] x)
           {
            String s = new java.util.Scanner(System.in).nextLine();
            int i,j;
            int t = s.length();
            char[] b = s.toCharArray();
            char[][] p = new char[2*t][t];
            int q = t;
            char v = b[0];
            for (i=0; i<2*t; i++)
            {
             for (j=0; j<t; j++)
             {
              p[i][j] = ' ';
             }
            }
            p[q][0] = v;
            String z = new String(p[0]);
            for (i=1; i<t; i++)
            {
             char c = b[i];
             int d = (c == v) ? 0 : (c > v ? -1 : 1);
             q += d;
             p[q][i] = c;
             v = c;
            }
            for (i=0; i<2*t; i++)
            {
             String n = new String(p[i]);
             if (!n.equals(z))
             {
              System.out.println(n);
             }
            }
           } 
          }
          

          【讨论】:

            【解决方案21】:

            C#(564 个字符的代码)

            using System;
            class Program {
                static void Main(string[] args) {
                    var input = args[0];
                    int min = 0, max = 0;
                    var heights = new int[input.Length];
            
                    for (var i = 1; i < input.Length; i++) {
                        heights[i] = heights[i-1] + (input[i] > input[i-1] ? 1 : (input[i] < input[i-1] ? -1 : 0));
                        min = Math.Min(min, heights[i]);
                        max = Math.Max(max, heights[i]);
                    }
            
                    for (var row = max; row >= min; row--, Console.WriteLine())
                        for (var col = 0; col < input.Length; col++)
                            Console.Write(heights[col] == row ? input[col] : ' ');
                }
            }
            

            压缩:(324 个字符的代码)

            using System;class A{static void Main(string[] args){var I=args[0];int M=0,X=0;var H=new int[I.Length];for(var i=1;i<I.Length;i++){H[i]=H[i-1]+(I[i]>I[i-1]?1:(I[i]<I[i-1]?-1:0));M=Math.Min(M,H[i]);X=Math.Max(X,H[i]);}for(var r=X;r>=M;r--,Console.WriteLine())for(var c=0;c<I.Length;c++)Console.Write(H[c]==r?I[c]:' ');}}
            

            使用 cmets 的技巧(283 个字符):

            using System;class A{static void Main(string[] a){var I=a[0];int M=0,X=0,i=1,r,h,c=0,l=I.Length;var H=new int[l];for(;i<l;i++){h=H[i-1]+(I[i]>I[i-1]?1:(I[i]<I[i-1]?-1:0));H[i]=h;M=M<h?M:h;X=x>h?X:h;}for(r=X;r>=M;r--,Console.Write('\n'))for(;c<l;c++)Console.Write(H[c]==r?I[c]:' ');}}
            

            【讨论】:

            • args 可以改写为a 什么的。另外,你不能定义irc以及MX吗?
            • 您可以通过替换 "M=Math.Min(M,H[i]);X=Math.Max(X,H[i]);" 来减少 7 个字符用 "var h=H[i];M=Mh?X:h;"
            • Console.WriteLine() 也可以换成 Console.Write('\n')
            • 将 I.Length 拉入一个变量可以节省大量空间
            • 呃,WriteLine() 的长度不是和 Write('\n') 完全一样吗? :-)
            【解决方案22】:

            Perl 5.10

            159 个字符,最“用户友好”的版本:

            perl -nE'chop;@l=split//;$l{$_}=$l{$_-1}+($l[$_]cmp$l[$_-1])for 0..$#l;%e=();for$x(sort{$b<=>$a}grep{!$e{$_}++}values%l){say map{$l{$_}==$x?$l[$_]:" "}0..$#l}'
            

            以下版本为153个字符,但只能输入一行。要输入多个,您必须重新启动程序。规则不清楚是否允许这样做,但我认为最好还是发布两个版本:

            perl -nE'chop;@l=split//;$l{$_}=$l{$_-1}+($l[$_]cmp$l[$_-1])for 0..$#l;for$x(sort{$b<=>$a}grep{!$e{$_}++}values%l){say map{$l{$_}==$x?$l[$_]:" "}0..$#l}'
            

            这是一个 149 字符版本 - 这是一个脚本而不是 shell 单行,也只适用于一行输入,但之后不会继续接受输入第一行,这可能是件好事:

            $_=<>;chop;@l=split//;$l{$_}=$l{$_-1}+($l[$_]cmp$l[$_-1])for 0..$#l;for$x(sort{$b<=>$a}grep{!$e{$_}++}values%l){say map{$l{$_}==$x?$l[$_]:" "}0..$#l}
            

            这些都没有已经发布的 Perl 解决方案那么短,但它们似乎确实胜过 Python 和 Ruby。此外,还有不止一种方法可以做到这一点。

            【讨论】:

            • 咳咳,Ruby 条目现在是 122,目前击败了所有 Perl 版本。
            • 在我发帖时,Ruby 大约 179 岁。另一个 Perl 进入者似乎根本不愿意修剪他的条目,所以我自己承担了为他做这件事的责任。
            【解决方案23】:

            F#,235 个字符

            与我的其他解决方案相比,完全不同的策略节省了一些字符。

            let F(s:string)=(fun L->let _,_,h=Seq.fold(fun(p,h,l)n->let r=h-sign(int n-int p)in n,r,r::l)(s.[0],0,[0])s in for r in Seq.min h..Seq.max h do printfn"%s"(new string(Array.init L (fun c->if r=h.[L-1-c]then s.[c]else ' '))))s.Length
            

            带空格:

            let F(s:string) = 
               (fun L->
                let _,_,h = Seq.fold (fun (p,h,l) n ->
                    let r = h - sign(int n-int p) in 
                    n,r,r::l) (s.[0],0,[0]) s in 
                for r in Seq.min h..Seq.max h do 
                    printfn "%s" (new string(Array.init L (fun c -> 
                        if r=h.[L-1-c] then s.[c] else ' ')))
               ) s.Length   
            

            【讨论】:

              【解决方案24】:

              C# 545 字节未压缩

              using System;
              using System.Linq;
              class Program{
                  static void Main(string[] b){
                      var s = b[0];
                      var t = new System.Collections.Generic.Dictionary<int, string>();
                      int y=0, p=0;
                      for (int i = 0; i < s.Length; i++){
                          y += Math.Sign(s[i] - p);
                          p = s[i];        
                          if (!t.ContainsKey(y))
                              t.Add(y, "");
                          t[y] = t[y].PadRight(i) + s[i];
                      }
                      foreach (var v in t.OrderBy(a => -a.Key))
                          Console.WriteLine(v.Value);
                  }
              }
              

              【讨论】:

                【解决方案25】:

                Ruby:109 字节,计算换行符!!

                s=gets
                r,a,q,i=[],s[0,1],99,0
                s.chars{|x|q+=a<=>x
                a=x
                t=r[q]||=""
                r[q]+=" "*(i-t.size)+x
                i+=1}
                puts r.compact
                

                未压缩:

                s = gets
                r,a,q,i = [],s[0,1],99,0
                s.chars { |x|
                  q += a<=>x
                  a  = x
                  t = r[q] ||= ""
                  r[q]  += " "*(i-t.size)+x
                  i += 1
                }
                puts r.compact
                

                【讨论】:

                • 我得到 [E:\ruby]wavegolf.rb abcdefgh E:/ruby/wavegolf.rb:3: undefined method 'chars' for "abcdefgh\n":String (NoMethodError) 知道什么可能是错的?
                • 听起来你运行的是 1.8.6 或更早版本。
                【解决方案26】:

                Groovy(195 个字符)

                测试

                s="1234567890qwertyuiopasdfghjklzxcvbnm"
                

                =(s=~/./).collect{(char)it}
                e=' ';x=0;l=[];u=[]
                w.eachWithIndex({it,n->
                if(l.size()>x){l[x]+=e*(n-u[x]-1)+it;u[x]=n}else{l+=e*n+it;u+=n}
                if(w[n+1]>it)x++else x--;})
                l.reverse().each({println it})
                

                【讨论】:

                  【解决方案27】:

                  PHP:108 个字符

                  <?while(-1<$a=fgetc(STDIN)){$d+=$a<$b^-($a>$b);$r[$d].=' ';$r[$d][$k++]=$b=$a;}ksort($r);echo join("\n",$r);
                  

                  可读版本:

                  <?
                  while(-1<$a=fgetc(STDIN)){
                    $d+=$a<$b^-($a>$b);
                    $r[$d].=' ';
                    $r[$d][$k++]=$b=$a;
                  }
                  ksort($r);
                  echo join("\n",$r);
                  

                  【讨论】:

                    【解决方案28】:

                    Golfscript - 65 个字符

                    ' ': :c;1/:a,.+,{:N;a,a{:@c<+c@:c<-.N=[ c]\=}%.[n+'']\$-1= ==\;}%
                    

                    逐行生成波形

                    {:N;a,a{:@c<+c@:c<-.N=[ c]\=}%
                    

                    过滤掉空行

                    .[n+'']\$-1= ==\
                    

                    【讨论】:

                      【解决方案29】:

                      ASL:73

                      args1[,;{ch},1_]@1]o o>:><-0 0a:/+,/&-;{()@:'{" "`}}@;{};;{(){`}#`}" ":|P
                      

                      我刚刚将 J 方案翻译成 ASL。

                      【讨论】:

                        【解决方案30】:

                        XQuery

                        (257 字节)

                        declare variable$i external;let$c:=string-to-codepoints($i),$h:= for$x at$p in$c
                        return sum(for$x in 1 to$p let$d:=$c[$x]-$c[$x -1]return(-1[$d>0],1[$d<0]))return
                        codepoints-to-string(for$p in min($h)to max($h),$x at$q
                        in($c,10)return(32[$h[$q]!=$p],$x)[1])
                        

                        由于 XQuery 是纯声明性的,我不得不将输入伪装成通过外部变量传入。这是用 XQSharp 运行它的命令行:

                        xquery wave.xq !method=text i='1234567890qwertyuiopasdfghjklzxcvbnm'
                        

                        如果字符串作为上下文项传入,则可以进一步减少,但是所有 XQuery 实现都不支持将上下文项设置为非节点值(XQSharp 命令行工具也不支持):

                        let$c:=string-to-codepoints(.),$h:= for$x at$p in$c return sum(for$x in 1 to$p
                        let$d:=$c[$x]-$c[$x -1]return(-1[$d>0],1[$d<0]))return codepoints-to-string(for$p
                        in min($h)to max($h),$x at$q in($c,10)return(32[$h[$q]!=$p],$x)[1])
                        

                        只有 228 个字节。

                        【讨论】:

                          猜你喜欢
                          • 2010-12-17
                          • 1970-01-01
                          • 1970-01-01
                          • 2010-12-01
                          • 1970-01-01
                          • 1970-01-01
                          • 2010-11-28
                          • 2011-02-08
                          • 2010-10-24
                          相关资源
                          最近更新 更多