Stampa un set Cantor


19

La sfida

Costruire un N-livellato Cantor Set .

Il set ternario Cantor viene creato eliminando ripetutamente i terzi medi aperti di un set di segmenti di linea.

Il programma riceve un parametro N(un numero intero) e quindi stampa (in console o in modo simile) un Cantor Set di N livelli. La stampa può contenere solo caratteri undescore ( _) e spazi bianchi. Il parametro può essere positivo o negativo e il segno indica l'orientamento della costruzione del set di cantori: se N > 0il set di cantori è costruito verso il basso e se N < 0il set di cantori è costruito verso l'alto. In N = 0tal caso, il programma stampa una riga singola ( _).

Per esempio:

N = 2

_________
___   ___
_ _   _ _

N = -2

_ _   _ _
___   ___
_________

N = 3

___________________________
_________         _________
___   ___         ___   ___
_ _   _ _         _ _   _ _

N = -3

_ _   _ _         _ _   _ _
___   ___         ___   ___
_________         _________
___________________________

Criteri vincenti

Poiché si tratta di una sfida di golf del codice, vince il codice più corto.

Modificato: modifica 0 input dal suggerimento di ugoren.


Perché non stampare nulla quando N = 0? Questo rende 0 un caso speciale e rende più difficile usare la ricorsione. La gestione generale sarebbe quella di stampare un singolo _(ma stamparlo verso il basso quando si ottiene -0).
ugoren,

Giusto. Ho già modificato le specifiche.
Averroè il

Risposte:


10

GolfScript, 49 42 40 caratteri

