Disegna la scala del diavolo


46

The Devil's Staircase è una funzione simile a un frattale relativa al set di Cantor.

inserisci qui la descrizione dell'immagine

Il tuo compito è replicare questa funzione funky - nell'arte ASCII!

Ingresso

Un singolo intero n >= 0, che indica la dimensione dell'output. L'input può essere fornito tramite STDIN, argomento della funzione o argomento della riga di comando.

Produzione

La rappresentazione in arte ASCII della scala del diavolo su misura n, restituita come una stringa o stampata su STDOUT. Gli spazi finali alla fine di ogni riga vanno bene, ma gli spazi iniziali no. Se lo si desidera, è possibile stampare una nuova riga finale.

Per dimensioni 0, l'output è solo:

x

(Se lo si desidera, è possibile utilizzare qualsiasi altro carattere ASCII stampabile diverso dallo spazio, al posto di x.)

Per dimensioni n > 0, noi:

  • Prendi l'output delle dimensioni n-1e allunga ogni riga di un fattore tre
  • Riffle tra le file di singole xs
  • Sposta le righe verso destra in modo che ce ne sia esattamente una xin ogni colonna e la posizione della prima xsia minima mentre diminuisce con le righe

Ad esempio, l'output per n = 1è:

    x
 xxx
x

Per ottenere l'output n = 2, estendiamo ogni riga di un fattore tre:

            xxx
   xxxxxxxxx
xxx

Scorri tra le file dei singoli x:

x
            xxx
x
   xxxxxxxxx
x
xxx
x

Spostamento verso destra:

                  x
               xxx
              x
     xxxxxxxxx
    x
 xxx
x

Come altro esempio, qui è n = 3.

punteggio

Questo è code-golf, quindi vince la soluzione nel minor numero di byte.

Risposte:


7

Pyth, 30

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

Questo è un programma che prende input da STDIN e usa il metodo di grc per trovare il set Cantor. Utilizza il carattere "per visualizzare la curva.

Provalo online qui.

Spiegazione:

Spiegherò il codice in due parti, in primo luogo, la generazione dell'insieme cantor:

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)

E la formattazione dell'output:

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 * '"'

Si noti che in pyth N = '"' per impostazione predefinita.


32

J ( 73 68 58 41 39 38 35 34 caratteri)

Dopo aver riflettuto sul problema per un po 'di tempo, ho trovato un modo completamente diverso di generare lo schema della scala del diavolo. La vecchia risposta inclusa la sua spiegazione è stata rimossa, puoi esaminare le revisioni di questa risposta per capire come è stata.

Questa risposta restituisce una serie di spazi vuoti e taglienti, che rappresentano la scala del diavolo.

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

Ecco la risposta suddivisa in due parti in notazione esplicita:

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

Spiegazione

