Imprimir um conjunto de cantores

19

O desafio

Construir uma N-nivelado Cantor Set .

O conjunto ternário Cantor é criado excluindo repetidamente os terços médios abertos de um conjunto de segmentos de linha.

O programa recebe um parâmetro N(um número inteiro) e depois imprime (no console ou de maneira semelhante) um conjunto de N níveis Cantor. A impressão pode conter apenas caracteres de undescore ( _) e com espaços. O parâmetro pode ser positivo ou negativo e o sinal indica a orientação de construção do conjunto de cantores: se N > 0o conjunto de cantores for construído para baixo e se N < 0o conjunto de cantores for construído para cima. Se N = 0então, o programa imprime uma única linha ( _).

Por exemplo:

N = 2

_________
___   ___
_ _   _ _

N = -2

_ _   _ _
___   ___
_________

N = 3

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

N = -3

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

Critérios de vitória

Como é um desafio de código de golfe, o código mais curto vence.

Editado: Modifique 0 entrada por sugestão de ugoren.

Averroes
fonte
Por que imprimir nada quando N = 0? Isso torna 0 um caso especial e dificulta o uso da recursão. O manuseio geral seria imprimir um único _(mas imprimi-lo para baixo ao obter -0).
ugoren
Certo. Eu já modifiquei as especificações.
Averroes

Respostas:

10

GolfScript, 49 42 40 caracteres

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

Com agradecimentos a hammar por 42-> 40.

Infelizmente, minha melhor tentativa de uma abordagem mais teórica dos números é muito mais longa:

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

ou

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

e desconfio que o tamanho basee zipo impossibilitem de alcançar.

Peter Taylor
fonte
~.abs.@/\.3\?'_'*\{.3%..,' '*\++}*](%n*tem 39 caracteres, mas trava na entrada 0. :-(
Ilmari Karonen
@IlmariKaronen, sim, a divisão por zero foi uma dor para a implementação C que eu escrevi também, porque significava que você não pode fazer n/abs(n)isso signum(n).
22413 Peter Peter
6

Python, 116 113 104 103 caracteres

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 mais antigo com 113 caracteres

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])
Steven Rumbalski
fonte
5

Rubi (97)

Baseado na versão python de 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

Tentativas anteriores, com o mesmo comprimento (112)

Crie linhas a partir de peças:

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

Comece com uma linha, faça furos nela:

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
jsvnm
fonte
3

Perl, 93 caracteres

@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

Pensei em tentar ver como a solução GolfScript de Peter Taylor seria portada para Perl. Recursos notáveis ​​incluem o uso de em sortvez de reversesalvar três caracteres, usando o fato de que um espaço é classificado anteriormente _.

Ilmari Karonen
fonte
2

Lisp comum, 217 210 caracteres

(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)))))

Expandido:

(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)))))

Eu acho que se o código Lisp conseguir superar qualquer contagem inicial para outro idioma (C, 219), estou indo bem :)

Paul Richter
fonte
2

C ( 163 161 caracteres)

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

Empresta alguns truques da resposta de ugoren , mas a lógica principal é bem diferente. Não consegui seguir o loop for dele, portanto, é possível hibridar e economizar um pouco mais.

Peter Taylor
fonte
2

C, 219 193 179 143 136 131 caracteres

Segui outra das idéias de Petyer Taylor, além de uma melhoria minha, economizando mais 6.
Integrou algumas dicas do @PeterTaylor, além de copiar sua função principal, com pequenas alterações, que salvam um personagem (é justo copiá-lo? Como nenhum de nós vencerá esse, acho que não é tão ruim).
Pensei em uma melhoria significativa em como minha recursão funciona e, depois de ver a resposta de Peter Taylor, implementei-a para recuperar a liderança. Ao ler sua resposta novamente, vi que fiz quase exatamente o que ele fez. Então isso parece a hibridização que ele sugeriu.
Também simplificou o loop main, mantendo o mesmo comprimento.
E levou o truque de Peter para imprimir nova linha, em vez de puts("")- salva um personagem.

Removido intda declaração da variável - um aviso, mas salva 4 caracteres.
O novo algoritmo não calcula 3 ^ x antecipadamente, mas usa um único loop para imprimir 3 ^ x caracteres.
Pode salvar mais um definindo int*v, mas 64 bits não funcionará.
A contagem de caracteres exclui o espaço em branco (que pode ser removido).

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 mais antigo, 219 caracteres:

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);
}
Ugoren
fonte
@ PeterTaylor, não consigo remover o iparâmetro, porque o uso global interferiria main. l--interferirá o>=le terei de substituí-lo por >(por que o escrevo como se fosse uma coisa ruim?) Também poderia copiar você main, que é mais simples e mais curto que o meu.
ugoren
@ PeterTaylor, você estava certo i- eu perdi o fato de que eu realmente não o uso mais (pensei que você quis dizer que não passo).
precisa saber é o seguinte
A propósito, não me importo que você assuma minha função principal. Minha regra geral é que copiar a solução de outra pessoa para alterar um único personagem é excessivamente agressivo, copiar a solução de outra pessoa para reescrever metade dela é perfeitamente justo, e há uma área cinzenta no meio. Talvez devêssemos tentar concordar com alguns padrões da comunidade sobre a meta.
31568 Peter
@ Peter Taylor, acho que chegamos a uma espécie de impasse. Meu pparece ótimo agora e o seu mainfoi melhor (não tenho certeza de que é ótimo, mas não posso melhorá-lo ainda mais). Portanto, exceto por uma nova estrutura de programa engenhosa, o único caminho a seguir era copiarmos o código do outro.
ugoren
BTW Como você está contando seus personagens? Porque eu fazer suas últimas versão 138 caracteres, não 136.
Peter Taylor
2

