代码高尔夫:谢尔宾斯基三角形

37

挑战

输出N次迭代的Sierpinski三角形的ASCII表示形式的最短代码,该三角形由以下ASCII三角形制成:

 /\
/__\

输入为一个正整数。

测试用例

Input:
    2
Output:
       /\
      /__\
     /\  /\
    /__\/__\

Input:
    3
Output:
           /\
          /__\
         /\  /\
        /__\/__\
       /\      /\
      /__\    /__\
     /\  /\  /\  /\
    /__\/__\/__\/__\

Input:
    5
Output:
                                   /\
                                  /__\
                                 /\  /\
                                /__\/__\
                               /\      /\
                              /__\    /__\
                             /\  /\  /\  /\
                            /__\/__\/__\/__\
                           /\              /\
                          /__\            /__\
                         /\  /\          /\  /\
                        /__\/__\        /__\/__\
                       /\      /\      /\      /\
                      /__\    /__\    /__\    /__\
                     /\  /\  /\  /\  /\  /\  /\  /\
                    /__\/__\/__\/__\/__\/__\/__\/__\
                   /\                              /\
                  /__\                            /__\
                 /\  /\                          /\  /\
                /__\/__\                        /__\/__\
               /\      /\                      /\      /\
              /__\    /__\                    /__\    /__\
             /\  /\  /\  /\                  /\  /\  /\  /\
            /__\/__\/__\/__\                /__\/__\/__\/__\
           /\              /\              /\              /\
          /__\            /__\            /__\            /__\
         /\  /\          /\  /\          /\  /\          /\  /\
        /__\/__\        /__\/__\        /__\/__\        /__\/__\
       /\      /\      /\      /\      /\      /\      /\      /\
      /__\    /__\    /__\    /__\    /__\    /__\    /__\    /__\
     /\  /\  /\  /\  /\  /\  /\  /\  /\  /\  /\  /\  /\  /\  /\  /\
    /__\/__\/__\/__\/__\/__\/__\/__\/__\/__\/__\/__\/__\/__\/__\/__\

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


9
我开始没有更多的想法了……你一直在大力挖掘“控制台输出数据”这一点。也许现在是放弃这个点子的时候了。《Lasers》不同寻常的地方之一就是输入并不平凡。或者干脆整个放松一下,但我已经习惯了周四的打球时间。即使我没有提交很多解决方案,我仍会对你的大部分问题进行摸索。 - dmckee --- ex-moderator kitten
11
LiraNuna,你做得非常棒。你的挑战获得最多的投票是有原因的。即使你再也不发表任何内容,你仍将成为Stack Overflow的传奇人物。感谢你带来的乐趣! - DigitalRoss
2
@dmckee:那我会尝试更多地思考激光的方式。虽然设计激光很困难,但我有一些想法,只是还没有完善。我可以始终开始“反向”系列!(反向蜂巢!) - LiraNuna
ephemient: *"文本格式化"*?方块或沙漏式呢?它们是使用输入变量从ASCII创建的。那些不好吗?我个人喜欢方块和蜂巢 - 它们足够简单,适合新手创建长答案并参与,但是具有适当代码可以缩短答案的潜力。 - LiraNuna
@LiraLuna:这些都很有趣,我感到很遗憾自己来晚了,没能做出什么好的贡献。尽管我“不喜欢”,但还是回答了(可能因为只用几分钟就写出了J语言的解决方案,而不是通常需要几个小时)。 - ephemient
显示剩余9条评论
21个回答

27

J

从标准输入读取46个字符。