L'approccio è un po 'diverso, quindi osserva e lasciati stupire.

  1. >: 3 - tre incrementati, ovvero

    4
    
  2. 2 ^ >: 3 - due alla potenza di tre incrementati, cioè

    16
    
  3. i. 2 ^ >: 3- i primi 2 ^ >: 3numeri interi, ovvero

    0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
    
  4. }. i. 2 ^ 4- i primi 2 ^ >: 3numeri interi, decapitati, ovvero

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

    Chiamiamo questa sequenza s; entriamo fora.

  5. 1 q: s- gli esponenti di 2 nella decomposizione primaria di ciascun oggetto di s. In generale, x q: yproduce una tabella degli esponenti per i primi xprimi nella decomposizione primaria di y. Questo produce:

    0
    1
    0
    2
    0
    1
    0
    3
    0
    1
    0
    2
    0
    1
    0
    
  6. 3 ^ 1 q: s - tre alla potenza di questi esponenti, cioè

     1
     3
     1
     9
     1
     3
     1
    27
     1
     3
     1
     9
     1
     3
     1
    
  7. , 3 ^ 1 q: s- il ravel (cioè l'argomento con la sua struttura è crollato in un vettore) del risultato precedente. Ciò è necessario perché q:introduce un asse finale indesiderato. Questo cede

     1 3 1 9 1 3 1 27 1 3 1 9 1 3 1
    
  8. (, 3 ^ 1 q: s) # s- ogni articolo sreplicato con la stessa frequenza dell'articolo corrispondente nel risultato precedente, ovvero

    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 - l'autoclassificazione del risultato precedente, ovvero una matrice in cui ogni riga rappresenta uno degli elementi univoci dell'argomento, ogni colonna rappresenta l'elemento corrispondente dell'argomento e ogni cella indica se gli elementi di riga e colonna sono uguali, questo è,

    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 - il risultato precedente è stato capovolto lungo l'asse verticale.

  11. (|. = (, 3 ^ 1 q: s) # s) { ' #'- gli elementi del risultato precedente utilizzati come indici nell'array ' #', quindi 0vengono sostituiti  e 1sostituiti da #, ovvero,

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

    il risultato che vogliamo.


All'interno del circuito di alimentazione (,],~3^#@~.)@]invece di (1,[:,1,"0~3*]) salvare 1 byte. E se stai bene con !l'output char u:32+invece di ' #'{~salvarne un altro.
randomra,

#\ invece di i.@#e superi APL! :)
randomra,

La tua seconda soluzione non funziona perché sarebbe necessario un limite, ma ho trovato un altro modo per battere APL.
FUZxxl,

Il nuovo output è la scala per il n-1non per n.
randomra,

@randomra Ah… è merda. Fammi vedere se è riparabile.
FUZxxl,

26

Esagonia , 217 byte

Questo è stato immensamente divertente. Grazie per aver pubblicato questa sfida.

Divulgazione completa: il linguaggio (Hexagony) non esisteva al momento della pubblicazione di questa sfida. Tuttavia, non l'ho inventato e il linguaggio non è stato progettato per questa sfida (o qualsiasi altra sfida specifica).

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

Disposto esagonalmente:

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

Il programma in realtà non utilizza l' #istruzione, quindi ho usato quel personaggio per mostrare quali celle sono veramente inutilizzate.

Come funziona questo programma? Dipende. Vuoi la versione corta o lunga?

Breve spiegazione

Per illustrare cosa intendo per "linea" e "segmento" nella seguente spiegazione, prendere in considerazione questa dissezione dell'output previsto:

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

Detto questo, il programma corrisponde al seguente pseudocodice:

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

Lunga spiegazione

Fare riferimento a questo diagramma del percorso del codice con codice colore.

Percorso di esecuzione

L'esecuzione inizia nell'angolo in alto a sinistra. La sequenza di istruzioni ){2'"''3''"2}?)viene eseguita (più alcune cancellazioni ridondanti, come "{ecc.) Perseguendo un percorso abbastanza contorto. Iniziamo con il puntatore a istruzioni n. 0, evidenziato in cremisi. A metà strada, passiamo al numero 1, iniziando nell'angolo in alto a destra e dipinto in verde foresta. Quando IP # 2 inizia in blu fiordaliso (al centro a destra), il layout della memoria è questo:

Layout di memoria

Durante l'intero programma, i bordi etichettati 2a e 2b avranno sempre il valore 2(li usiamo per calcolare 2ⁿ⁺¹ e dividiamo per 2, rispettivamente) e il bordo etichettato 3 sarà sempre 3(lo usiamo per calcolare 3ⁱ).

Entriamo in affari quando entriamo nel nostro primo anello, evidenziato in blu fiordaliso. Questo loop esegue le istruzioni (}*{=&}{=per calcolare il valore 2ⁿ⁺¹. Quando il loop termina, viene preso il percorso marrone della sella, che ci porta al puntatore di istruzioni n. 3. Questo IP si limita a dilagare lungo il bordo inferiore verso ovest in giallo dorato e presto passa il controllo a IP # 4.

Il percorso fucsia indica come IP # 4, iniziando in basso a sinistra, procede rapidamente alla linea di decremento , imposta ch su 32(il carattere spazio) e seg su (il nuovo valore di) linea . È a causa del decremento iniziale che in realtà iniziamo con 2ⁿ⁺¹ − 1 e alla fine sperimentiamo un'ultima iterazione con il valore 0. Quindi entriamo nel primo ciclo nidificato .

Rivolgiamo la nostra attenzione all'indaco ramificato, dove, dopo un breve decremento di seg , vediamo ch aggiornato xsolo se seg è ora zero. Successivamente, n viene impostato su line - seg per determinare il numero effettivo del segmento in cui ci troviamo. Immediatamente entriamo in un altro loop, questa volta nel bel colore del pomodoro.

Qui, scopriamo quante volte n (il numero di segmento corrente) può essere diviso per 2. Finché il modulo ci dà zero, incrementiamo i e dividere n per 2. Quando siamo soddisfatti n non è più così divisibile , ci ramifichiamo nel grigio ardesia, che contiene due anelli: prima aumenta 3 alla potenza dell'i che abbiamo calcolato, quindi emette ch molte volte. Si noti che il primo di questi loop contiene a[istruzione, che commuta il controllo su IP # 3 - quello che stava facendo solo piccoli passi lungo il bordo inferiore in precedenza. Il corpo del loop (moltiplicando per 3 e decrementando) viene eseguito da un IP # 3 solitario, imprigionato in un infinito ciclo verde oliva scuro lungo il bordo inferiore del codice. Allo stesso modo, il secondo di questi loop grigio ardesia contiene ]un'istruzione, che attiva IP # 5 per produrre ch e decremento, mostrato qui in rosso indiano scuro. In entrambi i casi, quei puntatori di istruzioni intrappolati nella servitù eseguono obbedientemente una iterazione alla volta e restituiscono il controllo a IP # 4, solo per dare il momento in cui il loro servizio verrà richiamato ancora una volta. Il grigio ardesia, nel frattempo, si unisce ai suoi fratelli fucsia e indaco.

Poiché seg inevitabilmente raggiunge lo zero, il ciclo indaco esce nel percorso verde prato, che semplicemente emette il carattere di nuova riga e si fonde rapidamente nel fucsia per continuare il ciclo di linea . Al di là dell'iterazione finale del loop di linea si trova il percorso ebon sable breve della terminazione finale del programma.


8
Ora questa è semplicemente una follia vecchio stile.
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

Iniziando con l'elenco L=[1], lo dupliciamo e inseriamo la potenza successiva di 3 nel mezzo, risultando in [1, 3, 1]. Questo è ripetuto nvolte per darci le lunghezze delle file per la scala del diavolo. Quindi stampiamo ogni riga imbottita di spazi.


20

APL, 38

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

Esempio:

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

Spiegazione:

⊖↑'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 

Questa è una bella soluzione.
FUZxxl,

20
Adoro il fatto che la spiegazione del codice assomigli ad una scala del diavolo.
Alex A.

Ho trovato una soluzione APL ancora più breve.
FUZxxl,

14

GNU sed, 142

Non la risposta più breve, ma è 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

Poiché si tratta di sed (nessuna aritmetica nativa), mi sto prendendo le libertà con la regola "Un singolo intero n> = 0, che indica la dimensione dell'output" . In questo caso, l'intero di input deve essere una stringa di 1s, la cui lunghezza è n. Penso che questo stia "indicando" la dimensione dell'output, anche se non è un equivalente numerico diretto di n. Pertanto per n = 2, la stringa di input sarà 11:

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

                  x
               xxx
              x
     xxxxxxxxx
    x
 xxx
x

$ 

Questo sembra completarsi con la complessità temporale esponenziale di O (c n ), dove c è circa 17. n = 8 ha impiegato circa 45 minuti per me.


In alternativa, se è necessario che n sia inserito numericamente esattamente, allora possiamo farlo:

sed, 274 byte

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

Produzione:

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

                  x
               xxx
              x
     xxxxxxxxx
    x
 xxx
x

$ 

7
Questo è davvero fantastico.
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

Versione del programma (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)

Il numero di x nella nriga 1 indicizzata è 3 alla potenza di (l'indice del primo bit impostato in n, a partire da lsb).


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)

Un approccio ricorsivo. La scala del diavolo $ n $ è divisa in tre parti

  • Il ramo ricorsivo sinistro, una scala di dimensioni n-1, la cui lunghezza è3**n - 2**n
  • La linea centrale di x', di lunghezza3**n
  • Il ramo ricorsivo giusto, una scala di dimensioni n-1, la cui lunghezza è3**n - 2**n

Si noti che la lunghezza totale delle tre parti è 3*(3**n) - 2*(2**n)o 3**(n+1) - 2**(n+1), il che conferma l'induzione.

La variabile opzionale smemorizza l'offset delle parti correnti che stiamo stampando. Prima riconduciamo al ramo sinistro con offset maggiore, quindi stampiamo la linea centrale, quindi eseguiamo il ramo destro sull'offset corrente.


6

CJam, 36 35 33 byte

Ecco un altro approccio di CJam (non ho esaminato il codice di Optimizer, quindi non so se in realtà è molto diverso):

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

Questo utilizza 0per la curva. In alternativa, (usando il trucco di grc)

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

quale usa x.

Provalo qui.

Spiegazione

L'idea di base è quella di formare prima un array con le righe, come

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

E poi per passare attraverso questo elenco, anteponendo la giusta quantità di spazi.

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.";

L'altra versione funziona in modo simile, ma crea una serie di lunghezze, come

[1 3 1 9 1 3 1]

E poi lo trasforma in stringhe di xs nella mappa finale.


6

Dyalog APL, 34 personaggi

Utilizzando l'approccio di grc. Disegna la scala con caratteri (domino) e accetta input dallo stdin. Questa soluzione presuppone ⎕IO←0.

' ⌹'[(∪∘.=⊖){⍵/⍳≢⍵}⊃(⊢,,)/3*⌽⍳1+⎕]
  • - accetta input da stdin.
  • ⌽⍳1+⎕- la sequenza dei numeri da giù a 0. (es. 3 2 1 0)
  • 3*⌽⍳1+⎕- tre alla potenza di quello (es. 27 9 3 1)
  • (⊢,,)/3*⌽⍳1+⎕- il risultato precedente piegato da destra dalla funzione tacita ⊢,,che è uguale al dfn che {⍵,⍺,⍵}fornisce le lunghezze del gradino della scala del diavolo secondo l'approccio di grc.
  • {⍵/⍳≢⍵}⊃(⊢,,)/3*⌽⍳1+⎕ le lunghezze dei passi convertite in passi.
  • (∪∘.=⊖){⍵/⍳≢⍵}⊃(⊢,,)/3*⌽⍳1+⎕che l'auto-classificata, come nel mio soluzione J . Si noti che già capovolge il risultato correttamente.
  • ' ⌹'[(∪∘.=⊖){⍵/⍳≢⍵}⊃(⊢,,)/3*⌽⍳1+⎕] i numeri sostituiti da spazi vuoti e domino.

4

Ruby, 99

Una risposta diversa alla mia altra, ispirata alla risposta di FUZxxl

FUZxxl nota che i numeri di x corrispondono al numero di fattori di 2 dell'indice. per esempio per n = 2 abbiamo la seguente fattorizzazione:

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

Uso un modo piuttosto più semplice di estrarre questi poteri di 2: i=m&-mche produce la sequenza 1 2 1 4 1 2 1ecc. Funziona come segue:

m-1è lo stesso dei msuoi bit più significativi, ma il bit di 1 meno significativo diventa uno zero e tutti gli zeri a destra diventano 1.

Per essere in grado di AND questo con l'originale, dobbiamo capovolgere i bit. Esistono vari modi per farlo. Un modo è sottrarlo -1.

La formula generale è quindi m& (-1 -(m-1)) che semplificam&(-m)

Esempio:

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

Ecco il codice: le nuove righe vengono contate, i rientri non sono necessari e quindi non contati, come l'altra mia risposta. È leggermente più lungo della mia altra risposta a causa della goffa conversione dalla base 2: 1 2 1 4 1 2 1 etcalla base 3: 1 3 1 9 1 3 1 etc(c'è un modo per evitarlo 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

Ruby, 140 99

Il mio secondo codice Ruby in assoluto e il mio primo uso non banale della lingua. I suggerimenti sono i benvenuti. Il conteggio dei byte esclude gli spazi iniziali per i rientri, ma include le nuove righe (sembra che la maggior parte delle nuove righe non possano essere eliminate a meno che non vengano sostituite da uno spazio almeno).

L'ingresso è tramite chiamata di funzione. L'output è una matrice di stringhe, che ruby ​​esegue il dump su stdout come un elenco separato da una nuova riga con un singolo puts.

L'algoritmo è semplicemente new iteration= previous iteration+ extra row of n**3 x's+ previous iteration. Tuttavia c'è un sacco una discreta quantità di codice solo per ottenere gli spazi iniziali nella giusta uscita.

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

Modifica: Ruby, 97

Questo utilizza l'approccio simile ma diverso di costruire una tabella numerica di tutti i numeri di x richiesti nell'array anel modo sopra descritto, ma successivamente costruendo una tabella di stringhe. La tabella delle stringhe è costruita all'indietro nell'array cusando il unshiftmetodo piuttosto strano per anteporre l'array esistente.

Attualmente questo approccio sembra migliore, ma solo di 2 byte :-)

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
È possibile sostituire for m in(0..n-1)do ... endcon n.times{|m|...}.
Omar,

@Omar Grazie, ci proverò domani. Non crederesti a quanti sforzi ci sono voluti per farlo funzionare a causa dei costanti errori di sintassi. Non sapevo come accedere alla variabile iterante n.timese lo ricorderò sicuramente. Elimina endanche un ! Tuttavia in questa occasione mi chiedevo se for m in (1..n)potesse essere migliore, per evitare il (m+1). C'è un modo più breve di scriverlo?
Level River St,

1
forè lungo principalmente perché sei costretto a usare end(puoi sostituirlo docon una nuova riga o con ;). Per 1..nte puoi usare 1.upto(n){|m|...}. Mi piace l'aspetto (1..n).each{|i|...}ma è leggermente più lungo dell'uso upto. E nota che iterando chiamando eacho uptonon è solo più breve, considera anche Ruby più idiomatico.
Omar,

@Grazie ancora 1.upto(n)! Con questo e alcune parentesi non necessarie, sono già sceso a 120. Penso che sotto 100 sia possibile, posterò il codice rivisto più tardi.
Level River St,

3

Haskell, 99 caratteri

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

La funzione è d:

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

Tutte queste parentesi! Non c'è davvero modo di spostarsi con meno?
FUZxxl,

È possibile perdere un byte scambiando le equazioni qe facendo q x=xin caso di elenco vuoto. Inoltre, sembra che le parentesi iterate...[1]non siano necessarie.
Zgarb,

3

PHP - 137 byte

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;}

Sto usando qui lo stesso trucco di GRC . Ecco la versione ungolfed:

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-> sembra PHP 5.6. Dovresti specificarlo. Questo è incompatibile con quasi tutte le installazioni di PHP. Per risparmiare qualche byte, dovresti iniziare con $r=str_repeat;e dove hai quella funzione, puoi sostituirlo con $r, salvandoti 2 byte. Inoltre, $r('x',$v)può essere $r(x,$v)e funzionerà bene (nota che ho già sostituito il nome della funzione con la variabile). Inoltre, credo che ++$i<=$npossa essere riscritto $n>++$irisparmiando un altro byte.
Ismael Miguel,

Ecco la tua funzione, con un piccolo trucco: 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;}(invece di avere quella brutta newline, ho aggiunto la sequenza di escape \rall'interno di una stringa tra virgolette doppie, con la variabile $oal suo interno. Quindi "\r$o"ha lo stesso conteggio byte di ''.$oquello, con newline ommited sull'ultimo e produce lo stesso risultato.
Ismael Miguel,

In realtà, la condizione di whiledeve essere $n>$i++perché questa riduzione funzioni correttamente.
Ismael Miguel,

@IsmaelMiguel PHP 5.6 è l'ultima versione di PHP, non devo aggiungere altro. Non è colpa mia se quasi tutti usano una versione precedente e se la maggioranza ne utilizza una obsoleta. Grazie per il $r=str_repeattrucco. Ci ho pensato solo $r='str_repeat';, che non stava salvando alcun byte. La costante indefinita è anche un buon trucco, ben fatto;). Una nuova riga è più piccola di un byte rispetto alla scrittura \n, quindi l'ho mantenuta, ma ho usato virgolette doppie per evitare una concatenazione $0. Grazie ancora !
Blackhole,

Ti starebbe solo bene. Se non ne fossi a conoscenza 3 ** $i, direi che hai una sintassi terribile. È possibile rivolgersi a tale correzione. Sto solo parlando di questo e non del [1]perché proveniente da PHP5.4, che è piuttosto "vecchio". 1 anno fa, ti chiederei di specificarlo. Oggi vi chiedo semplicemente di specificare (in una riga molto breve) che lo specifica. Parlando del codice, hai ancora il ++$i<=$nquale può essere sostituito $n>$i++. Ho dovuto convertire tutto il tuo codice in PHP5.3 per testarlo. Il che è stato doloroso. Ma vedo che finora hai mangiato 7 byte.
Ismael Miguel,

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');}}

Ecco lo stesso codice decompresso e leggermente ripulito:

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');
    }
}

