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


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.