Wydrukuj zestaw kantora

19

Wyzwanie

Zbuduj zestaw Cantor N-Leveled .

Zestaw trójskładnikowy Cantora jest tworzony przez wielokrotne usuwanie otwartych środkowych trzecich zbioru segmentów linii.

Program otrzymuje jeden parametr N(liczbę całkowitą), a następnie drukuje (w konsoli lub w podobny sposób) zestaw Cantor N poziomów. Wydruk może zawierać tylko znaki undescore ( _) i spacje. Parametr może być dodatni lub ujemny, a znak wskazuje orientację konstrukcyjną zestawu kantora: jeśli N > 0zestaw kantora jest konstruowany w dół, a N < 0zestaw kantora jest konstruowany w górę. Jeśli N = 0następnie program wypisze jedną linię ( _).

Na przykład:

N = 2

_________
___   ___
_ _   _ _

N = -2

_ _   _ _
___   ___
_________

N = 3

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

N = -3

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

Kryteria wygranej

Ponieważ jest to wyzwanie dla golfa, wygrywa najkrótszy kod.

Edytowano: Zmodyfikuj 0 danych według sugestii ugorena.

Averroes
źródło
Po co drukować nic, gdy N = 0? To sprawia, że ​​0 jest szczególnym przypadkiem i utrudnia użycie rekurencji. Ogólną obsługą byłoby wydrukowanie jednego _(ale wydrukowanie go w dół po uzyskaniu -0).
ugoren 30.01.12
Dobrze. Już zmodyfikowałem specyfikacje.
Averroes,

Odpowiedzi:

10

GolfScript, 49 42 40 znaków

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

Dzięki dzięki Hammar za 42-> 40.

Moja najlepsza próba jak dotąd podejścia bardziej liczbowego jest niestety znacznie dłuższa:

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

lub

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

i podejrzewam, że długość basei zipuniemożliwi nadrobienie zaległości.