Questo si basa sulla stessa idea della soluzione FUZxxl al problema, di utilizzare una forma esplicita piuttosto che implicita per le righe. La dichiarazione di j lo imposta su 2 ^ (n + 1), e il primo ciclo while calcola k = 3 ^ (n + 1); allora l = 3 ^ (n + 1) -2 ^ (n + 1) è la larghezza totale della scala (non è difficile da dimostrare). Quindi esaminiamo tutti i numeri da 1 a 2 ^ (n + 1) -1; per ognuno, se è divisibile per (esattamente) 2 ^ n, abbiamo in programma di stampare s = 3 ^ n 'X's. Sono regolato per essere sicuri di iniziare dal punto giusto: scriviamo gli spazi e le "X", quindi una nuova riga.


definire W in; while e omettere int per salvare alcuni caratteri.
FUZxxl,

anche t = l- = s per un certo risparmio.
FUZxxl,

@FUZxxl Ho provato entrambi, ma mentre C consente ancora tipi impliciti su funzioni, non li stava permettendo su dichiarazioni variabili anche con i flag 'classici' (almeno su GCC). E ho provato #define W; mentre e non sembrava curarmene, anche se potrei essere scivolato nella definizione.
Steven Stadnicki,

hm ... Penso che puoi solo omettere il tipo in una variabile globale. Non ti porta molto. Puoi provare ad aggiungere (*p)()=putchar;all'inizio per chiamare putcharcome p. Penso che dovrebbe funzionare.
FUZxxl,

