悪魔の階段を描く


46

悪魔の階段は、カントール集合に関連するフラクタルのような機能です。

ここに画像の説明を入力してください

あなたの仕事は、このファンキーな機能をASCIIアートで再現することです!

入力

n >= 0出力のサイズを示す単一の整数。入力は、STDIN、関数引数、またはコマンドライン引数を介して指定できます。

出力

sizeの悪魔の階段のASCIIアート表現n。文字列として返されるか、STDOUTに出力されます。各行の末尾のスペースは大丈夫ですが、先頭のスペースはそうではありません。オプションで、単一の末尾の改行を印刷できます。

sizeの0場合、出力は次のとおりです。

x

(希望する場合は、スペースの代わりに、印刷可能な他のASCII文字を使用できますx。)

サイズについてはn > 0、次のとおりです。

  • サイズの出力をn-1取得し、各行を3倍に拡大します
  • 単一の行の間リフルx
  • 行を右にシフトしてx、各列に正確に1つがあり、最初の位置xは最小になりますが、行とともに減少します

たとえば、の出力n = 1は次のとおりです。

    x
 xxx
x

の出力を取得するにはn = 2、各行を3倍に拡大します。

            xxx
   xxxxxxxxx
xxx

singleの行間をさわらせますx

x
            xxx
x
   xxxxxxxxx
x
xxx
x

右にシフト:

                  x
               xxx
              x
     xxxxxxxxx
    x
 xxx
x

別の例として、ここにありn = 3ます。

得点

これはコードゴルフであるため、最小バイト数のソリューションが優先されます。

回答:


7

Pyth、30

jb_u+G+*leGd*HNu+N+^3hTNUQ]1]k

これは、STDINからの入力を受け取り、grcのCantorセットを見つける方法を使用するプログラムです。「」文字を使用して曲線を表示します。

こちらからオンラインでお試しください。

説明:

コードを2つの部分で説明します。まず、カンターセットの生成です。

u+N+^3hTNUQ]1
u        UQ]1         : reduce( ... , over range(input), starting with [1])
 +N                   : lambda N,T: N + ...
   +^3hTN             : 3 ** (T+1) + N   (int + list in pyth is interpreted as [int] + list)

そして出力フォーマット:

jb_u+G+*leGd*HN    ]k
jb_                    : "\n".join(reversed(...)
   u               ]k  : reduce(lambda G,H: ... , over cantor set, starting with [""])
    +G+*leGd           : G + len(G[-1]) * " " + ...
            *HN        : H * '"'

pythでは、デフォルトでN = '"'であることに注意してください。


32

J(73 68 58 41 39 38 35 34文字)

しばらくの間この問題について考えた後、悪魔の階段パターンを生成するまったく異なる方法を見つけました。説明を含む古い回答は削除されました。この回答の改訂を調べて、それがどのようであったかを理解できます。

この答えは、悪魔の階段を表す空白とシャープの配列を返します。

