34
\$\begingroup\$

Write a program or function that takes in a nonempty single-line string. You may assume it only contains printable ASCII excluding space.

Print or return an ASCII art lozenge shape similar to a lemon or lime made from the prefixes of the string.

Suppose the input string is n letters long. Then, such a shape consists of 2n − 1 columns of ASCII art stitched together, each consisting of 2n − 1 lines. Counting from 1, the k-th column is f(k) = min(k, 2n − k) characters wide, and contains f(k) copies of the first f(k) characters of input, centered vertically, with single blank lines separating the copies.

For example, if the input is Lemon, the output should be:

          Lemon
      Lemo     Lemo
   Lem    Lemon    Lem
 Le   Lemo     Lemo   Le
L  Lem    Lemon    Lem  L
 Le   Lemo     Lemo   Le
   Lem    Lemon    Lem
      Lemo     Lemo
          Lemon

If the input is lime the output should be:

      lime
   lim    lim
 li   lime   li
l  lim    lim  l
 li   lime   li
   lim    lim
      lime

And the same pattern is followed for other inputs:

a

a

Be

 Be
B  B
 Be

/\

 /\
/  /
 /\

cat

   cat
 ca   ca
c  cat  c
 ca   ca
   cat

|||

   |||
 ||   ||
|  |||  |
 ||   ||
   |||

.__.

      .__.
   .__    .__
 ._   .__.   ._
.  .__    .__  . 
 ._   .__.   ._
   .__    .__
      .__.

$tring

               $tring
          $trin      $trin
      $tri     $tring     $tri
   $tr    $trin      $trin    $tr
 $t   $tri     $tring     $tri   $t
$  $tr    $trin      $trin    $tr  $
 $t   $tri     $tring     $tri   $t
   $tr    $trin      $trin    $tr
      $tri     $tring     $tri
          $trin      $trin
               $tring

Lines in the output may have trailing spaces and there may be one optional trailing newline.

The shortest code in bytes wins.

