Cantor-Set drucken

19

Die Herausforderung

Erstellen Sie ein Cantor-Set mit N-Level .

Die ternäre Cantor-Menge wird durch wiederholtes Löschen des offenen mittleren Drittels einer Menge von Liniensegmenten erstellt.

Das Programm empfängt einen Parameter N(eine Ganzzahl) und druckt dann (auf Konsolen- oder ähnliche Weise) einen Cantor-Satz von N Ebenen. Der Ausdruck darf nur nicht mit einem Punkt ( _) und mit Leerzeichen versehene Zeichen enthalten. Der Parameter kann positiv oder negativ sein und das Vorzeichen gibt die Konstruktionsausrichtung des Cantor-Sets an: Wenn N > 0das Cantor-Set nach unten und N < 0das Cantor-Set nach oben konstruiert ist. Wenn N = 0dann druckt das Programm eine einzelne Zeile ( _).

Beispielsweise:

N = 2

_________
___   ___
_ _   _ _

N = -2

_ _   _ _
___   ___
_________

N = 3

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

N = -3

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

Gewinnkriterien

Da es sich um eine Code-Golf-Herausforderung handelt, gewinnt der kürzeste Code.

Bearbeitet: Ändere die Eingabe von 0 nach dem Vorschlag von ugoren.

Averroes
quelle
Warum nichts drucken, wenn N = 0? Dies macht 0 zu einem Sonderfall und erschwert die Verwendung der Rekursion. Die allgemeine Vorgehensweise wäre, eine einzelne zu drucken _(aber sie nach unten zu drucken, wenn Sie -0 erhalten).
Ugoren
Recht. Ich habe die Spezifikationen bereits geändert.
Averroes

Antworten:

10

GolfScript, 49 42 40 Zeichen

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

Mit Dankeschön an Hammar für 42-> 40.

Mein bisher bester Versuch einer zahlen-theoretischen Herangehensweise ist leider viel länger:

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

oder

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

und ich vermute, dass die Länge von baseund zipes unmöglich machen wird, aufzuholen.

Peter Taylor
quelle
~.abs.@/\.3\?'_'*\{.3%..,' '*\++}*](%n*beträgt 39 Zeichen, stürzt jedoch bei der Eingabe ab 0. :-(
Ilmari Karonen
@IlmariKaronen, ja, das Teilen durch Null war für die C-Implementierung, die ich auch geschrieben habe, ein Schmerz, weil es bedeutete, dass man nichts tun kann n/abs(n), um es zu bekommen signum(n).
Peter Taylor
6

Python, 116 113 104 103 Zeichen

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

Älterer Algorithmus mit 113 Zeichen aufgefüllt

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

Rubin (97)

Basierend auf Steven Rumbalskis Python-Version:

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

Frühere Versuche, beide gleich lang (112)

Bauen Sie Linien aus Teilen:

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

Beginnen Sie mit einer Linie und bohren Sie Löcher hinein:

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

Perl, 93 Zeichen

@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

Ich dachte, ich würde versuchen zu sehen, wie gut sich Peter Taylors GolfScript-Lösung auf Perl portieren lässt. Zu den bemerkenswerten Merkmalen gehört die Verwendung von sortanstelle von reverse, um drei Zeichen zu speichern, wobei die Tatsache genutzt wird, dass ein Leerzeichen zuvor sortiert wurde _.

Ilmari Karonen
quelle
2

Common Lisp, 217 210 Zeichen

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

Erweitert:

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

Ich denke, wenn der Lisp-Code eine Anfangszählung für eine andere Sprache übertrifft (C, 219), geht es mir gut :)

Paul Richter
quelle
2

C ( 163 161 Zeichen)

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

Leiht sich ein paar Tricks aus Ugorens Antwort , aber die Kernlogik ist ganz anders. Ich konnte seiner for-Schleife nicht folgen, daher ist es möglicherweise möglich, weitere zu hybridisieren und zu speichern.

Peter Taylor
quelle
2

C, 219 193 179 143 136 131 Zeichen

Befolgte eine andere Idee von Petyer Taylor und eine Verbesserung meiner eigenen, sparte 6 weitere.
Einige Tipps von @PeterTaylor wurden integriert und seine Hauptfunktion mit geringfügigen Änderungen kopiert, die einen Charakter retten (ist es fair, ihn zu kopieren? Da keiner von uns diesen gewinnen wird, denke ich, dass es nicht so schlimm ist).
Ich dachte an eine signifikante Verbesserung der Funktionsweise meiner Rekursion und nachdem ich die Antwort von Peter Taylor gesehen hatte, implementierte ich sie, um den Vorsprung wiederzugewinnen. Als ich seine Antwort noch einmal las, sah ich, dass ich fast genau das tat, was er tat. Das scheint also die von ihm vorgeschlagene Hybridisierung zu sein.
Vereinfachte auch das Einschleifen bei maingleicher Länge.
Und nahm Peters Trick, um eine neue Zeile zu drucken, anstatt puts("")- einen Charakter zu speichern.

Aus intVariablendeklaration entfernt - eine Warnung, spart jedoch 4 Zeichen.
Der neue Algorithmus berechnet nicht 3 ^ x im Voraus, sondern verwendet eine einzelne Schleife, um 3 ^ x Zeichen zu drucken.
Kann durch Definieren einen weiteren speichern int*v, aber dann funktionieren 64-Bit nicht.
Die Anzahl der Zeichen schließt Leerzeichen aus (diese können entfernt werden).

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

Älterer Algorithmus, 219 Zeichen:

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
quelle
@PeterTaylor, ich kann den iParameter nicht entfernen , da die Verwendung der globalen würde stören main. l--wird stören o>=l, und ich muss es ersetzen >(warum schreibe ich es dann so, als wäre es eine schlechte Sache?) Ich könnte dich auch kopieren main, was einfacher und kürzer ist als meine.
Ugoren
@PeterTaylor, du hattest Recht i- ich habe die Tatsache übersehen, dass ich es wirklich nicht mehr benutze (ich dachte, du meinst, ich übergebe es nicht).
Ugoren
Übrigens macht es mir nichts aus, dass Sie meine Hauptfunktion übernehmen. Meine Faustregel ist, dass das Kopieren der Lösung eines anderen zum Ändern eines einzelnen Zeichens übermäßig aggressiv ist, das Kopieren der Lösung eines anderen zum Umschreiben der Hälfte davon ist vollkommen fair, und irgendwo dazwischen befindet sich eine graue Fläche. Wir sollten vielleicht versuchen, einige Community-Standards für Meta zu vereinbaren.
Peter Taylor
@PeterTaylor, ich denke wir haben eine Art Patt erreicht. Mein pscheint jetzt ganz optimal zu sein, und deines mainwar besser (ich bin nicht sicher, ob es optimal ist, aber ich kann es nicht weiter verbessern). Abgesehen von einer neuen genialen Programmstruktur war der einzige Weg, den Code des anderen zu kopieren.
Ugoren
BTW Wie zählst du deine Charaktere? Weil ich deine neueste Version 138 Zeichen mache, nicht 136.
Peter Taylor
2

J, 44 39 38 37 Bytes

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

Verwendet die Iteration, um den nächsten Satz zu erstellen, der anfänglich mit 1 (repräsentiert _) beginnt .

Verwendung

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

Erläuterung

' _'{~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
Meilen
quelle
Nett! Ich persönlich habe es nicht versucht, aber ich liebe es, die Agenda zu verwenden - @.vielleicht könnte es in Kombination mit $:hier von Nutzen sein? ZB sowas (zero case)`(positive case)`(negative case)@.*oder vielleicht sogar ":@_:`(positive case)`(|."1@$:)@.*.
Conor O'Brien
Ich habe keine rekursive Lösung versucht, aber ich könnte es versuchen.
Meilen
2

R , 141 139 137 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,,"")