J, 44 39 38 37 bytes

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

Usa a iteração para criar o próximo conjunto começando com 1 (representando _) inicialmente.

Uso

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

Explicação

' _'{~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
milhas
fonte
Agradável! Eu não tentei pessoalmente, mas adoro usar a agenda - @.talvez, combinada com $:, possa ser útil aqui? Por exemplo, algo como (zero case)`(positive case)`(negative case)@.*, ou mesmo talvez ":@_:`(positive case)`(|."1@$:)@.*.
Conor O'Brien
Não tentei uma solução recursiva, mas poderia tentar.
miles
2

R , 141 139137 bytes

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,,"")

Experimente online!

-15 bytes também graças ao uso de Giuseppe '('como função de identidade; writeem vez de catimprimir a saída; uso inteligente de %x%.

-2 bytes graças a Kirill L. usando em cvez de '('como a função de identidade.

JayCe
fonte
um produto Kronecker poderia funcionar aqui? %x%? Pode haver alguns problemas com a tomada de linhas alternadas talvez ...
Giuseppe
@ Giuseppe Eu tentei, baseando-me na resposta "Crie um" H "a partir de" H "menores" ... Vou tentar outra vez.
JayCe 23/05
Ah, então foi você quem votou nisso. essa é a única razão pela qual pensei krontambém! Eu imagino que isso possa diminuir para 125 bytes, se conseguirmos encontrar a abordagem correta.
Giuseppe
você pode usar `(`como função de identidade para poder usar writediretamente em vez de cate um forloop. 141 bytes
Giuseppe
@ Giuseppe Eu não tinha ideia de que (poderia ser usado dessa maneira, ou que if poderia ser usado para selecionar duas funções. E começarei a usar a gravação ... economiza muito "\ n".
21418 JayCe
1

Python, 177 164 caracteres

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])
Ante
fonte
Como você está usando o Python 2, não precisa converter os resultados de inputcomo int. Suas duas últimas linhas poderia ser reduzido paraprint"\n".join(r[::N>0 or-1])
Steven Rumbalski
@Steven eu fiz alterações. Obrigado.
Ante
1

Perl, 113 caracteres

$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

Expandido:

$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
Toto
fonte
1

JavaScript 121 bytes

Função recursiva interna e, em seguida, cuide da saída para trás, se necessário

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`

Menos golfe

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

Teste

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>

edc65
fonte
1

Lote, 265 262 242 236 235 bytes

@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%

Edit: Salvo 12 19 bytes graças a @ l4m2. Economizou 8 bytes removendo a %a%variável desnecessária .

Neil
fonte
Isso por 247 bytes.
Conor O'Brien
@ ConorO'Brien Lembre-se de que seria 261 se eu contasse todos os CRs e os LFs (o que tenho certeza de que você não é obrigado a fazer, mas sou preguiçoso assim).
Neil
Então você não está removendo os CRs do seu código? Mesmo que não seja exigido por arquivos .BAT e despojado pelo SE de qualquer maneira? : P
Conor O'Brien
@ ConorO'Brien É uma penalidade que eu aceito usar o Bloco de Notas para gravar arquivos em Lote.
Neil
Você pode fazer algo assim 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

JavaScript (Node.js) , 148 bytes

n=>f=(L=n<0&&n,R=n>0&&n)=>[...Array(r=3**(n>0?n:-n))].map(_=>((j++).toString(3)+1).indexOf(1)>(L>0?L:-L)?'_':' ',j=r+r).join``+`
${L++<R?f(L,R):''}`

Experimente online!

l4m2
fonte
0

Python 2 , 102 bytes

lambda n:'\n'.join(eval("[i+' '*len(i)+i for i in"*abs(n)+"'_'"+"]+['___'*len(i)]"*abs(n))[::n<1or-1])

Experimente online!

Erik, o Outgolfer
fonte
0

Prolog (SWI) , 265 232 213 bytes

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.

Experimente online!

Somente ASCII
fonte
0

PowerShell , 111 bytes

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

Experimente online!

Menos golfe:

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{
        '_'
    }
}
confuso
fonte