Draw the "Cool S"

  • Introduction



    We all know the cool S (also known as Superman S, Stüssy S, Super S, Skater S, Pointy S, Graffiti S etc. etc.): billions of schoolchildren around the world drew this S and immediately felt proud of themselves. In case you've forgotten or had a completely uncool childhood, here is an image of said cool S:





    Given a scale factor n as input (where \$1\leq n\leq 20\$), output the Cool S in ASCII art.



    How to Draw It



    From the Wikipedia page on the Cool S:





    Output



    The Cool S when n = 1 is:



       ^
    / \
    / \
    / \
    | | |
    | | |
    \ \ /
    \ \/
    /\ \
    / \ \
    | | |
    | | |
    \ /
    \ /
    \ /
    v


    And for different values of n, you simply make the output n times bigger. For example, n=2:



         ^  
    / \
    / \
    / \
    / \
    / \
    | | |
    | | |
    | | |
    | | |
    \ \ /
    \ \ /
    \ \/
    /\ \
    / \ \
    / \ \
    | | |
    | | |
    | | |
    | | |
    \ /
    \ /
    \ /
    \ /
    \ /
    v


    Note that the vertical sections are two times longer and the spacing between the vertical lines is two times wider.



    And when n=3:



           ^
    / \
    / \
    / \
    / \
    / \
    / \
    / \
    | | |
    | | |
    | | |
    | | |
    | | |
    | | |
    \ \ /
    \ \ /
    \ \ /
    \ \/
    /\ \
    / \ \
    / \ \
    / \ \
    | | |
    | | |
    | | |
    | | |
    | | |
    | | |
    \ /
    \ /
    \ /
    \ /
    \ /
    \ /
    \ /
    v


    Note: Although not required, your code may also be able to support n=0:



     ^
    / \
    \\/
    /\\
    \ /
    v


    Winning



    The shortest program in bytes wins.


    The ASCII-building 90's kid in me wants to suggest using /\ instead of ^ for the tip. Looks cleaner that way, plus it maintains the same slope inclination :)

    @Flater only problem is that /\ uses two characters, so the central vertical line would have to be offset which makes it look very untidy

    @BetaDecay: It looks fine on N=2 and N=3 (since it retains point symmetry), but I agree for N=1. There's also the option of the upside down V: `Λ`

    @Flater Since we're judging by bytes, wouldn't a unicode character potentially count as >1 byte?

    @JacobGarby: My argument was stylistic, not golfy :)

  • Charcoal, 58 53 47 43 41 bytes



    Nθ≔⊕⊗θδ↗θ/⊗θ↘δ^‖B↓‖M← vMδ⁰⊗θ↗⊕θM⁰δ↗θ/⊗θ⟲T


    Try it online!



    I just wanted to try another approach, this draws the outside via reflections (thanks to Neil for expanding the idea) and then draws the inside part. As Charcoal has :Left as default direction to draw lines, I make use of that direction as much as possible to save some bytes by drawing the S horizontally, like this:



         /----\    /----\     
    / \ / \
    / \/ \
    / / \
    / / \
    v ----/ /---- ^
    \ / /
    \ / /
    \ /\ /
    \ / \ /
    \----/ \----/


    And then I just need to rotate the canvas 90 degrees counterclockwise.


    You may be onto something there... 22 bytes gets you all of the outside...

    @Neil it wasn't exactly like that, your idea needed a minor fix, but indeed this has been a great improvement!

    Yeah I made a similar mistake on my original post because I didn't check the effect of scaling correctly.

    Did someone say `Rotate`? That gives me an idea...

    @Neil hey, you got quite an improvement there! :-)

    I'd say that **either** using the v and ^ **or** using the `-` is wrong. I assumed you used the ^ and v so that you can rotate the grid while retaining the characters, but then the same logic does not apply to `-` which you'd need to replace by `|` (and similarly, all slashes should then be inverted too... I think)

    @Flater when you perform a `RotateTransform` in Charcoal, the only characters that get rotated are the ones Charcoal knows how to rotate. These include the `/` that gets rotated to `\\` and the `-` that gets rotated to `|`, but not the `v` and the `^`. So in this case I need to print the final characters even when I'm drawing the horizontal S.

    Yes, it's a neat trick, saved me 3 bytes on "Double up some diamonds" too.

  • Charcoal, 47 42 41 bytes



    Fv^«↓⊗θ↘⊗⊕θ←↓⊗θ↙⊕⊗θ↖ι↖⊕⊗θ→↑⊗θ↗⊕θMθ⁺⊗θ⊕θ⟲⁴


    Try it online! Link is to verbose version of code. Explanation: Draws the following lines in order:



       ^
    / \
    / \
    / \
    | 1 |
    | 1 |
    \ 2 /
    \ 2/
    8\ 2
    8 \ 2
    7 | 3
    7 9 3
    6 4
    6 4
    6 4
    5


    Where 5 is the current character of the string v^. At the end of the first loop the cursor is then positioned at point 9. The entire canvas is then rotated so that the other half of the Cool S can be drawn. (The canvas actually gets rotated twice, but this is just an implementation detail.)



    Charcoal doesn't support RotateCopy(:Up, 4) but if it did then this would work for 33 bytes:



    ↖^↖⊕⊗θ→↑⊗θ↗⊕θ‖BM↓↙⊗θ→↓⊗θ⟲C↑⁴J⁰¦⁰v

    @BetaDecay Sorry about that. I also had the wrong byte count anyway...

    Nice, it gets n=0 right too

  • Python 3, 255 249 248 209 bytes



    -6 bytes thanks to Kevin Cruijssen



    -1 byte thanks to Kevin Cruijssen



    -39 bytes thanks to Rod and Jo King





    n=int(input())
    m=2*n
    a,b,q,c,l='\ \n/|'
    f=m*b
    s=q+q.join([f[d:]+c+b*2*d+b+a+f[d:]for d in range(m+1)]+[l+f+l+f+l]*m+[d*b+a+f+a+f[d*2:]+c+d*b for d in range(n)]+[n*b+a+f+a+c+n*b])
    print(f,'^'+s+q+s[::-1]+f,'v')


    Try it online!



    It now handles n=0.


    Both `o+~d` can be `m-d` and `range(o)` can be `range(m+1)`, and then you can remove `o=m+1\n` to save 6 bytes. Nice answer though, +1 from me.

    Oh, and one more byte by changing `p(s)\np(s::-1

    You can save 6 bytes if you use a single `print`, and more 4 by removing `

    You can also store `q.join` in a variable to save a byte

    217. Joined all the `q.join`s, and a couple of other things

  • Canvas, 36 32 29 bytes



    «|*‼l├/L1^╋;╶╵\∔∔│α╶«├:╵╋:↔↕∔


    Try it here!



    A whole lot of stack manipulation. (outdated) explanation:



    «|*                                an array of input*2 "|"s
    ‼ cast to a 2D object (needed because bug)
    : duplicate that (saved for the center line)
    l├ height+2
    / create a diagonal that long
    L1^╋ and in it, at (width; 1) insert "^"
    ;∔ append the vertical bars
    ^
    /
    so far done: /
    /
    |
    |
    ⁸╵ input+1
    \ antidiagonal with that size
    ∔ appended to the above
    │ mirror horizontally
    ^
    / \
    / \
    / \
    current: | |
    | |
    \ /
    \ / |
    α get the 2nd to last popped thing - the antidiagonal |
    └∔ append it to the vertical line copied way before: \
    ⁸«├ input/2 + 2 \
    :╵ duplicate + 1
    ╋ at (input/2 + 2; input/2 + 3) in the big part insert ^
    :↔↕∔ mirror a copy vertically & horizontally and append that to the original

  • Python 2, 227 208 207 202 196 181 bytes





    I=n=2*input()
    R,L,S,P='/\ |'
    k=n*[2*(P+S*n)+P]
    exec"k=[R+S+2*S*I+L]+k+-~I%2*[L+S*n+L+S*I+R];I-=1;"*-~n
    print'\n'.join(t.center(2*n+3)for t in['^']+k+[a[::-1]for a in k[::-1]]+['v'])


    Try it online!



    Thks to Jo King for 1 byte; and then another 5 bytes total (via n => 2*n).



    Works for n=0 as well.


  • C (gcc), 379 353 344 334 bytes



    I used a couple of #defines for subexpression elimination and several globals to communicate between the internal functions. The main loop goes {0,1,2,3,3,2,1,0} to construct the S.



    Thanks to Jonathan Frech for the suggestions.





    #define z(a,b...)printf("%*c%*c%*c\n"+a,b);}
    #define y(a){for(i=~-a*t;v*i<v*a*!t+t;i+=v)
    i,n,p,r,t,u,v;a(){z(6,r+2,94+t*24)b()y(-~r)z(3,-i-~r,47+u,i*2+2,92-u)c()y(r)z(0,~r,124,~r,124,~r,124)d()y(-~n)z(0,i+1,92-u,2*(n-t*i)+1,92,2*(n-!t*i)+1,47+u)(*x[])()={a,b,c,d};f(s){r=2*s;for(p=0;p<8;x[7*t-p++*(2*t-1)](n=s))t=p>3,v=2*!t-1,u=t*45;}


    Try it online!


    `w -r-1` could possibly be golfed to `w~r`.

    Though then inlining is one byte shorter.

    321 bytes – Try It Online")

  • C (gcc), 260 254 bytes


    -6 bytes thanks to ceilingcat.



    f(n){int s=2*n++,t=s+1,I[]={1,t,s,n,n,s,t,1},A[]={s,1,1,1,2*t,1,t,t,1,t,1,n,t,t,1,t,t,1,1,1,t,s,1,1},x;for(s=8;s--;)for(n=0;n<I[s];n++,puts(""))for(t=3;t--;)x=s*3+t,printf("%*c",n*("[email protected][email protected]"[x]-65)+A[x],"w!!!0]}}}]]00]]}}}]!0_!!"[x]-1);}

    Try it online!


    Rundown


    We can divide the shape into parts:


     ^           Top cap
    / \ Top slope
    ||| Sides
    \\/ Twist, part 1
    /\\ Twist, part 2
    ||| Sides
    \ / Bottom slope
    v Bottom cap

    Each part could be described by a number of lines, three chars, and three relationships to certain values that decides the field-width at each line.


    A first iteration came to be:


    #define g(x,s,A,B,C)for(i=0;i<x;i++)printf("%*c%*c%*c\n",A,*s,B,s[1],C,s[2]);
    f(n)
    {
    int s=2*n++,t=s+1,i;

    g(1, " ^", 1, 1, t-1)
    g(t, "/ \\",t-i, 1,2*i+1)
    g(s, "|||", 1, t, t)
    g(n,"\\\\/",i+1, t,t-2*i)
    g(n,"/\\\\",n-i, 2*i+1, t)
    g(s, "|||", 1, t, t)
    g(t, "\\/ ",i+1,2*t-2*i, 1)
    g(1, " v", 1, 1, t-1)
    }

    The calls to the g() macro looks very much like a table could be constructed and looped over. Field-widths are sometimes related to the index counter, and sometimes not. We can generalise the field-width to be F * i + A, where F is some factor to multiply i with, and A is some value to add to the width. So the last width of the fourth call above would be -2 * i + t, for example.


    Thus we get:


    f(n){int s=2*n++,t=s+1,         s = size of "side" parts, t = size of top and bottom slopes
    I[]={1,t,s,n,n,s,t,1}, The number of lines per part.
    A[]={...},x; A[] holds the values to add to each field-width.
    for(s=8;s--;) Loop through the parts.
    for(n=0;n<I[s];n++,puts("")) I[s] decides how many lines to the part. Ends with newline.
    for(t=3;t--;) Go through the three chars of each line.
    x=s*3+t, Calculate offset.
    printf("%*c", Print the char.
    n*("..."[x]-65)+A[x], Build field-width. The string holds the index factor, A[]
    holds the offset part.
    "..."[x]-1);} The char itself is grabbed from the string.
    Shifted by 1 to eliminated double backspaces.

    In the end it was not much shorter than a tightened version of the g() calling one, but shorter is shorter.


    @ceilingcat Cheers.

    @ceilingcat The undefined evaluation order of function arguments give me pause.

  • Java, 435 bytes



    The function itself takes 435 bytes. There is certainly room for improvement, "high level" by analyzing the rules about where to place which character (in the end the S is point-symmetric), and "low-level", by classical golfing (maybe pulling out another variable or combining two of the for-loops). But it's a first shot with this rather ungolfy language:



    import static java.util.Arrays.*;
    import static java.lang.System.*;

    public class CoolS
    {
    public static void main(String[] args)
    {
    print(1);
    print(2);
    print(3);
    }
    static void print(int n){int i,r,d=3+6*n,w=3+n*4,h=6+n*10,m=n+n,v=w/2,k=h-1,j=w-1;char t[],S='/',B='\\',P='|',s[][]=new char[h][w];for(char x[]:s)fill(x,' ');s[0][v]='^';s[k][v]='v';for(i=0;i<1+m;i++){r=i+1;t=s[r];t[v-r]=S;t[v+r]=B;t=s[k-r];t[v-r]=B;t[v+r]=S;}for(i=0;i<m;i++){r=2+m+i;t=s[r];t[0]=t[v]=t[j]=P;t=s[k-r];t[0]=t[v]=t[j]=P;}for(i=0;i<1+n;i++){r=2+m+m+i;t=s[r];t[i]=t[i+1+m]=B;t[j-i]=S;t=s[d-i];t[i]=S;t[v-i]=t[j-i]=B;}for(char x[]:s)out.println(x);}
    }

    Hi there. Imports are part of the byte-count I'm afraid, so your current answer is actually 478 bytes. You can however golf it down to (coincidentally enough) your current 435 bytes with some basic things to golf.

    Been able to golf a bit more to 405 bytes by removing some variables and using `t=...` a bit less where it would save bytes. If you have any questions about any of the changes I made, let me know. :)

    Thanks @KevinCruijssen , unfortunately I currently cannot invest more time here - this was just a recreational thing, and considering the "verbosity" of Java, not a serious competitor anyhow ;-) Consider adding your solution as an own answer, though - **then** we at least have some intra-language competition :-)

  • PHP, 378 374 378 377 376 335 331 328 bytes



    -3 bytes, thanks to manatwork



    -4 bytes, used str_pad instead of str_repeat



    -41 bytes, thanks to manatworks' suggestions



    -1 byte, merged two increments into a +=2



    -1 byte, removed superfluous \



    -4 bytes by echoing once. Forgot I needed to pass the string into the function so this is more bytes



    Works for n = 0 as well.





    function s($b){return str_pad($w,$b);}echo s($i=1+$a=2*$argv[1]).'^
    ';for(;$i;$j++,$y=$z.$y)echo$z=s(--$i).'/'.s(++$j).'\
    ';for(;$k<$a;$k++)$x.='|'.s($a).'|'.s($a).'|
    ';echo$x;for(;$l<=$a/2;)echo s($m++).$c='\\',s($a).$c.s($a-$l++*2).'/
    ';for(;$m;$n+=2)echo s(--$m).'/'.s($n).$c.s($a).'\
    ';echo$x.strtr($y,'/\\','\/').s($a+1).v;


    Try it online!


    As function declaration is quite expensive and you use t() only twice, would be shorter without it. If beside the 9 notices you take 1 warning too, you can remove the quotes around `'v'` in the final `echo`.

    You could use single loop for the top and bottom oblique parts. The initialization of $a and $i could be compacted by moving them at their first usage.

    Oh, and `$i>0` and `$m>0` can be written simply as `$i` and `$m`.

    With trailing spaces, as in some other solutions.

    @manatwork thanks for all the help! Some really nice tricks to use in other answers too

    You can also move the declaration of $c to its first usage. Just change the `.` concatenation after it to `,`. Try it online!

  • Python 3, 321 307 bytes



    Thanks to @EsolangingFruit for saving 14 bytes





    n=int(input())
    b,f='\/'
    c,l=4*n+3,10*n+6
    r=range
    h=c//2
    L=[c*[' ']for _ in r(l)]
    L[0][h],L[-1][h]='^v'
    for i in r(h):a=L[h-i];a[i],a[c+~i]=f,b
    for i in r(2*n):L[h-~i][0::h]='|'*3
    for i in r(n+1):a=L[h+h+i];a[c+~i],a[i:c-1:h]=f,b*2
    for i in r(1,l//2):L[l+~i]=L[i][::-1]
    print('\n'.join(''.join(i)for i in L))


    Try it online!



    Python 2, 303 bytes





    n=int(input())
    b,f='\/'
    c,l,r=4*n+3,10*n+6,range
    h=c/2
    L=[c*[' ']for _ in r(l)]
    L[0][h],L[-1][h]='^v'
    for i in r(h):a=L[h-i];a[i],a[c+~i]=f,b
    for i in r(2*n):L[h-~i][0::h]='|'*3
    for i in r(n+1):a=L[h+h+i];a[c+~i],a[i:c-1:h]=f,b*2
    for i in r(1,l/2):L[l+~1]=L[i][::-1]
    print'\n'.join(''.join(i)for i in L)


    Try it online!


    You can replace `'\\','/'` on the second line with `*'\/'` to save three bytes.

    Thanks! @EsolangingFruit! I was not aware of bit operations in Python. Also, it would save a few bytes to use Python2 because of the division and parentheses in `print`

    In Python 2, `input()` automatically `eval()`s the string, so you can skip the `int()` call as well.

    For Python 3, you can change the last line to `for l in L:print(*l,sep="")` (I don't think there is an equivalent in Python 2).

License under CC-BY-SA with attribution


Content dated before 7/24/2021 11:53 AM

Tags used