\$\endgroup\$
  • 13
    \$\begingroup\$ I was surprised that you only used prefixes - I was expecting prefixes on the left and suffixes on the right! \$\endgroup\$ – Neil Aug 11 '16 at 2:35
  • 1
    \$\begingroup\$ (Actually from a coding POV I would have preferred suffixes throughout but you can't have your cake and eat it.) \$\endgroup\$ – Neil Aug 11 '16 at 2:38
  • 2
    \$\begingroup\$ Define "shape similar to a lemon or lime" \$\endgroup\$ – Peter Taylor Aug 11 '16 at 5:49
  • 6
    \$\begingroup\$ @PeterTaylor The shape shown by the examples. Is there honestly an input string you can't infer the output for? \$\endgroup\$ – Calvin's Hobbies Aug 11 '16 at 8:45
  • 6
    \$\begingroup\$ I shouldn't have to infer anything: the question should have a specification. \$\endgroup\$ – Peter Taylor Aug 11 '16 at 9:53

12 Answers 12

11
\$\begingroup\$

Matlab, 140 136 128 124 bytes

Basically first starts with the middle section, and then prepends/appends the shortened/modified versions step by step.

a=input('');v=ones(nnz(a)*2-1,1)*a;v(2:2:end,:)=0;b=v;for k=a;v=v(2:end,1:end-1);v(end+1,:)=0;b=[v,b,v,''];end;b(~flip(b))=0

Thanks for 8 bytes @LuisMendo!

E.g. for MATLAB we get:

               MATLAB               
          MATLA      MATLA          
      MATL     MATLAB     MATL      
   MAT    MATLA      MATLA    MAT   
 MA   MATL     MATLAB     MATL   MA 
M  MAT    MATLA      MATLA    MAT  M
 MA   MATL     MATLAB     MATL   MA 
   MAT    MATLA      MATLA    MAT   
      MATL     MATLAB     MATL      
          MATLA      MATLA          
               MATLAB                    
\$\endgroup\$
  • \$\begingroup\$ Oh, cool idea! Unfortunately my old version does not have flip :/ \$\endgroup\$ – flawr Aug 10 '16 at 23:05
  • \$\begingroup\$ I tested your 124-byte code on R2015b and I confirm it works \$\endgroup\$ – Luis Mendo Aug 10 '16 at 23:14
  • \$\begingroup\$ ​Tha​n​k​ ​y​o​u!​​ \$\endgroup\$ – flawr Aug 10 '16 at 23:16
7
\$\begingroup\$

Python 2, 121 110 bytes

s=input()
n=len(s)
r=range(1,n)+range(n,0,-1)
for y in r:print''.join(s[:(x+y-n&(x+y>n))*x]or' '*x for x in r)

116 bytes if using raw_input. The program essentially does a mask based on L1-norm/Manhattan distance from the centre, as well as the parity of this distance compared to the parity of the input length.

(Thanks to @Lynn for -9 bytes and paving the way for 2 more)

\$\endgroup\$
  • \$\begingroup\$ One thing that pops out is that you could compact the first two lines to l=len(input()), no? \$\endgroup\$ – Frank Aug 11 '16 at 1:45
  • \$\begingroup\$ @Frank s is used at the end of the long line, so unfortunately that's not possible \$\endgroup\$ – Sp3000 Aug 11 '16 at 2:14
  • \$\begingroup\$ Python 2 can get 112 or 116 bytes using a slightly different choice for R. \$\endgroup\$ – Lynn Aug 11 '16 at 16:10
  • \$\begingroup\$ Ah, I didn't catch that one, sorry. \$\endgroup\$ – Frank Aug 11 '16 at 17:13
  • \$\begingroup\$ @Lynn Oh wow, that choice or R does make the code a lot neater! \$\endgroup\$ – Sp3000 Aug 13 '16 at 7:21
6
\$\begingroup\$

MATL, 44 bytes

I took some inspiration from @flawr's answer (although the algorithm is not the same)

GtnEq:!g*2Mo*XKG"K1YS3LZ)OX@:Y(PO5MY(XKwyhhc

Input is a string with single quotes.

Try it online!

\$\endgroup\$
6
\$\begingroup\$

JavaScript (ES6), 132 bytes

s=>{x=' '.repeat(l=s.length);for(n=r='';n++<l;r=r?t+`
${r}
`+t:t)for(i=l,t='';i;t=t?w+t+w:w)w=(i<n|n+i&1?x:s).slice(0,i--);return r}

Test

var solution =

s=>{
  x=' '.repeat(l=s.length);
  for(n=r='';n++<l;r=r?t+`\n${r}\n`+t:t)
    for(i=l,t='';i;t=t?w+t+w:w)
      w=(i<n|n+i&1?x:s).slice(0,i--);
  return r
}

result.textContent = solution('Lemon');
<input type="text" id="input" value="Lemon" oninput="result.textContent=solution(this.value)" /><pre id="result"></pre>

\$\endgroup\$
5
\$\begingroup\$

Pyth, 32 bytes

jsMCm.[tylztsmC*\ dd*;ld+J._zt_J

Demonstration

\$\endgroup\$
5
\$\begingroup\$

Jelly, 32 26 bytes

³L_+«0ị“~ ”«³ḣ
JµṖ;Ṛç@þ`j⁷

Try it online!

EDIT: Dennis saved 6 bytes. Thanks!

\$\endgroup\$
2
\$\begingroup\$

JavaScript, 187 178 bytes

A bitwise approach. Function m defines a mask by starting at 2 ** length, e.g. 00100 in binary, and defining m(n) = m(n-1) << 1 | m(n-1) >> 1 for the first half. Interestingly the second half can be defined as m(n) = m(n-1) << 1 & m(n-1) >> 1. (though the program instead opts to define m(n) = m(2 * length - 1) for the second half) From here these masks can be used to determine whether a word or space should appear by checking 2 ** column & m(row). Of course in JavaScript it's shorter to write 2 ** something with 1 << something...

note: written while tired. May Almost surely does have mistakes.

s=>{m=n=>n?n>l?m(2*l-n):(p=m(n-1))>>1|p<<1:1<<l
for(r=0;r/2<=(l=s.length-1);r++){for(i=1,o="";i/2-1<l;i++)o+=(1<<i-1&m(r)?s:" ".repeat(i)).slice(0,i>l?2*l+2-i:i)
console.log(o)}}
\$\endgroup\$
2
\$\begingroup\$

Haskell, 109 bytes

f s|n<-length s,r<-[1..n]++[n-1,n-2..1]=unlines[do x<-r;min(" ~"!!mod((x+y+n)*min(n-x-y)0)2)<$>take x s|y<-r]
\$\endgroup\$
2
\$\begingroup\$

Brachylog, 46 bytes

{a₀⟨{;Ṣ}j₎l⟩}ᶠL&l;Ṣj₍ẹa₁ᶠ;Lz{czzcᵐ}ᵐ⟨kc↔⟩zcᵐ~ṇ

Try it online!

Terrible byte count and probably worse approach (not to mention Brachylog isn't exactly designed for ASCII art), but I wasted enough time on it to post it anyways.

              L    The variable L
{           }ᶠ     is a list containing every possible
 a₀                prefix of
                   the input
    {;Ṣ}           paired with a space
        j          and concatenated with itself
   ⟨     ₎l⟩       a number of times equal to its length.
          ᶠ    A list containing every possible
        a₁     suffix of
   Ṣ           a space
    j          concatenated with itself
  ;  ₍         a number of times equal to
 l             the length of
&              the input
      ẹ        then split back up into its elements
               is an important list which doesn't actually get a name.
                         That list
;Lz                      zipped with L
   {     }ᵐ              with each pair being
    c                    concatenated,
     z                   zipped with cycling,
      z                  zipped back,
        ᵐ                and subjected to each of its elements being
       c                 concatenated itself,
           ⟨kc↔⟩         then palindromized
                z        and zipped yet again
                 cᵐ      with every line concatenated once more
                   ~ṇ    and finally joined on newlines
                         is the output.

Just about the only clever part of any of this is the use of a₁ to generate the vertical spaces largest-first while a₀ generates the word prefixes smallest-first, and zz to expand single spaces into blocks of space matching the widths of the prefixes.

\$\endgroup\$
1
\$\begingroup\$

TSQL, 259 bytes

Golfed:

DECLARE @ VARCHAR(30)='TSQL'

,@o VARCHAR(max),@i INT=0,@j INT,@t VARCHAR(max)SET @j=LEN(@)z:WHILE @i<LEN(@)SELECT @o=x+ISNULL(@o+x,''),@i+=1FROM(SELECT LEFT(IIF((@j-@i)%2=1,@,SPACE(99)),LEN(@)-@i)x)z SELECT @j-=1,@t=@o+ISNULL(CHAR(10)+@t+CHAR(10)+@o,''),@o=null,@i=0IF @j>0GOTO z PRINT @t

Ungolfed:

DECLARE @ VARCHAR(30)='TSQL'

,@o VARCHAR(max),@i INT=0,@j INT,@t VARCHAR(max)SET @j=LEN(@)
z:
WHILE @i<LEN(@)
  SELECT @o=x+ISNULL(@o+x,''),@i+=1
  FROM(SELECT LEFT(IIF((@j-@i)%2=1,@,SPACE(99)),LEN(@)-@i)x)z
SELECT @j-=1,@t=@o+ISNULL(CHAR(10)+@t+CHAR(10)+@o,''),@o=null,@i=0
IF @j>0 GOTO z

PRINT @t

Fiddle

\$\endgroup\$
0
\$\begingroup\$

C, 167 bytes

This program expects the input text to be passed as the first parameter to the program (via command line or however else) and will write the output to stdout.

int i,j,k,l,v;main(h,s)char**s;{h=strlen(s[1]);l=h*2;for(;++i<l;puts(""))for(j=0;++j<l,v=j<h?j:l-j;)for(k=0;k++<v;putchar((i+j+h%2)%2&&v>h-(i<h?i:l-i)?s[1][k-1]:32));}

This is my first attempt at code golf here as it seemed like a reasonable challenge, so it can probably be golfed more than I was able to just due to how I did it.

Explanation

/* Static variables
   i - "Row" number
   j - "Column" number
   k - String character counter
   l - Double length of the input string
   v - Inverted column distance from center */
int i,j,k,l,v;

/* Main parameters
   h - (argc) Input string length
   s - argv */
main(h, s)
char**s;
{
  /* Assign the input string length and double length */

  h = strlen(s[1]);
  l = h * 2;

  /* Display content */

    /* Loop over rows l - 1 times and put a newline after each */
  for (; ++i < l; puts(""))
      /* Loop over columns l - 1 times and set the inverted column
         distance each time */
    for (j = 0; ++j < l, v = ((j < h) ? j : l - j);)
        /* Loop over characters up to the inverted column distance from the
           center (this generates the pattern of output lengths needed) */
      for (k = 0; k++ < v;)
        putchar(
            /* Check for if the current row + column (with an offset based on
               the input parity) parity is even or odd, creating the needed
               checkerboard pattern */
          (i + j + h % 2) % 2 &&
            /* If the inverted column distance from the center is more than the
               row distance from the center, then the cell is inside the
               circular shape */
          v > (h - ((i < h) ? i : l - i)) ?
              /* Display the requested character (minus one for 0 based) */
            s[1][k-1] :
            32 /* Otherwise display a space (ASCII 32) */
        );
}

It is significant enough to note the usage of (n < m) ? n : (m * 2) - n in the program at least twice to get the inverted distance from a center position m on a range of m * 2 with the input n. If there is a shorter way to do that then it could be golfed down some more easily as that algorithm is important for how this program works.

\$\endgroup\$
0
\$\begingroup\$

C, 137 bytes

x,y,w;main(l,v)char**v;{for(y=l=strlen(v[1]);-l<--y;putchar(10))for(x=l;-l<--x;printf("%*.*s",w,w,x+y+l&1&&w>abs(y)?v[1]:""))w=l-abs(x);}

Breakdown:

This draws every element of the 2n-1 x 2n-1 grid, with a mask function deciding whether the current element should be blank space or the input word (the mask checks for a diamond shape and checkerboard pattern).

x,y,w;
main(l,v)char**v;{
    for(y=l=strlen(v[1]);-l<--y;/*...*/)    // row loop (count down to save bytes)
        for(x=l;-l<--x;/*...*/)             // column loop
            w=l-abs(x);                     // calculate current word's width
            printf("%*.*s",                 // print...
                w,w,                        // ...with min & max width...
                x+y+l&1&&w>abs(y)           // Check mask:
                    ?v[1]                   //  ...word
                    :"")                    //  ...or blank space
        putchar(10)                         // Newline
}
\$\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.