~.abs.3\?'_'*\{.3%..,' '*\++}*](0>2*(%n*

Con grazie a Hammar per 42-> 40.

Il mio miglior tentativo ancora per un approccio più teorico ai numeri è purtroppo molto più lungo:

~.abs:^3\?,{3^)?+3base(;1+1?.'_'*^@-)' '*+}%zip\0>2*(%n*

o

~.abs 3\?:^,{6^*+3base.1+1?.('_'*@,@-' '*+}%zip\0>2*(%n*

e sospetto che la lunghezza di basee ziprenderà impossibile raggiungerlo.


~.abs.@/\.3\?'_'*\{.3%..,' '*\++}*](%n*è di 39 caratteri, ma si blocca sull'input 0. :-(
Ilmari Karonen,

@IlmariKaronen, sì, la divisione per zero è stata una seccatura per l'implementazione in C che ho scritto, perché significava che non puoi fare n/abs(n)per ottenerla signum(n).
Peter Taylor,

6

Python, 116 113 104 103 caratteri

n=input()
d=n>0 or-1
for i in range(n*d+1)[::d]:
 s='_'*3**i
 while i<n*d:s+=len(s)*' '+s;i+=1
 print s

Algoritmo precedente superato a 113 caratteri

r=input()
u='_'
l=[u]
for _ in abs(r)*u:o=len(l[0]);l=[s+o*' '+s for s in l]+[u*o*3]
print'\n'.join(l[::r>0 or-1])

5

Rubino (97)

Basato sulla versione pitone di Steven Rumbalski:

n,r=$*[0].to_i,[?_]
n.abs.times{z=r[0].size;r=r.map{|s|s+' '*z+s}+[?_*z*3]}
puts n<0?r:r.reverse

Tentativi precedenti, entrambi della stessa lunghezza (112)

Crea linee da parti:

c=->x,n{n<1??_*x :(z=c[s=x/3,n-1])+' '*s+z}
r=(0..m=(n=$*[0].to_i).abs).map{|i|c[3**m,i]}
puts n<0?r.reverse: r

Inizia con una riga, crea dei buchi:

r=[?_*3**a=(n=$*[0].to_i).abs]
a.times{|c|r<<r[-1].gsub((x=?_*o=3**(a-c-1))*3,x+' '*o+x)}
puts n<0?r.reverse: r

3

Perl, 93 caratteri

@x=($t=$x=_ x 3**($a=abs($n=<>)),map$x.=$"x($x=~s/(.)../$1/g).$x,1..$a);say for$n<0?sort@x:@x

Ho pensato di provare a vedere come la soluzione GolfScript di Peter Taylor avrebbe portato su Perl. Le caratteristiche degne di nota includono l'uso di sortinvece di reversesalvare tre caratteri, usando il fatto che uno spazio ordina prima _.


2

Lisp comune, 217 210 caratteri

(defun m(x)(flet((c(n v)(if(= n 0)`((,v))(cons(substitute v nil(make-list(expt 3 n)))(mapcar #'append(c(1- n)v)(c(1- n)" ")(c(1- n)v))))))(format t "~{~{~a~}~%~}"(let((r(c(abs x)'_)))(if(< x 1)(reverse r)r)))))

Allargato:

(defun m(x)
  (flet((c(n v)
    (if(= n 0)
       `((,v))
       (cons(substitute v nil(make-list(expt 3 n)))
            (mapcar #'append
                    (c(1- n)v)
                    (c(1- n)" ")
                    (c(1- n)v))))))
   (format t "~{~{~a~}~%~}"(let((r(c(abs x)'_)))(if(< x 1)(reverse r)r)))))

Immagino che se il codice Lisp riesce a battere qualsiasi conteggio iniziale per un'altra lingua (C, 219) Sto andando bene :)


2

C ( 163 161 caratteri)

i,l,N;f(n,m,s){if(n){s=--n<l?m:s;f(n,m,s);f(n,s,s);f(n,m,s);}else
putchar(m);}main(n,v)int**v;{for(i=N=abs(n=atoi(1[v]));i+1;i--)l=n<N?N-i:i,f(N,95,32),f(0,10);}

Prende in prestito un paio di trucchi dalla risposta di Ugoren , ma la logica di base è abbastanza diversa. Non ho potuto seguire il suo ciclo for, quindi potrebbe essere possibile ibridare e salvarne un altro.


2

C, 219 193 179 143 136 131 caratteri

Ho seguito un'altra delle idee di Petyer Taylor, oltre a un mio miglioramento, ne ho salvate altre 6.
Integrati alcuni suggerimenti di @PeterTaylor, oltre a aver copiato la sua funzione principale, con lievi modifiche, che salvano un personaggio (è giusto copiarlo? Dal momento che nessuno di noi vincerà questo, immagino non sia poi così male).
Ho pensato a un miglioramento significativo nel modo in cui funziona la mia ricorsione e, dopo aver visto la risposta di Peter Taylor, l'ho implementata per riconquistare il comando. Quando ho letto di nuovo la sua risposta, ho visto che ho fatto quasi esattamente quello che ha fatto. Quindi questa sembra l'ibridazione che ha suggerito.
Inoltre ha semplificato il loop in main, mantenendo la stessa lunghezza.
E ha preso il trucco di Peter per stampare newline, invece di puts("")- salva un personaggio.

Rimosso intdalla dichiarazione delle variabili - un avvertimento, ma salva 4 caratteri.
Il nuovo algoritmo non calcola 3 ^ x in anticipo, ma utilizza un singolo ciclo per stampare 3 ^ x caratteri.
Puoi salvarne un altro definendolo int*v, ma a 64 bit non funzionerà.
Il conteggio dei caratteri esclude gli spazi bianchi (che possono essere rimossi).

o,i,n;
p(c) {
    n-- ?
        p(c),p(o>n?c:32),p(c)
    :
        putchar(c);
    n++;
}
main(c,v)int**v; {
    for(n=abs(c=atoi(v[1]));i<=n;i++)o=c+n?n-i:i,p(95),puts("");
}

Algoritmo precedente, 219 caratteri:

p(l,o,i,m,c,j) {
    for(;i<(m=l);i++)
        for(j=0,c=95;m/o||!putchar(c);j++)
            i/m%3-1||(c=32),m/=3;
    puts("");
}
main(c,v,n,i,l,o)int**v;{
    (n=atoi(v[1]))<0?n=-n:(c=0);
    for(i=n,l=1;i;i--)l*=3;
    o=c?1:l;
    for (;i<=n;i++)p(l,o,0),c?o*=3:(o/=3);
}

@PeterTaylor, non riesco a rimuovere il iparametro, perché l'uso del globale interferirebbe main. l--interferirà con o>=l, e dovrò sostituirlo con >(quindi perché lo scrivo come se fosse una brutta cosa?) Potrei anche copiarti main, che è più semplice e più corto del mio.
ugoren,

@PeterTaylor, avevi ragione i, mi mancava il fatto che davvero non lo uso più (pensavo volessi dire che non lo passo).
ugoren,

A proposito, non mi dispiace che tu abbia assunto la mia funzione principale. La mia regola empirica è che copiare la soluzione di qualcun altro per cambiare un singolo personaggio è eccessivamente aggressivo, copiare la soluzione di qualcun altro per riscriverne metà è perfettamente equo, e c'è una zona grigia nel mezzo. Forse dovremmo cercare di concordare alcuni standard della community su meta.
Peter Taylor,

@PeterTaylor, penso che abbiamo raggiunto una sorta di stallo. Il mio psembra abbastanza ottimale ora, e il tuo è mainstato migliore (non sono sicuro che sia ottimale, ma non posso migliorarlo ulteriormente). Quindi, fatta eccezione per una nuova ingegnosa struttura di programma, l'unica strada da percorrere è stata la copia del codice dell'altro.
ugoren,

A proposito, come stai contando i tuoi personaggi? Perché realizzo la tua ultima versione 138 caratteri, non 136.
Peter Taylor,

2

J, 44 39 38 37 byte

' _'{~0&>_&(]|.)(,:1)1&(,],.0&*,.])~|

Utilizza l'iterazione per creare il set successivo che inizia _inizialmente con 1 (che rappresenta ).

uso

   f =: ' _'{~0&>_&(]|.)(,:1)1&(,],.0&*,.])~|
   f 0
_
   f 1
___
_ _
   f _1
_ _
___
   f 2
_________
___   ___
_ _   _ _
   f _2
_ _   _ _
___   ___
_________
   f 3
___________________________
_________         _________
___   ___         ___   ___
_ _   _ _         _ _   _ _
   f _3
_ _   _ _         _ _   _ _
___   ___         ___   ___
_________         _________
___________________________

Spiegazione

' _'{~0&>_&(]|.)(,:1)1&(,],.0&*,.])~|  Input: integer n
                                    |  Absolute value of n
                (,:1)                  The array [1]
                     1&(          )~   Repeat abs(n) times starting with x = [1]
                                 ]       Identity function, gets x
                            0&*          Multiply x by 0
                               ,.        Join the rows together
                         ]               Identity function, gets x
                          ,.             Join the rows together
                     1  ,                Prepend a row of 1's and return
      0&>                              Test if n is negative, 1 if true else 0
         _&(   )                       If n is negative
             |.                          Reverse the previous result
            ]                            Return that
                                       Else pass the previous result unmodified
' _'                                   The string ' _'
    {~                                 Select from the string using the result
                                       as indices and return

Bello! Non ho provato personalmente, ma adoro usare l'agenda @.: forse, in combinazione $:, potrebbe essere di qualche utilità qui? Ad esempio qualcosa del genere (zero case)`(positive case)`(negative case)@.*, o forse forse ":@_:`(positive case)`(|."1@$:)@.*.
Conor O'Brien,

Non ho provato una soluzione ricorsiva, ma potrei provarla.
miglia

2

R , 141 139 137 byte

m=abs(n<-scan());write("if"(n<m,rev,c)(c(" ","_")[Reduce(`%x%`,rep(list(matrix(c(1,1,1,1,0,1),3)),m),t(1))[,1+2^m-2^(m:0)]+1]),1,3^m,,"")

Provalo online!

-15 byte grazie anche all'uso di Giuseppe '('come funzione di identità; writeanziché catstampare l'output; uso intelligente di %x%.

-2 byte grazie a Kirill L. usando cinvece '('come funzione di identità.


un prodotto Kronecker potrebbe funzionare qui? %x%? Potrebbero esserci dei problemi nel prendere file alternate forse ...
Giuseppe,

@Giuseppe ci ho provato, basandomi sulla tua risposta "Crea una" H "da una" H "più piccola ... Ci proverò ancora.
JayCe,

Ah, quindi sei stato tu a votarlo. questa è l'unica ragione per cui ho pensato kronanche io ! Immagino che questo dovrebbe essere in grado di scendere a 125 byte se riusciamo a trovare l'approccio giusto.
Giuseppe,

puoi usare `(`come funzione di identità in modo da poter usare writedirettamente invece di cate un forciclo. 141 byte
Giuseppe,

@Giuseppe Non avevo idea che (potesse essere usato in questo modo, o che if potesse essere usato per selezionare tra due funzioni. E inizierò a usare write ... salva un sacco di "\ n".
JayCe,

1

Python, 177 164 caratteri

N=input()
n=abs(N)
c=lambda x:0if x<1 else x%3==1or c(x/3)
r=["".join([["_"," "][c(x/3**i)]for x in range(3**n)])for i in range(n+1)]
print"\n".join(r[::N>0 or-1])

Dato che stai usando Python 2 non è necessario trasmettere i risultati di inputas int. Le tue ultime due righe potrebbero essere abbreviate inprint"\n".join(r[::N>0 or-1])
Steven Rumbalski,

@Steven ho apportato modifiche. Grazie.
Ante

1

Perl, 113 caratteri

$i=abs($I=<>);@w=$_='_'x3**$i;while($i--){$x=3**$i;s/(__){$x}/'_'x$x.' 'x$x/eg;push@w,$_}say for$I>0?reverse@w:@w

Allargato:

$i=abs($I=<>);
@w=$_='_'x3**$i;
while($i--){
    $x=3**$i;
    s/(__){$x}/'_'x$x.' 'x$x/eg;
    push@w,$_
}
say for$I>0?reverse@w:@w

1

JavaScript 121 byte

Funzione ricorsiva interna, quindi occuparsi dell'output all'indietro, se necessario

n=>(f=(n,t=n&&f(n-1),r=t[0])=>n?[r+r+r,...t.map(x=>x+t[n]+x)]:['_',' '],f=f(n<0?-n:n),f.pop(),n<0?f.reverse():f).join`\n`

Meno golf

n=>{
  var f = n => { // recursive function
    var t = n && f(n-1), r = t[0]
    return n 
      ? [r+r+r, ...t.map(x => x+t[n]+x)]
      : ['_',' ']
  };
  f = f(n < 0 ? -n : n);
  f.pop(); // last row is all blanks
  if (n<0) f.reverse();
  return f.join`\n`
}

Test

var F=
n=>(f=(n,t=n&&f(n-1),r=t[0])=>n?[r+r+r,...t.map(x=>x+t[n]+x)]:['_',' '],f=f(n<0?-n:n),f.pop(),n<0?f.reverse():f).join`\n`

function go()
{
  var n=+I.value
  O.textContent = F(n)
}

go()
<input id=I type=number value=3 oninput='go()'>
<pre id=O></pre>


1

Lotto, 265 262 242 236 235 byte

@echo off
set/pn=
set c=%n%,-1,0
if %n% lss 0 set c=0,1,%n:-=%
for /l %%i in (%c%)do call:l %%i
exit/b
:l
set s=_
for /l %%j in (1,1,%n:-=%)do call:m %1 %%j
echo %s%
:m
set t=%s%
if %1 lss +%2 set t=%s:_= %
set s=%s%%t%%s%

Modifica: salvato 12 19 byte grazie a @ l4m2. Salvato 8 byte rimuovendo la %a%variabile non necessaria .


Questo per 247 byte.
Conor O'Brien,

@ ConorO'Brien Ricordati che sarebbe 261 se avessi contato tutti i CR e gli LF (che sono sicuro che non sei obbligato a fare ma sono pigro in quel modo).
Neil,

Quindi non stai rimuovendo CR dal tuo codice? Anche se non è richiesto dai file .BAT e comunque rimosso da SE? : P
Conor O'Brien,

@ ConorO'Brien È una penalità che accetto di usare Blocco note per scrivere file batch.
Neil,

Sai fare qualcosa del genere set c=%n%,-1,0 [LF] if %n% lss 0 set c=0,1,%a% [LF] for /l %%i in (%c%)do call:l %%i?
l4m2



0

Prolog (SWI) , 265 232 213 byte

S-E-R:-between(S,E,R).
[]/R/R.
[H|T]/B/R:-T/[H,32,H|B]/R.
N+R:-(N>0->O is N-1,O+S,S/[]/R;R=`_`).
N*[H|T]:-1-N-_,writef("%n",[H]);N*T.
_*[]:-nl.
-N:-(0-N-J,K is N-J;N-0-I,J is -I,K is I-N),L is 3^K,J+R,L*R,1=0;1=1.

Provalo online!


0

PowerShell , 111 byte

filter f{if($s=[math]::Sign($_)){($x=$_-$s|f|%{$_+' '*($l=$_|% Le*)+$_})|?{$s-1};'_'*3*$l;$x|?{$s+1}}else{'_'}}

Provalo online!

Meno golf:

filter f{
    if($sign=[math]::Sign($_)){
        $x=$_-$sign|f|%{
            $_+' '*($length=$_|% Length)+$_
        }
        $x|?{$sign-1}  # output $x if $_ is negative
        '_'*3*$length
        $x|?{$sign+1}  # output $x if $_ is positive
    }
    else{
        '_'
    }
}
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.