2

CJam, 46 43 41 39 36 35 byte

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

AGGIORNA usando un approccio diverso ora.


Vecchio approccio:

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

Abbastanza ingenuo e lungo, ma qualcosa per iniziare.

Aggiungerò spiegazione una volta che lo golf.

Provalo online qui


Sembra aver bisogno di un po 'di lavoro. Non ha funzionato correttamente per n = 4, 5, 17. Visualizzate stringhe riffles di x visualizzate nella parte superiore. Con n = 17 ha scaricato il codice sullo schermo e riempito il fondo con le x.
DavidC,

1
@DavidCarraher Per 4, 5 Penso che sia solo il ritorno a capo. Se copi l'output in un editor di testo senza il ritorno a capo, mi sembra giusto.
Sp3000,

Ok. Lo so vedere.
DavidC,

2

Java, 271 269 ​​byte

Usa il metodo di 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;}

rientrato:

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;
}

Eventuali suggerimenti sono ben accetti

2 byte grazie a mbomb007


È possibile utilizzare b.size()>0invece di !b.isEmpty(), salvando 2 byte.
mbomb007,

1

Perl, 62

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

In primo luogo calcola il risultato in modo iterativo senza gli spazi iniziali. Quindi li aggiunge prima di ogni riga in base al numero di xcaratteri nel resto della stringa.