' #'{~1(]|.@=@#~[:,3^q:)2}.@i.@^>:

明示的な表記で2つの部分に分けられた回答を次に示します。

f =: 3 : '|. = (, 3 ^ 1 q: y) # y'
g =: 3 : '(f }. i. 2 ^ >: y) { '' #'''

説明

アプローチは少し異なりますので、観察してびっくりしてください。

  1. >: 3 – 3増分、つまり

    4
    
  2. 2 ^ >: 3 – 2の3乗、つまり、

    16
    
  3. i. 2 ^ >: 3–最初の2 ^ >: 3整数、つまり

    0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
    
  4. }. i. 2 ^ 4–最初の2 ^ >: 3整数、斬首、つまり

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
    

    このシーケンスを呼び出しましょうs; 今入りfます。

  5. 1 q: s–の各項目の素数分解における2の指数s。一般に、の素数分解のx q: y最初のx素数の指数の表を生成しますy。これにより以下が得られます。

    0
    1
    0
    2
    0
    1
    0
    3
    0
    1
    0
    2
    0
    1
    0
    
  6. 3 ^ 1 q: s –これらの指数の3乗、つまり

     1
     3
     1
     9
     1
     3
     1
    27
     1
     3
     1
     9
     1
     3
     1
    
  7. , 3 ^ 1 q: s–前の結果のラベル(つまり、その構造を持つ引数がベクトルに崩壊した)。q:不要な後続軸が導入されるため、これが必要です。これにより

     1 3 1 9 1 3 1 27 1 3 1 9 1 3 1
    
  8. (, 3 ^ 1 q: s) # ss前の結果の対応するアイテムと同じ頻度で複製された各アイテム、つまり

    1 2 2 2 3 4 4 4 4 4 4 4 4 4 5 6 6 6 7 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 9 10 10 10 11 12 12 12 12 12 12 12 12 12 13 14 14 14 15
    
  9. = (, 3 ^ 1 q: s) # s –前の結果の自己分類。これは、各行が引数の一意の項目の1つを表し、各列が引数の対応する項目を表し、各セルが行と列の項目が等しいかどうかを表す行列です。あれは、

    1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
    
  10. |. = (, 3 ^ 1 q: s) # s –前の結果が垂直軸に沿って反転しました。

  11. (|. = (, 3 ^ 1 q: s) # s) { ' #'-配列へのインデックスとして使用される前の結果の項目は' #'、そう0で置き換えられている 1によって置き換えられている#、すなわち、

                                                                    #
                                                                 ### 
                                                                #    
                                                       #########     
                                                      #              
                                                   ###               
                                                  #                  
                       ###########################                   
                      #                                              
                   ###                                               
                  #                                                  
         #########                                                   
        #                                                            
     ###                                                             
    #      
    

    望む結果。


電源ループ内では、 1バイト(,],~3^#@~.)@](1,[:,1,"0~3*])節約します。そして、!出力文字として別のものu:32+' #'{~保存する代わりに大丈夫なら。
-randomra

#\ 代わりにi.@#APLを追い越します!:)
randomra

キャップが必要になるため、2番目のソリューションは機能しませんが、APLを打ち負かす別の方法を見つけました。
FUZxxl

新しい出力は、の階段n-1ですn
randomra

@randomraああ…それはくだらない。修正可能かどうか見てみましょう。
FUZxxl

26

六角形、217バイト

これは非常に楽しかったです。このチャレンジを投稿していただきありがとうございます。

完全な開示:このチャレンジが投稿された時点では、言語(六角形)は存在していませんでした。しかし、私はそれを発明しなかったし、言語はこの課題(または他の特定の課題)向けに設計されていません。

){_2"_{\"{{""}"{'2//_.\><*\"\/_><[\]/3\'\_;|#__/(\2\'3_'}(#:|{$#{>_\//(#={/;01*&"\\_|[##={|}$_#></)]$_##|){*_.>.(/?#//~-="{}<_"=#/\}.>"%<.{#{x\"<#_/=&{./1#_#>__<_'\/"#|@_|/{=/'|\"".{/>}]#]>(_<\'{\&#|>=&{{(\=/\{*'"]<$_

六角形にレイアウト:

        ) { _ 2 " _ { \ "
       { { " " } " { ' 2 /
      / _ . \ > < * \ " \ /
     _ > < [ \ ] / 3 \ ' \ _
    ; | # _ _ / ( \ 2 \ ' 3 _
   ' } ( # : | { $ # { > _ \ /
  / ( # = { / ; 0 1 * & " \ \ _
 | [ # # = { | } $ _ # > < / ) ]
$ _ # # | ) { * _ . > . ( / ? # /
 / ~ - = " { } < _ " = # / \ } .
  > " % < . { # { x \ " < # _ /
   = & { . / 1 # _ # > _ _ < _
    ' \ / " # | @ _ | / { = /
     ' | \ " " . { / > } ] #
      ] > ( _ < \ ' { \ & #
       | > = & { { ( \ = /
        \ { * ' " ] < $ _

プログラムは実際に#命令を使用しないため、その文字を使用して、実際に使用されていないセルを示します。

このプログラムはどのように機能しますか?場合によります。短いバージョンが必要ですか、それとも長いバージョンですか?

簡単な説明

以下の説明で「ライン」と「セグメント」が意味することを説明するために、意図した出力のこの分析を検討してください。

segments →
 │   │ │         │ │   │x   lines
─┼───┼─┼─────────┼─┼───┼─     ↓
 │   │ │         │ │xxx│
─┼───┼─┼─────────┼─┼───┘
 │   │ │         │x│
─┼───┼─┼─────────┼─┘
 │   │ │xxxxxxxxx│
─┼───┼─┼─────────┘
 │   │x│
─┼───┼─┘
 │xxx│
─┼───┘
x│

説明すると、プログラムは次の擬似コードに対応します。

n = get integer from stdin

# Calculate the number of lines we need to output.
line = pow(2, n+1)

while line > 0:
    line = line - 1

    # For all segments except the last, the character to use is spaces.
    ch = ' ' (space, ASCII 32)

    # The number of segments in each line is
    # equal to the line number, counting down.
    seg = line

    while seg > 0:
        seg = seg - 1

        # For the last segment, use x’s.
        if seg = 0:
            ch = 'x' (ASCII 120)

        # Calculate the actual segment number, where the leftmost is 1
        n = line - seg

        # Output the segment
        i = pow(3, number of times n can be divided by 2)
        i times: output ch

    output '\n' (newline, ASCII 10)

end program

長い説明

この色分けされたコードパス図を参照してください。

実行パス

実行は左上隅から始まります。かなり複雑なパスを追跡することにより){2'"''3''"2}?)、一連の命令が実行されます(さらに、いくつかの冗長なキャンセル"{など)。深紅色で強調表示された命令ポインター#0から始めます。途中で、右上隅からフォレストグリーンに塗られた#1に切り替えます。IP#2がコーンフラワーブルー(右中央)で始まる場合、メモリレイアウトは次のようになります。

メモリレイアウト

プログラム全体を通して、2aおよび2bとラベル付けされたエッジは常に値を持ち2(それぞれ2ⁿ⁺¹を計算し、2で割る)、3とラベル付けされたエッジは常に3(3ⁱを計算するためにそれを使用します)。

コーンフラワーブルーで強調表示されている最初のループに入ると、ビジネスが始まります。このループは、命令(}*{=&}{=を実行して値2ⁿ⁺¹を計算します。ループが終了すると、茶色のサドルパスが使用され、命令ポインター#3に移動します。このIPは、ゴールデンロッドイエローで西の下端に沿って軽くたたくだけで、すぐにIP#4に制御を渡します。

フクシアのパスは、左下から始まるIP#4がデクリメントにすばやく進み、ch32(スペース文字)およびsegを(新しい値)lineに設定する方法を示します。それは、実際に2ⁿ⁺¹-1で始まり、最終的に値0で最後の反復を経験するのは初期の減少のためです。次に、最初のネストされたループに入ります。

私たちは、の簡単デクリメントした後、分岐藍、に注意を向けワンセグ、私たちが見るchはに更新されxた場合にのみ、ワンセグは今ゼロです。その後、nline-segに設定して、現在のセグメントの実際の数を決定します。すぐに別のループに入ります。今回はトマトの色がきれいです。

ここでは、我々は何回見つけ出すのn長いモジュロが私たちを与えるほどのために2で割ることができます(現在のセグメント番号)ゼロ、我々は増加しないと除算nは我々が成立したとき2でのnはもはやthusly割り切れます、2つのループを含むスレートグレーに分岐します。最初に3 を計算したiの累乗にし、次にchを何回も出力します。これらのループの最初に含まれていることに注意してください[命令、制御をIP#3に切り替えます。これは、以前に下端に沿って赤ちゃんの一歩を踏み出しただけのものでした。ループの本体(3倍とデクリメント)は、コードの下端に沿って無限の暗いオリーブグリーンのサイクルに閉じ込められた孤独なIP#3によって実行されます。同様に、これらのスレートグレーループの2番目には、]IP#5をアクティブにしてchとデクリメントを出力する命令が含まれています(ここでは濃いインド赤で示されています)。どちらの場合も、奴隷状態に陥った命令ポインターは、一度に1つの反復を素直に実行し、IP#4に制御を戻しますが、サービスが再び呼び出される瞬間を逃します。一方、スレートグレーは、フクシアとインディゴの兄弟に再び加わります。

SEG必然単に改行文字を出力し、速やかに継続するバックフクシアに合流芝生グリーンパスへインジゴループ終了し、ゼロに達するループ。ラインループの最後の反復を超えて、究極のプログラム終了の短いセーブルのebonパスがあります。


8
今、これは単なる昔ながらの狂気です。
FUZxxl

21

Python 2、78

L=[1]
i=3
exec"L+=[i]+L;i*=3;"*input()
while L:x=L.pop();print' '*sum(L)+'x'*x

リストから始めて、リストL=[1]を複製し、中央に次の3のべき乗を挿入し[1, 3, 1]ます。これはn、悪魔の階段の列の長さを与えるために何度も繰り返されます。次に、スペースが埋め込まれた各行を印刷します。


20

APL、38

⊖↑'x'/⍨¨D,⍨¨0,¯1↓-+\D←{1,⍨∊1,⍪3×⍵}⍣⎕,1

例:

      ⊖↑'x'/⍨¨D,⍨¨0,¯1↓-+\D←{1,⍨∊1,⍪3×⍵}⍣⎕,1
⎕:
      2
                  x
               xxx 
              x    
     xxxxxxxxx     
    x              
 xxx               
x   

説明:

⊖↑'x'/⍨¨D,⍨¨0,¯1↓-+\D←{1,⍨∊1,⍪3×⍵}⍣⎕,1

                                     ⎕       ⍝ read a number from the keyboard
                       {           }⍣ ,1      ⍝ apply this function N times to [1]
                               3×⍵           ⍝ multiply each value by 3
                           ∊1,⍪               ⍝ add an 1 in front of each value
                        1,⍨                  ⍝ add an 1 to the end
                     D←                      ⍝ store values in D (lengths of rows)
                   +\                        ⍝ get running sum of D
                  -                          ⍝ negate (negative values on / give spaces)
             0,¯1↓                           ⍝ remove last item and add a 0 to the beginning
                                             ⍝ (each row needs offset of total length of preceding rows)   
         D,⍨¨                                ⍝ join each offset with each row length
   'x'/⍨¨                                    ⍝ get the right number of x-es and spaces for each row
 ↑                                           ⍝ make a matrix out of the rows
⊖                                            ⍝ mirror horizontally 

それは素晴らしい解決策です。
-FUZxxl

20
コードの説明が悪魔の階段のように見えることが大好きです。
アレックスA.

さらに短いAPLソリューションが見つかりました。
-FUZxxl

14

GNU sed、142

最短の答えではなく、そのsed !:

s/$/:/
:l
s/x/xxx/g
s/:/:x:/g
tb
:b
s/^1//
tl
s/:x/X/g
s/^/:/
:m
s/.*:([Xx]+)Xx*:$/&\1:/
tm
:n
s/([ :])[Xx](x*Xx*)/\1 \2/g
tn
s/:/\n/g
s/X/x/g

これはsed(ネイティブの算術演算ではない)であるため、「出力のサイズを示す単一の整数n> = 0」というルールを自由に取っています。この場合、入力整数は1、長さがn であるsの文字列でなければなりません。これは、nに相当する直接的な数値ではありませんが、出力のサイズを「示している」と思います。したがって、n = 2の場合、入力文字列は次のようになります11

$ echo 11 | sed -rf devils-staircase.sed

                  x
               xxx
              x
     xxxxxxxxx
    x
 xxx
x

$ 

これは、O(c n)の指数関数的な時間の複雑さで完了するように見えます。ここで、cは約17です。n= 8は約45分かかりました。


あるいは、nを正確に数値で入力する必要がある場合は、次のようにします。

sed、274バイト

s/[0-9]/<&/g
s/9/8Z/g
s/8/7Z/g
s/7/6Z/g
s/6/5Z/g
s/5/4Z/g
s/4/3Z/g
s/3/2Z/g
s/2/1Z/g
s/1/Z/g
s/0//g
:t
s/Z</<ZZZZZZZZZZ/g
tt
s/<//g
s/$/:/
:l
s/x/xxx/g
s/:/:x:/g
tb
:b
s/^Z//
tl
s/:x/X/g
s/^/:/
:m
s/.*:([Xx]+)Xx*:$/&\1:/
tm
:n
s/([ :])[Xx](x*Xx*)/\1 \2/g
tn
s/:/\n/g
s/X/x/g

出力:

$ echo 2 | sed -rf devils-staircase.sed

                  x
               xxx
              x
     xxxxxxxxx
    x
 xxx
x

$ 

7
これは本当にクールです。
FUZxxl

8

Python 2、81

def f(n,i=1,s=0):
 if i<2<<n:q=3**len(bin(i&-i))/27;f(n,i+1,s+q);print' '*s+'x'*q

プログラムバージョン(88)

def f(n,s=0):
 if n:q=3**len(bin(n&-n))/27;f(n-1,s+q);print' '*s+'x'*q
f((2<<input())-1)

n1番目のインデックスが付けられた行のxの数は、3の累乗(nlsbから始まる、の最初のセットビットのインデックス)です。


8

Python 2、74

def f(n,s=0):
 if~n:B=3**n;A=s+B-2**n;f(n-1,A+B);print' '*A+'x'*B;f(n-1,s)

再帰的アプローチ。サイズ$ n $の悪魔の階段は3つの部分に分かれています

  • 左再帰ブランチ、サイズの階段 n-1、その長さは3**n - 2**n
  • の中心線 x'、長さ3**n
  • 右側の再帰分岐、サイズが階段でn-1、その長さは3**n - 2**n

三つの部分の合計の長さであることに注意してください3*(3**n) - 2*(2**n)または3**(n+1) - 2**(n+1)誘導を確認しました。

オプションの変数にsは、印刷する現在のパーツのオフセットが格納されます。最初に、より大きなオフセットを使用して左ブランチに再帰し、次に中心線を印刷し、次に現在のオフセットで右ブランチを実行します。


6

CJam、36 35 33バイト

ここに別のCJamアプローチがあります(オプティマイザーのコードを見たことがないので、実際に大きく異なるかどうかはわかりません)。

L0sl~{{3*0s}%0s\+}*{1$,S*\+}%W%N*

これは0曲線に使用します。または、(grcのトリックを使用して)

LLl~){3\#a1$++}/{1$,S*\'x*+}%W%N*

を使用しxます。

ここでテストしてください。

説明

基本的な考え方は、最初に次のように行で配列を形成することです

["0" "000" "0" "000000000" "0" "000" "0"]

そして、このリストを確認するには、適切な量のスペースを追加します。

L0sl~{{3*0s}%0s\+}*{1$,S*\+}%W%N*
L                                 "Push an empty string for later.";
 0s                               "Push the array containing '0. This is the base case.";
   l~                             "Read and evaluate input.";
     {           }*               "Repeat the block that many times.";
      {    }%                     "Map this block onto the array.";
       3*                         "Triple the current string.";
         0s                       "Push a new zero string.";
             0s\+                 "Prepend another zero string.";
                   {       }%     "Map this block onto the result.";
                    1$            "Copy the last line.";
                      ,S*         "Get its length and make a string with that many spaces.";
                         \+       "Prepend the spaces to the current row.";
                             W%   "Reverse the rows.";
                               N* "Join them with newlines.";

他のバージョンも同様に機能しますが、次のような長さの配列を作成します

[1 3 1 9 1 3 1]

そして、それをx最終的なマップのsの文字列に変換します。


6

Dyalog APL、34文字

grcによるアプローチの使用。(ドミノ)文字で階段を描画し、stdinから入力を取得します。このソリューションはを前提としてい⎕IO←0ます。

' ⌹'[(∪∘.=⊖){⍵/⍳≢⍵}⊃(⊢,,)/3*⌽⍳1+⎕]
  • – stdinから入力を取得します。
  • ⌽⍳1+⎕0 から下までの数字のシーケンス(例3 2 1 0
  • 3*⌽⍳1+⎕– 3のべき乗(例27 9 3 1
  • (⊢,,)/3*⌽⍳1+⎕–前の結果は、grcのアプローチに従って悪魔の階段のステップ長を生成する⊢,,dfnに等しい暗黙の関数によって右から折り返されました{⍵,⍺,⍵}
  • {⍵/⍳≢⍵}⊃(⊢,,)/3*⌽⍳1+⎕ ステップに変換されたステップ長。
  • (∪∘.=⊖){⍵/⍳≢⍵}⊃(⊢,,)/3*⌽⍳1+⎕私のJソリューションのように、それは自己分類されました。すでに結果が正しく反転していることに注意してください。
  • ' ⌹'[(∪∘.=⊖){⍵/⍳≢⍵}⊃(⊢,,)/3*⌽⍳1+⎕] 数字は空白とドミノに置き換えられます。

4

ルビー、99

FUZxxlの回答に触発された、他の回答とは異なる回答

FUZxxlは、xの数がインデックスの2の因子の数に対応していることに注目しています。たとえば、n = 2の場合、次の因数分解があります。

1 =1
2 =1 * 2
3 =3
4 =1 * 2 * 2
5 =5
6 =3 * 2
7 =7

私はこれらの2のべき乗を抽出するより簡単な方法を使用してi=m&-m、シーケンスを生成します1 2 1 4 1 2 1。これなど。これは次のように機能します。

m-1m最上位ビットと同じですが、最下位の1のビットはゼロになり、右側のすべてのゼロは1になります。

これをオリジナルとANDできるようにするには、ビットを反転する必要があります。これにはさまざまな方法があります。1つの方法は、からそれを減算することです-1

全体的な式は、次のようm& (-1 -(m-1)) に単純化されますm&(-m)

例:

          100   01100100
100-1=     99   01100011
-1-99=   -100   10011100
100&-100=   4   00000100

コードは次のとおりです。他の答えとして、改行がカウントされ、インデントは不要であるためカウントされません。基数2 1 2 1 4 1 2 1 etcから基数3 への不器用な変換のため、他の回答よりも少し長くなっています1 3 1 9 1 3 1 etc(それを回避する方法はありMath::ますか?)

def s(n)
  a=[]
  t=0
  1.upto(2*2**n-1){|m|i=3**Math::log(m&-m,2)
    a.unshift" "*t+"x"*i 
    t+=i}
  puts a
end

3

ルビー、140 99

私の2番目のRubyコード、およびこの言語の最初の非自明な使用。提案は大歓迎です。バイトカウントではインデントの先頭のスペースは除外されますが、改行は含まれます(少なくともスペースで置き換えられない限り、ほとんどの改行は削除できないようです)。

入力は関数呼び出しによるものです。出力は文字列の配列で、rubyは単一ので改行区切りリストとしてstdoutに便利にダンプしますputs

アルゴリズムは、単純にnew iteration= previous iteration+ extra row of n**3 x's+ previous iterationです。しかし、そこにあるたくさんの 公正な量のコードは、単に出力の権利で先頭のスペースを取得します。

def s(n)
  a=["x"]
  1.upto(n){|m|t=" "*a[0].length
    a=a.map{|i|t+" "*3**m+i}+[t+"x"*3**m]+a}
  puts a
end

編集:ルビー、97

これは、a上記で説明した方法で配列に必要なすべてのxの数の数値テーブルを構築し、その後に文字列のテーブルを構築する、類似しているが異なるアプローチを使用します。文字列のテーブルはc、かなり奇妙な名前のunshiftメソッドを使用して既存の配列の先頭に追加する配列で逆向きに構築されます。

現在、このアプローチは見栄えがよくなっていますが、2バイトしかありません:-)

def s(n)
  a=c=[]
  (n+1).times{|m|a=a+[3**m]+a}
  t=0
  a.each{|i|c.unshift" "*t+"x"*i
    t+=i}
  puts c
end

1
あなたは置き換えることができfor m in(0..n-1)do ... endn.times{|m|...}
オマー

@Omarありがとう、明日試してみます。構文エラーが絶えないため、それを実行するのにどれだけの労力がかかったのか信じられないでしょう。繰り返し変数にアクセスする方法を知りませんでしn.timesた。確かにそれを覚えています。それも排除しendます!しかし、この機会に私はfor m in (1..n)、それを避けるために、より良いかもしれないかと思っていました(m+1)。それを書く短い方法はありますか?
レベルリバーセント

1
for使用を強制されているため、主に長いですenddo改行またはで置き換えることができます;)。以下のために1..nあなたが使用することができます1.upto(n){|m|...}。私はの外観が好きですが(1..n).each{|i|...}、それを使用するよりも少し長いですupto。また、eachor を呼び出して反復することuptoは短くなるだけでなく、より慣用的なRubyを考慮することにも注意してください。
オマー

@ありがとうございます、1.upto(n)そうです!それといくつかの不必要な括弧がなくなって、私はすでに120にまで下がっています。100未満は可能だと思うので、修正したコードを後で投稿します。
レベルリバーセント

3

Haskell、99文字

d=q.((iterate((1:).(>>=(:[1]).(*3)))[1])!!)
q[]=[];q(a:r)=sum r&' '++a&'x'++'\n':q r
(&)=replicate

機能はd次のとおりです。

λ: putStr $ d 3
                                                                x
                                                             xxx
                                                            x
                                                   xxxxxxxxx
                                                  x
                                               xxx
                                              x
                   xxxxxxxxxxxxxxxxxxxxxxxxxxx
                  x
               xxx
              x
     xxxxxxxxx
    x
 xxx
x

これらすべての括弧!より少ないもので回避する方法は本当にありませんか?
-FUZxxl

空のリストの場合に式を交換しqて実行q x=xすると、1バイトを失う可能性があります。また、括弧iterate...[1]は不要なようです。
ズガルブ

3

PHP-137バイト

function f($n){for($a=[];$i<=$n;array_push($a,3**$i++,...$a))$r=str_repeat;foreach($a as$v){$o=$r(' ',$s).$r(x,$v)."
$o";$s+=$v;}echo$o;}

ここではgrcと同じトリックを使用しています。以下は、バージョン化されていないバージョンです。

function staircase($n)
{
    $lengthsList = [];
    for ($i = 0; $i <= $n; ++$i) {
        array_push($lengthsList, 3 ** $i, ...$lengthsList);
    }

    $output = '';
    $cumulatedLength = 0;
    foreach ($lengthsList as $length)
    {
        $output = str_repeat(' ', $cumulatedLength) . str_repeat('x', $length) . "\n" . $output;
        $cumulatedLength += $length;
    }

    echo $output;
}

3**$i-> PHP 5.6のように感じます。指定する必要があります。これは、PHPのほとんどすべてのインストールと互換性がありません。数バイトを節約するために、$r=str_repeat;あなたはその機能を持っている場所から始め、に置き換えて$r2バイト節約することができます。また、$r('x',$v)することができ$r(x,$v)、それは正常に動作します(関数名を既に変数に置き換えていることに注意してください)。また、別のバイト++$i<=$n$n>++$i節約するように書き換えることができると思います。
イスマエルミゲル

ここにあなたの機能は少しクールなトリックで、次のとおりです。function f($n){$r=str_repeat;$a=[1];while($n>++$i)$a=array_merge($a,[3**$i],$a);foreach($a as$v){$o=$r(' ',$s).$r(x,$v)."\r$o";$s+=$v;}echo$o;}(代わりにその醜い改行を有するので、私はエスケープシーケンスを追加した\r変数で、二重引用符で囲まれた文字列内$o。その中にこのように"\r$o"同じバイト数を持っている''.$o1、最後の改行は省​​略され、同じ結果が生成されます
Ismael Miguel

実際には、この削減が適切に機能するための条件がwhile必要$n>$i++です。
イスマエルミゲル

@IsmaelMiguel PHP 5.6はPHPの最後のバージョンです。これ以上言う必要はありません。ほとんどすべての人が古いバージョンを使用しており、大多数が古いバージョンを使用している場合、それは私のせいではありません。$r=str_repeatトリックをありがとう。私はについてのみ考えてきましたが$r='str_repeat';、これはバイトを保存していませんでした。未定義の定数も良いトリックです、よくやった;)。改行は書き込みよりも1バイト小さいので\n、それを保持しましたが、との連結を避けるために二重引用符を使用しました$0。再度、感謝します !
ブラックホール

それはあなたにのみ似合うでしょう。もし私がそれを知らなければ3 ** $i、あなたはひどい構文を持っていると言うでしょう。その修正に対処できます。私はこれについてだけ言って[1]いますが、それはかなり古い「PHP5.4」から来たからではありません。1年前に、それを指定するようにお願いします。今日、これを指定する(非常に短い行で)単純に指定するようお願いします。コードについて言えば、++$i<=$nで置き換えることができるものがまだあります$n>$i++。テストするために、すべてのコードをPHP5.3に変換する必要がありました。痛かった。しかし、私はあなたがこれまでに7バイトを食べたことを見ます。
イスマエルミゲル

3

C、165

#define W while
f(n){int i=n+1,j=1<<i,k=1,l,r,s,t;W(i--)k*=3;l=k-j;W(--j){r=j,s=1;W(!(r%2))r/=2,s*=3;l-=s;t=l;W(t--)putchar(32);W(++t<s)putchar(88);putchar('\n');}}

以下は、同じコードを展開して少しクリーンアップしたものです。

int f(int n) {
    int i=n+1, j=1<<i, k=1;
    while (i--) k*=3;
    int l=k-j;
    while (--j) {
        int r=j,s=1;
        while (!(r%2))
            r/=2, s*=3;
        l-=s;
        int t=l;
        while (t--) putchar(' ');
        while (++t<s) putchar('X');
        putchar('\n');
    }
}

これは、FUZxxlの問題に対する解決策と同じ考え方に基づいており、行に暗黙的な形式ではなく明示的な形式を使用します。jの宣言は2 ^(n + 1)に設定し、最初のwhileループはk = 3 ^(n + 1)を計算します。その場合、l = 3 ^(n + 1)-2 ^(n + 1)は階段の全幅です(これは証明するのが難しくありません)。次に、1から2 ^(n + 1)-1までのすべての数値rを調べます。それぞれについて、(正確に)2 ^ nで割り切れる場合、s = 3 ^ n 'X'を印刷する予定です。lは適切な場所から開始するように調整されます。l個のスペースとs個の「X」、次に改行を記述します。


Wを; whileに定義し、intを省略して一部の文字を保存します。
FUZxxl

また、t = l- = sで保存することもできます。
FUZxxl

@FUZxxl私はそれらの両方を試しましたが、Cはまだ関数の暗黙的な型を許可しますが、(少なくともGCCで) 'classic'フラグがあっても変数宣言でそれらを許可しませんでした。そして、私は#define Wを試しました;一方、それは気にしなかったようですが、私は定義で滑っていたかもしれません。
スティーブンスタドニッキー

hm ...グローバル変数の型のみを省略できると思います。それはあまりあなたをもたらしません。を(*p)()=putchar;最初に追加して、putcharとして呼び出すことができpます。うまくいくと思う。
-FUZxxl

2

CJam、 46 43 41 39 36 35バイト

L0ri),(a*+_W%(;+{3\#'x*+_,S*}%$1>N*

現在、別のアプローチを使用して更新します。


古いアプローチ:

]ri){3f*_,)"x"a*\]z:+}*_s,f{1$,U+:U-S*\N}

かなり素朴で長いですが、始めるには何か。

ゴルフしたら説明を追加します。

こちらからオンラインでお試しください


いくつかの作業が必要なようです。n = 4、5、17の場合、正しく機能しませんでした。上部にxの左フォーマットの波紋文字列が表示されました。n = 17の場合、コードを画面にダンプし、下部をxで埋めました。
DavidC

1
@DavidCarraher 4、5の場合、これは単なる行の折り返しだと思います。行を折り返さずに出力をテキストエディターにコピーすると、問題ないように見えます。
Sp3000

OK。わかるよ。
DavidC

2

Java、271 269バイト

grcのメソッドを使用します。

import java.util.*;String a(int a){List<Integer>b=new ArrayList<>();int c=-1,d=1;for(;c++<a;b.add(d),b.addAll(b),b.remove(b.size()-1),d*=3);String f="";for(;b.size()>0;f+="\n"){d=b.remove(b.size()-1);for(int g:b)for(c=0;c<g;c++)f+=' ';for(c=0;c<d;c++)f+='x';}return f;}

インデント:

import java.util.*;
String a(int a){
    List<Integer>b=new ArrayList<>();
    int c=-1,d=1;
    for(;c++<a;b.add(d),b.addAll(b),b.remove(b.size()-1),d*=3);
    String f="";
    for(;b.size()>0;f+="\n"){
        d=b.remove(b.size()-1);
        for(int g:b)
            for(c=0;c<g;c++)
                f+=' ';
        for(c=0;c<d;c++)
            f+='x';
    }
    return f;
}

どんな提案でも大歓迎です。

mbomb007のおかげで2バイト


b.size()>0代わりに使用して!b.isEmpty()、2バイト節約できます。
mbomb007

1

Perl、62

#!perl -p
eval's/x+/$&$&$&
x/g,s/\d*/x
/;'x++$_;s/x+/$"x$'=~y!x!!.$&/ge

最初に、先頭のスペースなしで結果を繰り返し計算します。次にx、文字列の残りの文字数に従って、各行の前にそれらを追加します。


1

JavaScriptの(ES6)104 106 118

編集再帰関数を削除し、各行の「*」のリストを繰り返し取得します。他の多くの回答と同様に、ビットと3のべき乗をいじり
ます。各行に追加する先行スペースの

F=n=>{
  for(i=a=s='';++i<2<<n;a=s+'*'.repeat(t)+'\n'+a,s+=' '.repeat(t))
    for(t=u=1;~i&u;u*=2)t*=3;
  return a
}

最初の削除を削除

再帰的なR関数は、各行に「*」の数を持つ配列を作成します。たとえば、R(2)は[1, 3, 1, 9, 1, 3, 1]
この配列をスキャンして複数行の文字列をボトムアップで構築し、各行に追加する先行スペースの実行カウントを維持します

F=n=>
(R=n=>[1].concat(...n?R(n-1).map(n=>[n*3,1]):[]))(n)
.map(n=>a=' '.repeat(s,s-=-n)+'*'.repeat(n)+'\n'+a,a=s='')
&&a 

Firefox / FireBugコンソールでテストする

F(3)

出力

                                                                *
                                                             ***
                                                            *
                                                   *********
                                                  *
                                               ***
                                              *
                   ***************************
                  *
               ***
              *
     *********
    *
 ***
*

1

R-111文字

簡単な実装。アレイを繰り返し構築し、ゆっくりと破壊します。

n=scan()
a=1
if(n)for(x in 1:n)a=c(a,3^x,a)
for(A in a){cat(rep(' ',sum(a)-A),rep('x',A),'\n',sep='');a=a[-1]}

使用法:

> source('devil.r')
1: 2
2: 
Read 1 item
                  x
               xxx
              x
     xxxxxxxxx
    x
 xxx
x

良い点はn、コマンドラインから引数を取るようにコードを修正したことです
-koekenbakker

1
STDINから読み取ることで8バイトを節約できます。n=scan()
アレックスA.

xカーソルとして使用するために宣言する必要も、必要もありませんif(n)。また、改行は文字としてカウントされます。
freekvd

ありがとう、あなたは正しいxif(n)しかし、よくわかりません。事件に対処するためにその部分を追加しましたn=0if(n)次いで戻りF、したがって単一のを返しますx。削除すると、n=0望ましくない結果が得られます。ここでは新しいので、改行については知りませんでした。今含まれています!
koekenbakker

a=0ループを設定して開始するとx in 0:n、n = 0でも機能します。次に、if(n)。を省略できます。
freekvd
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.