Probieren Sie es online!

-15 Bytes danke auch Giuseppes Verwendung '('als Identitätsfunktion; writeanstatt catdie Ausgabe zu drucken; kluger Gebrauch von %x%.

-2 Bytes dank Kirill L. mit cstatt '('als Identitätsfunktion.

JayCe
quelle
könnte hier ein Kronecker-Produkt funktionieren? %x%? Es könnte einige Probleme geben, wenn man abwechselnde Reihen nimmt ...
Giuseppe
@ Giuseppe Ich habe versucht, aufbauend auf Ihrer Antwort "Erstellen Sie ein" H "aus kleineren" H "" ... Ich werde es noch einmal versuchen.
JayCe
Ah, das hast du also befürwortet. Das ist der einzige Grund, an den ich auch gedacht kronhabe! Ich würde mir vorstellen, dass dies 125 Bytes erreichen sollte, wenn wir den richtigen Ansatz finden.
Giuseppe
Sie können `(`als Identitätsfunktion verwenden, sodass Sie writedirekt anstelle von catund eine forSchleife verwenden können. 141 Bytes
Giuseppe
@ Giuseppe Ich hatte keine Ahnung, (wie man das so macht, oder dass if man damit aus zwei Funktionen auswählen kann. Und ich werde anfangen zu schreiben ... spart eine Menge "\ n".
JayCe
1

Python, 177 164 Zeichen

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
quelle
Da Sie Python 2 verwenden, müssen Sie die Ergebnisse von inputas nicht konvertieren int. Ihre letzten beiden Zeilen könnten verkürzt werden aufprint"\n".join(r[::N>0 or-1])
Steven Rumbalski
@Steven Ich habe Änderungen vorgenommen. Vielen Dank.
Ante
1

Perl, 113 Zeichen

$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

Erweitert:

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

JavaScript 121 Bytes

Innere rekursive Funktion, dann kümmern Sie sich bei Bedarf um die Rückwärtsausgabe

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`

Weniger golfen

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

Prüfung

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

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

Bearbeiten: 12 bis 19 Bytes dank @ l4m2 gespeichert. 8 Bytes durch Entfernen der unnötigen %a%Variablen gespart .

Neil
quelle
Dies für 247 Bytes.
Conor O'Brien
@ ConorO'Brien Wohlgemerkt wäre es 261, wenn ich alle CRs sowie die LFs zählen würde (was Sie sicher nicht tun müssen, aber ich bin so faul).
Neil
Sie entfernen also keine CRs aus Ihrem Code? Auch wenn es von .BAT-Dateien nicht benötigt und von SE trotzdem entfernt wird? : P
Conor O'Brien
@ ConorO'Brien Es ist eine Strafe, die ich akzeptiere, wenn ich Notepad zum Schreiben von Batch-Dateien benutze.
Neil
Kannst du so etwas machen 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?
14.
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):''}`

Probieren Sie es online!

l4m2
quelle
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.

Probieren Sie es online!

Nur ASCII
quelle
0

PowerShell , 111 Byte

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

Probieren Sie es online!

Weniger golfen:

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
quelle