1

JavaScript (ES6) 104106 118

Modifica Rimossa la funzione ricorsiva, l'elenco di '*' per ogni riga viene ottenuto iterativamente, armeggiando con bit e potenze di 3 (come in molte altre risposte)
All'interno del ciclo, una stringa multilinea viene costruita dal basso verso l'alto, mantenendo un conteggio progressivo di spazi iniziali da aggiungere su ogni riga

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
}

Primo tentativo rimosso

La funzione ricorsiva R crea un array con il numero di '*' per ogni riga. Ad esempio R (2) è [1, 3, 1, 9, 1, 3, 1]
Questo array viene scansionato per creare una stringa multilinea dal basso verso l'alto, mantenendo un conteggio corrente degli spazi iniziali da aggiungere su ogni riga

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 

Test nella console di Firefox / FireBug

F(3)

Produzione

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

1

R - 111 caratteri

Implementazione semplice, costruendo l'array in modo iterativo e distruggendolo lentamente.

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]}

Uso:

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

Bene, ho modificato il mio codice in modo che prenda l' nargomento dalla riga di comando
koekenbakker,

1
Si salva 8 byte leggendo da STDIN. n=scan().
Alex A.

Non è necessario dichiarare xdi usarlo come cursore, né è necessario if(n). Inoltre, le interruzioni di riga contano come un personaggio penso.
freekvd,

Grazie, hai ragione x. Non sono sicuro if(n)però. Ho aggiunto quella parte per trattare il caso n=0. L' if(n)poi ritorna Fe quindi restituisce una singola x. Se lo rimuovo, n=0dà risultati indesiderati. Nuovo qui, quindi non sapevo delle interruzioni di riga. Incluso ora!
koekenbakker,

Se imposti a=0e avvii il ciclo x in 0:n, funziona anche per n = 0. Quindi puoi omettere il if(n).
freekvd,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.