(,.~,~[,.~' '$~#,#)^:(<:".1!:1]3)' /\',:'/__\'

\n总是分隔句子,这使得它无法适应S3(只有54个字符可用)。S4有点大,有162个字符,所以我加了填充。巧合的是,/\是一个合法的副词。☺

               /\
              i=:3
             /\  /\
            %r=:1!:1
           /\      /\
          t=:]    [r+i
         /\  /\  /\  /\
        b=:' /\',:'/__\'
       /\              /\
      i=:1            -".t
     /\  /\          /\  /\
    h=:(' '$        ~#,#),.]
   /\      /\      /\      /\
  s=:(    h^:1    ,d=:    ,.~)
 /\  /\  /\  /\  /\  /\  /\  /\
(,,&(10{a.)"1[s^:(-i)b)(1!:2)(4)

5
60个字符。挑战要求一个完整的程序。 - LiraNuna
8
哎呀,那里有两个困倦的笑脸 (~,~) 和一个微笑的 (=])!这太可爱了! - LiraNuna
我实际上看到另一个 :( - RCIX
1
我上周五已经给你点赞了 :p,但是这个三角形真的很棒。 - John La Rooy

24

抱歉我来晚了。这是基于A. Rex的Perl解决方案:

                           &I                               
                          ;for                              
                         $x  (2                             
                        ..<>){$E                            
                       .=      $E                           
                      ;my$    y;3*                          
                     33  +3  **  3;                         
                    s".+"$y.=$n.$&x2                        
                   ,$              E.                       
                  $&.$            E"ge                      
                 ;;  $_          .=  $y                     
                }print;;        sub I{($                    
               E,      $n      ,$      F,                   
              $B,$    U)=(    $",$    /,qw                  
             (/   \   _  ))  ;$  _=  $E  .$                 
            F.$B.$E.$n.$F.$U.$U.$B};33333333                

4
我原本想用Golfscript来完成这个任务,但是我没有足够的字符。 - John La Rooy

20

Golfscript - 46

' /\ /__\ '4/{).+: ;.{ \ ++}%\{.+}%+~ ]}@~(*n*

Golfscript - 47

' /\ /__\ '4/): ;{  +: ;.{ \ ++}%\{.+}%+}@~(*n*

Golfscript - 48

' ': '/\ /__\\'+4/{2 *: ;.{ \ ++}%\{.+}%+}@~(*n*

Golfscript - 51

~' ': '/\ /__\\'+4/\(,{;2 *: ;.{ \ ++}%\{.+}%+}%;n*

与我较短的Python(和Ruby)答案相同的算法

Golfscript-78

2\~(?,{-1*}$1: ;{"  ":$*. 2base.{[$$+' /\ ']=}%n+@@{[$$+"/__\\"]=}%n .2*^: ;}%

和我较长的 Python 解决方案相同的算法

这个有重要的换行符

2\~(?,{-1*}$1: ;{"  ":
*. 2base.{[
2*' /\ ']=}%n+@@{[
2*"/__\\"]=}%n .2*^: ;}%

感谢您的辛勤工作,您已经促使我尽可能地简化我的解决方案 - 但我仍然无法击败您 :) - ephemient
1
这个被选中是因为它是第一个达到46个字符的标记。 - LiraNuna

16

Go, 273 characters

package main
import(f"fmt";"os";s"strconv";)func main(){var
t=[2]string{" /\\ ","/__\\"};
n,_:=s.Atoi(os.Args[1]);a:=1;N:=a<<uint(n);for
N>0{N-=2;for
k:=0;k<2;k++{for
j:=0;j<N;j++{f.Print(" ")}b:=a;for
b>0{o:=t[k];if
b&1==0{o="    "}f.Print(o);b>>=1}f.Print("\n")}a^=a*2}}

空格是非常重要的。

未压缩的代码,使用gofmt sierpinski-3.go | perl -p -e's/\t/ /g'

package main

import (
    "fmt";
    "os";
    "strconv";
)

func main() {
    var t = [2]string{" /\\ ", "/__\\"};
    n, _ := strconv.Atoi(os.Args[1]);
    a := 1;
    N := a << uint(n);
    for N > 0 {
        N -= 2;
        for k := 0; k < 2; k++ {
            for j := 0; j < N; j++ {
                fmt.Print(" ")
            }
            b := a;
            for b > 0 {
                o := t[k];
                if b&1 == 0 {
                    o = "    "
                }
                fmt.Print(o);
                b >>= 1;
            }
            fmt.Print("\n");
        }
        a ^= a * 2;
    }
}

我在这里得到了关于Go语言高效编程的有益提示:这里


5
我猜“Go”不是“高尔夫语言”的缩写。 - mob
@mobrule:我昨天才开始学习Go语言。我相信更有经验的Go程序员可以做得更好。不幸的是,由于这门语言只在两天前宣布,因此经验丰富的Go程序员并不多见。请参见http://stackoverflow.com/questions/1712172/。 - user181548
1
“:=” 让我感觉回到了高中 Turbo Pascal 课堂。 - gnovice
5
我不了解Turbo Pascal,但在Go语言中,x:=1的意思是var x int = 1,而y:="moo"则相当于var y string = "moo"。这里省略了变量类型,根据变量值推断出类型。 - user181548
在未经最小化的版本中,应删除所有分号。 - mk12
显示剩余2条评论

10

Python - 102

a=" /\ ","/__\\"
j=' '
for n in~-input()*j:j+=j;a=[j+x+j for x in a]+[x*2for x in a]
print"\n".join(a)

Python - 105

a=" /\ ","/__\\"
j=' '
for n in(input()-1)*j:j+=j;a=[j+x+j for x in a]+[x+x for x in a]
print"\n".join(a)

Python - 109

a=" /\ ","/__\\"
for n in range(1,input()):j=' '*2**n;a=[j+x+j for x in a]+[x+x for x in a]
print"\n".join(a)

Python2.6 - 120

N=1<<input()
a=1
while N:
 N-=2
 for s in" /\ ","/__\\":print' '*N+bin(a)[2:].replace('0',' '*4).replace('1',s)
 a=a^a*2

这个同样的挑战被发布在AnarchyGolf上。这是我的解决方案:http://golf.shinh.org/reveal.rb?Sierpinski+Fractal/MarkByers/1223081482&py - Mark Byers

9

Perl,82个字符

这个版本不再打印尾随的换行符。只有第一个换行符是必需的:

$_=' /\ 
/__\\';
for$x(2..<>){
my$y;
$".=$";
s#.+#$y.=$/.$&x2,$".$&.$"#ge;
$_.=$y
}
print

如果允许使用命令行开关,则按照传统的 Perl golf 计分法,这将是 77+3 条(第一个换行符为字面量):
#!perl -p
$\=' /\ 
/__\\';
$y="",
$".=$",
$\=~s#.+#$y.=$/.$&x2,$".$&.$"#ge,
$\.=$y
for 2..$_

如果你发现有改进的地方,欢迎随时编辑我的回答。


如果你要广泛使用开关,传统上会将其编写为shell调用:perl -pae'code here'(将shell调用和shell引号的所有字符计算为答案的一部分,这也将禁止您在答案中使用单引号)。但实际上可能会变得更长。 - Chris Lutz
1
@Chris Lutz:传统的 Perl 高尔夫记分是你的代码长度加上你需要添加到通常的 perl 之上的字符数。所以在我的情况下,我认为它是 77 杆加上额外的 -pa 所需的 4 杆。 - A. Rex
@ephemient:我并没有计算你刚才删除的换行符,它们只是为了可读性而存在(如果您可以在这种情况下说“可读性”的话)。等你编辑完成后,我会更改答案以明确这一点。谢谢你的帮助。 - A. Rex
@A. Rex - 我一直都有计算调用次数。(而且在我的系统上 #!perl 不是一个有效的 shebang 行。) - Chris Lutz
1
几乎所有你需要了解的J语言内容都可以从这个网页链接中找到:http://www.jsoftware.com/help/dictionary/vocabul.htm - ephemient
显示剩余5条评论

8

Haskell,153 149 137 125 118 112个字符:

使用尾递归:

(%)=zipWith(++)
p="  ":p
g t _ 1=t
g t s(n+1)=g(s%t%s++t%t)(s%s)n
main=interact$unlines.g[" /\\ ","/__\\"]p.read

早期版本,@118个字符:
(%)=zipWith(++)
f 1=[" /\\ ","/__\\"]
f(n+1)=s%t%s++t%t where t=f n;s=replicate(2^n)' ':s
main=interact$unlines.f.read

使用(理应废弃的!)n+k模式 节省了4个字符。

我喜欢它在压缩形式下也能够半读。

编辑:旧主要内容

main=do{n<-getLine;putStr$unlines$f$read n}

我在 Prelude 中发现了一些可能有用的东西: main=readLn>>=putStr.unlines.f - barkmadley
zipWith!我知道有更好的方法来做到这一点。 - barkmadley

7

Perl

94 characters when newlines are removed.

$c=2**<>;$\=$/;for$a(0..--$c){print$"x($c-$a&~1),
map$_*2&~$a?$"x4:$a&1?'/__\\':' /\ ',0..$a/2}

如果需要的话,使用<>从stdin读取可以节省5个字符。 如果不需要,pop仍然可以节省字符。 无论哪种方式,您都可以使用荒谬的构造$ c = 2 **〜- <>;$ c = 2 **〜- pop;来在/2周围节省括号。 - A. Rex

7

Ruby — 85

a=' /\ ','/__\\'
j=' '
2.upto(gets.to_i){j+=j;a=a.map{|x|j+x+j}+a.map{|x|x+x}}
puts a

101个字符 - 从Rosetta Code的解决方案中修改的/\
(a=2**gets.to_i).times{|y|puts" "*(a-y-1)+(0..y).map{|x|~y&x>0?'  ':y%2>0?x%2>0?'_\\':'/_':'/\\'}*''}

4

Python, 135个字符

S=lambda n:[" /\\ ","/__\\"]if n==1 else[" "*(1<<n-1)+x+" "*(1<<n-1)for x in S(n-1)]+[x+x for x in S(n-1)]
for s in S(input()):print s

1
可以通过将int(raw_input())更改为input()来稍微缩短这个代码。 - Jeffrey Aylesworth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接