Peter Taylor
źródło
~.abs.@/\.3\?'_'*\{.3%..,' '*\++}*](%n*ma 39 znaków, ale ulega awarii na wejściu 0. :-(
Ilmari Karonen
@IlmariKaronen tak, dzielenie przez zero było uciążliwe dla realizacji C napisałem też, bo to oznaczało, że nie można zrobić n/abs(n), aby dostać signum(n).
Peter Taylor
6

Python, 116 113 104 103 znaków

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

Starszy algorytm został uzupełniony o 113 znaków

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
źródło
5

Rubin (97)

Na podstawie pythonowej wersji Stevena Rumbalskiego:

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

Poprzednie próby, obie o tej samej długości (112)

Buduj linie z części:

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

Zacznij od jednej linii, zrób w niej dziury:

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
źródło
3

Perl, 93 znaki

@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

Pomyślałem, że postaram się sprawdzić, jak dobrze rozwiązanie GolfScript Petera Taylora przenosi się na Perla. Godne uwagi funkcje obejmują użycie sortzamiast reversedo zapisywania trzech znaków, wykorzystując fakt, że spacja sortuje się wcześniej _.

Ilmari Karonen
źródło
2

Common Lisp, 217 210 znaków

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

Rozszerzony:

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

Domyślam się, że kodowi Lisp uda się pobić jakąkolwiek początkową liczbę dla innego języka (C, 219) Mam się dobrze :)

Paul Richter
źródło
2

C ( 163161 znaków)

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

Pożycza kilka sztuczek od odpowiedzi ugorena , ale podstawowa logika jest zupełnie inna. Nie mogłem śledzić jego pętli for, więc może być możliwe hybrydyzacja i uratowanie kilku innych.

Peter Taylor
źródło
2

C, 219 193 179 143 136 131 znaków

Podążyłem za kolejnymi pomysłami Petyera Taylora, a także ulepszeniem własnym, zaoszczędziłem jeszcze 6.
Zintegrowałem kilka wskazówek od @PeterTaylor, a także skopiowałem jego główną funkcję, z niewielkimi zmianami, które ratują postać (czy to w porządku, aby ją skopiować? Ponieważ żadne z nas nie wygra tej, myślę, że nie jest tak źle).
Pomyślałem o znacznej poprawie działania mojej rekurencji i po zobaczeniu odpowiedzi Petera Taylora wdrożyłem ją, aby odzyskać prowadzenie. Po ponownym przeczytaniu jego odpowiedzi zobaczyłem, że zrobiłem prawie dokładnie to, co on. Wygląda to na sugerowaną przez niego hybrydyzację.
Uprościłem również pętlę main, zachowując tę ​​samą długość.
I wziął sztuczkę Petera, aby wydrukować nowy wiersz, zamiast puts("")- ratuje postać.

Usunięto intz deklaracji zmiennej - ostrzeżenie, ale zapisuje 4 znaki.
Nowy algorytm nie oblicza z góry 3 ^ x, ale używa pojedynczej pętli do drukowania 3 ^ x znaków.
Można zapisać jeszcze jeden, definiując int*v, ale wtedy 64-bitowy nie będzie działać.
Liczba znaków wyklucza białe znaki (które można usunąć).

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

Starszy algorytm, 219 znaków:

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
źródło
@PeterTaylor, nie mogę usunąć iparametru, ponieważ użycie globalnego zakłóciłoby działanie main. l--będę się wtrącać o>=li będę musiał go zastąpić >(więc dlaczego piszę to tak, jakby to coś złego?) Mógłbym również skopiować cię main, co jest prostsze i krótsze niż moje.
ugoren
@PeterTaylor, miałeś rację i- przegapiłem fakt, że tak naprawdę już go nie używam (myślałem, że masz na myśli, że go nie zaliczam).
ugoren
Nawiasem mówiąc, nie mam nic przeciwko, że przejmiesz moją główną funkcję. Moja ogólna zasada polega na tym, że kopiowanie czyjegoś rozwiązania zmiany pojedynczej postaci jest zbyt agresywne, kopiowanie czyjś rozwiązania, aby przepisać połowę z nich, jest całkowicie sprawiedliwe, a pomiędzy nimi jest szara strefa. Być może powinniśmy spróbować uzgodnić niektóre standardy społeczności dotyczące meta.
Peter Taylor
@PeterTaylor, myślę, że osiągnęliśmy rodzaj impasu. Mój pwydaje się teraz całkiem optymalny, a twój mainbył lepszy (nie jestem pewien, czy jest optymalny, ale nie mogę go dalej poprawić). Więc oprócz nowej genialnej struktury programu, jedyną drogą było kopiowanie kodu drugiej osoby.
ugoren
BTW Jak liczysz swoje postacie? Ponieważ tworzę twoją najnowszą wersję 138 znaków, a nie 136.
Peter Taylor
2

J, 44 39 38 37 bajtów

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

Używa iteracji do zbudowania następnego zestawu, zaczynając od 1 (reprezentującego _) na początku.

Stosowanie

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

Wyjaśnienie

' _'{~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
mile
źródło
Ładny! Nie próbowałem osobiście, ale uwielbiam korzystać z agendy - @.może w połączeniu z nią $:może się tu przydać ? Np. Coś (zero case)`(positive case)`(negative case)@.*, a może nawet ":@_:`(positive case)`(|."1@$:)@.*.
Conor O'Brien,
Nie próbowałem rozwiązania rekurencyjnego, ale mogłem spróbować.
mile
2

R , 141 139 137 bajtów

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

Wypróbuj online!

-15 bajtów, dzięki Giuseppe '('jako funkcji tożsamości; writezamiast catwydrukować; sprytne użycie %x%.

-2 bajty dzięki Kirill L. przy użyciu czamiast '('jako funkcji tożsamości.

JayCe
źródło
czy mógłby tu działać produkt Kronecker? %x%? Mogą występować problemy z przyjmowaniem naprzemiennych wierszy ...
Giuseppe,
@Giuseppe Próbowałem, bazując na Twojej odpowiedzi „Utwórz literę„ H ”na podstawie mniejszej odpowiedzi„ H ”… Spróbuję jeszcze raz.
JayCe
Ach, więc to wy głosowaliście. to jedyny powód, dla którego też myślałem kron! Wyobrażam sobie, że powinno to być w stanie obniżyć się do 125 bajtów, jeśli znajdziemy właściwe podejście.
Giuseppe
możesz użyć `(`jako funkcji tożsamości, dzięki czemu możesz użyć writebezpośrednio zamiast cati forpętli. 141 bajtów
Giuseppe
@Giuseppe Nie miałem pojęcia, że (można go użyć w ten sposób lub że if można go użyć do wyboru jednej z dwóch funkcji. I zacznę używać zapisu ... zapisuje dużo „\ n”.
JayCe
1

Python, 177 164 znaków

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
źródło
Ponieważ używasz Python 2, nie musisz rzutować wyników inputas int. Ostatnie dwie linie można skrócić doprint"\n".join(r[::N>0 or-1])
Steven Rumbalski
@Steven Dokonałem zmian. Dziękuję Ci.
Ante
1

Perl, 113 znaków

$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

Rozszerzony:

$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
źródło
1

JavaScript 121 bajtów

Wewnętrzna funkcja rekurencyjna, następnie w razie potrzeby zadbaj o wyjście wstecz

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`

Mniej golfa

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>

edc65
źródło
1

Partia, 265 262 242 236 235 bajtów

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

Edycja: Zapisano 12 19 bajtów dzięki @ l4m2. Zapisano 8 bajtów, usuwając niepotrzebną %a%zmienną.

Neil
źródło
To dla 247 bajtów.
Conor O'Brien,
@ ConorO'Brien Pamiętaj, że byłoby 261, gdybym policzył wszystkie CR, a także LF (co, jestem pewien, że nie musisz tego robić, ale jestem leniwy).
Neil,
Więc nie usuwasz CR ze swojego kodu? Nawet jeśli nie jest to wymagane przez pliki .BAT i usunięte przez SE w ogóle? : P
Conor O'Brien
@ ConorO'Brien Za karę akceptuję używanie Notatnika do zapisywania plików wsadowych.
Neil,
Czy możesz zrobić coś takiego 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 bajtów

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):''}`

Wypróbuj online!

l4m2
źródło
0

Python 2 , 102 bajty

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

Wypróbuj online!

Erik the Outgolfer
źródło
0

Prolog (SWI) , 265 232 213 bajtów

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.

Wypróbuj online!

Tylko ASCII
źródło
0

PowerShell , 111 bajtów

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

Wypróbuj online!

Mniej golfa:

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{
        '_'
    }
}
mazzy
źródło