15
\$\begingroup\$

Write a program or function that takes in a positive integer N, and prints or returns an N×N ASCII art string whose top half is a semicircle made of ('s and whose bottom half is a downward-pointing triangle made of V's, with spaces used as padding.

In other words, make an ASCII ice cream cone: (output for N = 17)

      (((((      
    (((((((((    
  (((((((((((((  
  (((((((((((((  
 ((((((((((((((( 
 ((((((((((((((( 
(((((((((((((((((
(((((((((((((((((
VVVVVVVVVVVVVVVVV
 VVVVVVVVVVVVVVV 
  VVVVVVVVVVVVV  
   VVVVVVVVVVV   
    VVVVVVVVV    
     VVVVVVV     
      VVVVV      
       VVV       
        V        

Examples

Here are the outputs for N = 1 to 5. Note that for odd N, the triangle always must be the larger half.

V

((
VV

(((
VVV
 V 

 (( 
((((
VVVV
 VV 

 ((( 
(((((
VVVVV
 VVV 
  V  

Here's an N = 101 pastebin.

And here's an ungolfed Python 3 reference implementation:

N = int(input())
ic = [[' '] * N for _ in range(N)]
for y in range(N//2):
    for x in range(N):
        if (x - (N - 1) / 2)**2 + (y - (N - 1) / 2)**2 < (N / 2)**2:
            ic[y][x] = '('
for y in range(N//2, N):
    for x in range(y - N//2, N - (y - N//2)):
        ic[y][x] = 'V'
for line in ic:
    print(''.join(line))

Details

  • Take input from stdin, command line, or as function argument. Output to stdout or similar, or you may return the string if you write a function.
  • The cone portion should exactly match the reference implementation for all N.
  • The ice cream portion does not need to exactly match the reference implementation as long as it is clearly in the shape of a semicircle for all N. (This is so you don't have to worry about slight differences in the semicircle due to roundoff errors.)
  • There should not be any unnecessary leading spaces but there may be superfluous trailing spaces.
  • The output may optionally contain a trailing newline.
  • You may optionally use any 3 other distinct printable ASCII characters in place of (, V, and space.

Scoring

The shortest submission in bytes wins. Tiebreaker goes to the oldest submission.

\$\endgroup\$
  • 6
    \$\begingroup\$ Am I the only one who thought "IceCII ASCream" when I read the title? \$\endgroup\$ – Sp3000 Mar 2 '15 at 17:19
  • 15
    \$\begingroup\$ @Sp3000 Jeez, I hope so... \$\endgroup\$ – Calvin's Hobbies Mar 2 '15 at 17:21
7
\$\begingroup\$

CJam, 46 bytes

Try it online.

{:Z{Z{Z(2./:R-zYR<):P#YR-zP#+Z2./P#>SP?}/N}fY}

I believe this currently mimics the original specification exactly, which was required when I started producing this answer. There may be potential to save a few bytes by making the math less accurate to the original specification, but until I see a way to save more than one or two bytes doing so, I'll leave it as-is.

Explanation

{               "Begin block";
  :Z{             "For each y from 0 to input-1";
    Z{              "For each x from 0 to input-1";
      Z(2./:R         "Calculate the radius as (input-1)/2.0";
      -z              "Calculate the horizontal distance from the center";
      YR<):P          "Calculate the power to raise distances to: (y<radius)+1
                       (This results in Euclidean distance being calculated for
                        the ice cream and Manhattan distance being calculated
                        for the cone)";
      #               "Raise the horizontal distance to the determined power";
      YR-zP#          "Calculate the vertical distance from the center and
                       raise it to the determined power";
      +               "Add the horizontal and vertical distances";
      Z2./P#          "Calculate the solid distance threshold and raise it to
                       the determined power";
      >SP?            "If the solid threshold is exceeded, produce a space;
                       otherwise, produce the determined power digit
                       (This results in ice cream being represented by the
                        digit '2' and the cone by the digit '1')";
    }/              "End x loop";
    N               "Produce a new line";
  }fY             "End y loop";
}               "End block";
\$\endgroup\$
  • \$\begingroup\$ This appears to use 2's and 1's instead of ('s and V's ? \$\endgroup\$ – Mark Reed Mar 2 '15 at 22:54
  • \$\begingroup\$ @MarkReed This is allowed. Last line in the details section. \$\endgroup\$ – Jakube Mar 2 '15 at 23:01
3
\$\begingroup\$

inca2 129 123 121 111 107

This mostly uses the formulas from the python example, but using jot-dots and iotas instead of double-looping. The i function performs the circular test for the j function which invokes jot-dot upon it. And the k function performs the triangle test for the l function. The c function catenates the results of j and l and reshapes it to N×N.

edit: -6 combine 2 maps into 1.
edit: -2 remove useless ravels.
edit: nicer typescript.
edit: -10 apply repeated expression array-wise.
edit: -4 factor out repeated expression as a function.
edit: line-by-line commentary.

q:y-(n-1)%2
i:[((n%2)^2)>+/(qx y)^2
j:(~[y%2)i.(~y)
k:2*[x>[|qy
l:(@1+~]y%2)k.(~y)
c:y y#((jn<y),ly){' (V' 

In more detail, the entry-point is the c function which takes one argument implicitly named y.

c:y y#((jn<y),ly){' (V' 
         n<y            } assign y to 'n'
        jn<y            } call j(y)
              ly        } call l(y)
      ((    ),  )       } catenate the results
      (         ){' (V' } map 0 1 2 to ' ' '(' 'V'
  y y#                  } reshape to NxN

The j function receives the same input value as its y parameter.

j:(~[y%2)i.(~y)
     y%2         } y divided by 2
    [            } floor
   ~             } iota. this generates the row indices 0..y/2
            ~y   } iota y. this generates the column indices 0..y
  (     )i.(  )  } jot-dot with the function i

The jot-dot here does the double-loop. It calls the i function with every combination of elements from the left and right arrays (0..n/2 and 0..n). So the i function receives as x the y index of the table, and it receives as y the x index. The names got a little backwards here :).

i:[((n%2)^2)>+/(qx y)^2
     n%2                 } n divided by 2
    (n%2)^2              } squared
                 x y     } make a 2-element array (x,y)
                qx y     } call q on this array

where q does

q:y-(n-1)%2
     n-1    } n minus 1
         %2 } divided by 2
  y-        } y minus that

back to i

i:[((n%2)^2)>+/(qx y)^2
               (    )^2  } square the result from q(x,y)
             +/          } sum the two numbers
            >            } compare the left side (above) with the right (=> 0/1)
  [                      } floor

The floor should not be necessary. But apparently there's a bug in the interpreter.

The l function works similarly to the j function, using a jot-dot.

l:(@1+~]y%2)k.(~y)
        y%2         } y divided by 2
       ]            } ceiling
      ~             } iota 0..ceil(y/2)-1
    1+              } add 1 => 1..ceil(y/2)
   @                } reverse => ceil(y/2)..1
               ~y   } iota y  0..y-1
  (        )k.(  )  } jot-dot using k

The k function yields a boolean scaled by 2 so the values can be distinguished from the ice cream values later on, in the mapping.

k:2*[x>[|qy
     x       } k's left arg
         qy  } y-(n-1)%2
        |    } abs
       [     } floor
     x       } left-hand-side again
      >      } compare 
    [        } floor (should be unnecessary)
  2*         } scale by 2

In action (piping through tr to remove tab chars which are the REPL's prompt):

josh@Z1 ~/inca
$ ./inca2 <icecream | tr -d '\t'

c1
V

c2
((
VV

c3
(((
VVV
 V 

c4
 (( 
((((
VVVV
 VV 

c5
 ((( 
(((((
VVVVV
 VVV 
  V  

josh@Z1 ~/inca
$ 
\$\endgroup\$
2
\$\begingroup\$

Python 2, 193 192

Does not use strings, only math

N=input()
R=(N+1)/2;r=range(R)
s=lambda L,U:(10**U-10**L)/9
f=lambda N,m:s(0,N)+s(m,N-m)
g=lambda N,m:s(0,N)+s(m,N-m)*6
for i in r[1:]:print f(N,int(R-(2*R*i-i*i)**.5))
for i in r:print g(N,i)

s(L,U) returns a number of the form "U-digits with the rightmost L zeros and the rest ones"
f(N,m) returns an N-digit number with the inner section of 2 and an m-wide border of 1on each side
g(N,m) does the same, but using 7 for the 'colour' of the inner section since it matches the texture of the cone more closely

Output

N=8         N=9
11122111    112222211
12222221    122222221
22222222    222222222
22222222    222222222
77777777    777777777
17777771    177777771
11777711    117777711
11177111    111777111
            111171111
\$\endgroup\$
  • \$\begingroup\$ Very unique way to do it :) \$\endgroup\$ – Calvin's Hobbies Mar 4 '15 at 14:13
  • \$\begingroup\$ If only we can see the ice cream too :P \$\endgroup\$ – Optimizer Mar 4 '15 at 14:22
2
\$\begingroup\$

Perl 6, 175

Pretty straightforward implementation without much golfing, just extraneous whitespace/punctuation elimination:

sub MAIN($d){my$r=($d/2).Int;for 1..$r ->$n
{my$y=$n-$r;my$h=sqrt($r*$r-$y*$y).Int;my$w=2*$h+$d%2;say
' 'x($r-$h)~'('x$w};for 1..($d-$r) ->$y {say ' 'x($y-1)~'V'x($d-2*$y+2)}}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.