Cetak Set Cantor

19

Tantangan

Membangun Set Cantor N-Leveled .

Set terner Cantor dibuat dengan berulang kali menghapus pertiga tengah terbuka dari satu set segmen garis.

Program menerima satu parameter N(angka integer) dan kemudian mencetak (dalam konsol atau dengan cara serupa) Cantor Set level N. Hasil cetak hanya dapat berisi karakter undescore ( _) dan spasi. Parameter bisa positif atau negatif dan tanda menunjukkan orientasi konstruksi Cantor Set: Jika N > 0Cantor Set dibangun ke bawah dan jika N < 0Cantor Set dibangun ke atas. Jika N = 0kemudian program mencetak satu baris ( _).

Sebagai contoh:

N = 2

_________
___   ___
_ _   _ _

N = -2

_ _   _ _
___   ___
_________

N = 3

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

N = -3

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

Kriteria menang

Karena ini merupakan tantangan kode golf, kode terpendek menang.

Diedit: Ubah 0 input dengan saran ugoren.

Averroes
sumber
Mengapa tidak mencetak apa-apa saat N = 0? Ini menjadikan 0 kasus khusus, dan membuatnya lebih sulit untuk menggunakan rekursi. Penanganan umum akan mencetak satu _(tapi cetak ke bawah saat mendapatkan -0).
ugoren
Baik. Saya sudah memodifikasi spesifikasi.
Averroes

Jawaban:

10

GolfScript, 49 42 40 karakter

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

Dengan terima kasih kepada hammar untuk 42-> 40.

Upaya terbaik saya pada pendekatan yang lebih banyak angka-teoretis sayangnya jauh lebih lama:

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

atau

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

dan saya menduga bahwa panjang basedan zipakan membuat tidak mungkin untuk mengejar ketinggalan.

Peter Taylor
sumber
~.abs.@/\.3\?'_'*\{.3%..,' '*\++}*](%n*39 karakter, tetapi macet saat input 0. :-(
Ilmari Karonen
@IlmariKaronen, ya, pembagian dengan nol itu menyebalkan untuk implementasi C yang saya tulis juga, karena itu berarti Anda tidak bisa melakukannya n/abs(n)untuk mendapatkannya signum(n).
Peter Taylor
6

Python, 116 113 104 103 karakter

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

Algoritma yang lebih lama mencapai 113 karakter

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
sumber
5

Ruby (97)

Berdasarkan versi python 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

Upaya sebelumnya, keduanya sama-sama panjang (112)

Buat garis dari bagian:

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

Mulai dengan satu baris, buat lubang di dalamnya:

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
sumber
3

Perl, 93 karakter

@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

Saya pikir saya akan mencoba melihat seberapa baik solusi GolfScript Peter Taylor akan port ke Perl. Fitur-fitur penting termasuk penggunaan sortalih - alih reverseuntuk menyimpan tiga karakter, menggunakan fakta bahwa ruang seperti sebelumnya _.

Ilmari Karonen
sumber
2

Common Lisp, 217 210 karakter

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

Diperluas:

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

Saya pikir jika kode Lisp berhasil mengalahkan hitungan awal apa pun untuk bahasa lain (C, 219) Saya baik-baik saja :)

Paul Richter
sumber
2

C ( 163 161 karakter)

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

Pinjam beberapa trik dari jawaban ugoren , tetapi logika intinya sangat berbeda. Saya tidak bisa mengikuti jejaknya, jadi mungkin saja untuk melakukan hibridisasi dan menyimpan lebih banyak.

Peter Taylor
sumber
2

C, 219 193 179 143 136 131 karakter

Mengikuti gagasan Petyer Taylor yang lain, ditambah peningkatan saya sendiri, menyelamatkan 6 lebih banyak.
Mengintegrasikan beberapa tips dari @PeterTaylor, ditambah menyalin fungsi utamanya, dengan sedikit perubahan, yang menyelamatkan karakter (apakah adil untuk menyalinnya? Karena kita berdua tidak akan memenangkan yang ini, saya kira itu tidak terlalu buruk).
Saya memikirkan peningkatan yang signifikan dalam cara rekursi saya bekerja, dan setelah melihat jawaban Peter Taylor, saya menerapkannya untuk mendapatkan kembali kepemimpinan. Ketika membaca jawabannya lagi, saya melihat bahwa saya melakukan hampir apa yang dia lakukan. Jadi ini sepertinya hibridisasi yang disarankannya.
Juga menyederhanakan loop main, menjaga panjang yang sama.
Dan mengambil trik Peter untuk mencetak baris baru, bukannya puts("")- menyimpan karakter.

Dihapus intdari deklarasi variabel - peringatan, tetapi menyimpan 4 karakter.
Algoritma baru tidak menghitung 3 ^ x di muka, tetapi menggunakan satu loop untuk mencetak 3 ^ x karakter.
Dapat menyimpan satu lagi dengan mendefinisikan int*v, tetapi 64bit tidak akan berfungsi.
Jumlah karakter tidak termasuk spasi putih (yang dapat dihapus).

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

Algoritma yang lebih lama, 219 karakter:

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
sumber
@PeterTaylor, saya tidak bisa menghapus iparameter, karena menggunakan global akan mengganggu main. l--akan mengganggu o>=l, dan saya harus menggantinya dengan >(jadi mengapa saya menulisnya seolah itu hal yang buruk?) Saya juga bisa menyalin Anda main, yang lebih sederhana dan lebih pendek dari milik saya.
ugoren
@ PeterTaylor, Anda benar tentang i- Saya merindukan kenyataan bahwa saya benar-benar tidak lagi menggunakannya (saya pikir Anda maksud saya tidak lulus).
ugoren
Ngomong-ngomong, saya tidak keberatan Anda mengambil fungsi utama saya. Aturan praktis saya adalah bahwa menyalin solusi orang lain untuk mengubah satu karakter terlalu agresif, menyalin solusi orang lain untuk menulis ulang setengah dari itu benar-benar adil, dan ada area abu-abu di antara keduanya. Kita mungkin harus mencoba menyepakati beberapa standar komunitas tentang meta.
Peter Taylor
@ PeterTaylor, saya pikir kami mencapai semacam jalan buntu. pTampaknya saya cukup optimal sekarang, dan Anda mainlebih baik (saya tidak yakin itu optimal, tetapi tidak dapat memperbaikinya lebih lanjut). Jadi kecuali untuk struktur program baru yang cerdik, satu-satunya cara untuk pergi adalah salah satu dari kita menyalin kode yang lain.
ugoren
BTW Bagaimana Anda menghitung karakter Anda? Karena saya membuat versi terbaru Anda 138 karakter, bukan 136.
Peter Taylor
2

J, 44 39 38 37 byte

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

Gunakan iterasi untuk membangun set berikutnya dimulai dengan 1 (mewakili _ ) pada awalnya.

Pemakaian

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

Penjelasan

' _'{~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
mil
sumber
Bagus! Saya belum mencoba secara pribadi, tapi saya suka menggunakan agenda @.- mungkin, dikombinasikan dengan $:, dapat bermanfaat di sini? Misalnya sesuatu seperti (zero case)`(positive case)`(negative case)@.*, atau bahkan mungkin ":@_:`(positive case)`(|."1@$:)@.*.
Conor O'Brien
Saya belum mencoba solusi rekursif, tetapi saya bisa mencobanya.
mil
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,,"")

