Роздрукуйте набір кантора


19

Змагання

Побудувати N-вирівняли Кантора Set .

Потрійний набір Кантора створюється багаторазовим вилученням відкритих середніх третин набору відрізків рядків.

Програма отримує один параметр N(ціле число), а потім друкує (консольним чи подібним чином) набір кантора з N рівнів. Друк може містити лише відмітки ( _) та пробіли. Параметр може бути позитивним або негативним, і знак вказує орієнтацію конструкції набору кантора: Якщо N > 0набір канторів побудований вниз і якщо N < 0набір канторів побудований вгору. Якщо N = 0тоді програма виводить один рядок ( _).

Наприклад:

N = 2

_________
___   ___
_ _   _ _

N = -2

_ _   _ _
___   ___
_________

N = 3

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

N = -3

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

Критерії виграшу

Оскільки це кодове завдання для гольфу, виграє найкоротший код.

Відредаговано: Змініть 0 введення за пропозицією ugoren.


Чому нічого не друкувати, коли N = 0? Це робить 0 особливим випадком і ускладнює використання рекурсії. Загальним поводженням було б роздрукувати сингл _(але роздрукувати його вниз при отриманні -0).
ugoren

Правильно. Я вже змінив характеристики.
Аверрое

Відповіді:


10

GolfScript, 49 42 40 символів

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

Завдяки гаммару за 42-> 40.

На жаль, моя найкраща спроба більш теоретичного підходу, на жаль, значно довша:

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

або

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

і я підозрюю, що довжина baseі zipзробить неможливим наздогнати.