Cobalah online!

-15 byte terima kasih juga penggunaan Giuseppe '('sebagai fungsi identitas; writealih-alih catmencetak hasil; penggunaan cerdas %x%.

-2 byte terima kasih kepada Kirill L. dengan menggunakan calih-alih '('sebagai fungsi identitas.

JayCe
sumber
dapatkah produk Kronecker bekerja di sini? %x%? Mungkin ada beberapa masalah dengan mengambil baris bergantian mungkin ...
Giuseppe
@ Giuseppe Saya mencoba, membangun "Buat" H "dari jawaban" H "yang lebih kecil ... Saya akan mencobanya lagi.
JayCe
Ah, jadi Andalah yang memutuskan itu. itulah satu-satunya alasan yang saya pikirkan kronjuga! Saya membayangkan ini harus bisa turun menjadi seperti 125 byte jika kita dapat menemukan pendekatan yang tepat.
Giuseppe
Anda dapat menggunakan `(`sebagai fungsi identitas sehingga Anda dapat menggunakan writesecara langsung alih-alih catdan satu forlingkaran. 141 byte
Giuseppe
@ Giuseppe Saya tidak tahu (bisa digunakan dengan cara ini, atau yang if dapat digunakan untuk memilih dari dua fungsi. Dan saya akan mulai menggunakan tulis ... menyimpan banyak "\ n".
JayCe
1

Python, 177 164 karakter

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])
Sokongan
sumber
Karena Anda menggunakan Python 2, Anda tidak perlu menampilkan hasil inputas int. Dua baris terakhir Anda dapat disingkat menjadiprint"\n".join(r[::N>0 or-1])
Steven Rumbalski
@ Seven saya membuat perubahan. Terima kasih.
Ante
1

Perl, 113 karakter

$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

Diperluas:

$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
sumber
1

JavaScript 121 byte

Fungsi rekursif dalam, kemudian urus output mundur jika diperlukan

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`

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

Uji

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
sumber
1

Batch, 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%

Sunting: Disimpan 12 19 byte berkat @ l4m2. Disimpan 8 byte dengan menghapus %a%variabel yang tidak perlu .

Neil
sumber
Ini untuk 247 byte.
Conor O'Brien
@ ConorO'Brien Pikiran Anda akan menjadi 261 jika saya menghitung semua CR serta LF (yang saya yakin Anda tidak perlu melakukan tetapi saya malas seperti itu).
Neil
Jadi Anda tidak menghapus CR dari kode Anda? Meskipun itu tidak diperlukan oleh file .BAT dan dilucuti oleh SE bagaimanapun? : P
Conor O'Brien
@ ConorO'Brien Ini penalti yang saya terima menggunakan Notepad untuk menulis file Batch.
Neil
Bisakah Anda melakukan sesuatu seperti 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?
14m2
0

JavaScript (Node.js) , 148 byte

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

Cobalah online!

l4m2
sumber
0

Python 2 , 102 byte

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

Cobalah online!

Erik the Outgolfer
sumber
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.

Cobalah online!

Khusus ASCII
sumber
0

PowerShell , 111 byte

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

Cobalah online!

Kurang bermain 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{
        '_'
    }
}
mazzy
sumber