~.abs.@/\.3\?'_'*\{.3%..,' '*\++}*](%n*становить 39 знаків, але виходить з ладу при вході 0. :-(
Ілмарі Каронен

@IlmariKaronen, так, поділ на нуль була біль для реалізації C Я писав теж, тому що це означало , що ви не можете зробити , n/abs(n)щоб отримати signum(n).
Пітер Тейлор

6

Пітона, 116 113 104 103 символів

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

Старіший алгоритм перевищував 113 символів

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

Рубін (97)

На основі версії пітона Стівена Румбальського:

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

Попередні спроби, однакові за довжиною (112)

Побудувати лінії з деталей:

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

Почніть з одного рядка, зробіть в ньому отвори:

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 ч

@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

Я думав, що спробую побачити, наскільки добре рішення GolfScript Пітера Тейлора перенесеться на Perl. Помітні функції включають використання sortзамість того, reverseщоб зберегти три символи, використовуючи той факт, що пробіл впорядковувався раніше _.


2

Лист звичайний, 217 210 символів

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

Розширено:

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

Я думаю, якщо код Lisp зуміє перемогти будь-який початковий підрахунок для іншої мови (C, 219), я все в порядку :)


2

C ( 163 161 символів)

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

Позичайте пару хитрощів з відповіді ugoren , але основна логіка зовсім інша. Я не міг слідкувати за його циклом, тому можливо гібридизувати та зберегти ще кілька.


2

C, 219 193 179 143 136 131 символів

Слідом за черговою ідеєю Петьє Тейлора, а також покращенням моїх власних, врятувало ще 6.
Інтегровано кілька порад від @PeterTaylor, а також скопійовано його основну функцію з невеликими змінами, які врятують персонажа (чи справедливо його скопіювати? Оскільки ніхто з нас не виграє цього, я думаю, це не дуже погано).
Я подумав про значне поліпшення роботи моєї рекурсії, і побачивши відповідь Пітера Тейлора, я реалізував це, щоб відновити лідерство. Прочитавши ще раз його відповідь, я побачив, що я зробив майже точно те, що робив. Отже, це здається гібридизацією, яку він запропонував.
Також спрощена петля в main, зберігаючи однакову довжину.
І взяв фокус Петра, щоб замість цього друкувати новий рядок, puts("")- зберігає персонаж.

Видалено intзі змінної декларації - попередження, але економить 4 символи.
Новий алгоритм не обчислює 3 ^ х заздалегідь, але використовує один цикл для друку 3 ^ х символів.
Можна зберегти ще один, визначившись int*v, але тоді 64-бітний не працюватиме.
Кількість символів виключає пробіл (який можна видалити).

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

Старіший алгоритм, 219 символів:

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, я не можу видалити iпараметр, тому що використання глобального може заважати main. l--буде заважати o>=l, і мені доведеться замінити його >(так чому я це пишу так, ніби це погано?) Я також міг би вас скопіювати main, що простіше і коротше мого.
угорен

@PeterTaylor, ви мали рацію i- я пропустив той факт, що я його справді більше не використовую (я думав, ти маєш на увазі, що я його не передаю).
угорен

До речі, я не заперечую, щоб ти взяв мою головну функцію. Моє правило полягає в тому, що копіювати чуже рішення для зміни одного символу надмірно агресивно, копіювати чуже рішення, щоб переписати половину його, цілком справедливо, а десь посередині є сіра область. Ми, можливо, варто спробувати погодити деякі стандарти громади щодо мета.
Пітер Тейлор

@PeterTaylor, я думаю, ми досягли свого роду тупика. Моє зараз pздається цілком оптимальним, і ваше mainбуло краще (я не впевнений, що це оптимально, але не можу вдосконалити його далі). Отже, за винятком нової геніальної структури програми, єдиним із нас було скопіювати код іншого.
угорен

BTW Як ти рахуєш своїх персонажів? Тому що я складаю останню версію 138 символів, а не 136.
Пітер Тейлор

2

J, 44 39 38 37 байт

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

Використовує ітерацію для побудови наступного набору, починаючи з 1 (представляючи _) спочатку.

Використання

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

Пояснення

' _'{~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

Приємно! Я особисто не намагався, але я люблю використовувати порядок денний @.- можливо, це в поєднанні з цим $:може бути корисним? Наприклад, щось на кшталт (zero case)`(positive case)`(negative case)@.*або, можливо, навіть ":@_:`(positive case)`(|."1@$:)@.*.
Conor O'Brien

Я не намагався рекурсивного рішення, але міг би спробувати.
миль

2

R , 141 139 137 байт

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

Спробуйте в Інтернеті!

-15 байт також завдяки використанню Джузеппе '('як функції ідентичності; writeзамість catдрукувати вихід; розумне використання %x%.

-2 байти завдяки Кирилу Л., використовуючи cзамість '('нього функцію ідентичності.


чи може тут працювати Kronecker продукт? %x%? Можливо, можуть виникнути проблеми з заміною чергувань рядків ...
Джузеппе

@Giuseppe Я спробував, спираючись на вашу відповідь "Створіть" H "з менших" H "s" відповідей ... Я спробую ще раз.
JayCe

А, значить, це ти заперечив. це єдина причина, про яку я kronтеж думав ! Я думаю, що це може бути здатне зменшитись до 125 байт, якщо ми зможемо знайти правильний підхід.
Джузеппе

ви можете використовувати `(`як функцію ідентичності, щоб ви могли використовувати writeбезпосередньо замість catі forцикл. 141 байт
Джузеппе

@Giuseppe Я не мав уявлення, що це (може бути використано таким чином, або що if можна використати для вибору з двох функцій. І я почну використовувати write ... економить багато "\ n".
JayCe

1

Пітон, 177 164 символів

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

Так як ви використовуєте Python 2 вам не потрібно , щоб привести результати в inputякості int. Ваші останні два рядки можуть бути скорочені доprint"\n".join(r[::N>0 or-1])
Стівен Румбальський

@Steven Я вніс зміни. Дякую.
Анте

1

Perl, 113 чол

$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

Розширено:

$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 байт

Внутрішня рекурсивна функція, потім подбайте про зворотній вихід, якщо це необхідно

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`

Менше гольфу

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

Тест

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

Пакетна, 265 262 242 236 235 байт

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

Редагувати: Збережено 12 19 байт завдяки @ l4m2. Збережено 8 байт, видаливши непотрібну %a%змінну.


Це на 247 байт.
Conor O'Brien

@ ConorO'Brien Зверніть увагу, це було б 261, якби я порахував усі КР, а також КЧ (що я впевнений, що вам цього не потрібно, але я ледачий такий).
Ніл

Отже, ви не видаляєте CR зі свого коду? Навіть незважаючи на те, що це не потрібно файлами .BAT і позбавленим SE? : P
Conor O'Brien

@ ConorO'Brien Це штраф, який я приймаю за використання Блокнота для написання пакетних файлів.
Ніл

Ви можете зробити щось на кшталт 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




Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.