39
\$\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\$
5
  • 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, 2016 at 2:35
  • 2
    \$\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, 2016 at 2:38
  • 2
    \$\begingroup\$ Define "shape similar to a lemon or lime" \$\endgroup\$ Aug 11, 2016 at 5:49
  • 8
    \$\begingroup\$ @PeterTaylor The shape shown by the examples. Is there honestly an input string you can't infer the output for? \$\endgroup\$ Aug 11, 2016 at 8:45
  • 8
    \$\begingroup\$ I shouldn't have to infer anything: the question should have a specification. \$\endgroup\$ Aug 11, 2016 at 9:53

17 Answers 17

13
\$\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\$
3
  • \$\begingroup\$ Oh, cool idea! Unfortunately my old version does not have flip :/ \$\endgroup\$
    – flawr
    Aug 10, 2016 at 23:05
  • \$\begingroup\$ I tested your 124-byte code on R2015b and I confirm it works \$\endgroup\$
    – Luis Mendo
    Aug 10, 2016 at 23:14
  • \$\begingroup\$ ​Tha​n​k​ ​y​o​u!​​ \$\endgroup\$
    – flawr
    Aug 10, 2016 at 23:16
7
\$\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\$
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\$
6
  • \$\begingroup\$ One thing that pops out is that you could compact the first two lines to l=len(input()), no? \$\endgroup\$
    – Frank
    Aug 11, 2016 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, 2016 at 2:14
  • \$\begingroup\$ Python 2 can get 112 or 116 bytes using a slightly different choice for R. \$\endgroup\$
    – Lynn
    Aug 11, 2016 at 16:10
  • \$\begingroup\$ Ah, I didn't catch that one, sorry. \$\endgroup\$
    – Frank
    Aug 11, 2016 at 17:13
  • \$\begingroup\$ @Lynn Oh wow, that choice or R does make the code a lot neater! \$\endgroup\$
    – Sp3000
    Aug 13, 2016 at 7:21
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\$
0
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\$
1
\$\begingroup\$

J, 67 bytes

[:;"1@|:(#-h){.&.>"0 1]((<#)#&.>,:&''@]<@{"{~2|[)~[:+/~h=.|@i:@<:@#

Try it online!

I may try to improve this further tomorrow.

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

PowerShell, 116 bytes

($r=0..($n=($a=$args).count-1)+$n..0|gu)|%{$y=$_;-join($r|%{($a[0..$_],(' '*($_+1)))[($_+$y+$n)%2-or($_+$y)-lt$n]})}

Try it online!

Unrolled:

$a=$args
$n=$a.count-1
$range=0..$n+$n..0|Get-Unique
$range|%{
    $y=$_
    $line=-join(
        $range|%{
            $word=$a[0..$_]
            $space=' '*($_+1)
            $switch=($_+$y+$n)%2-or($_+$y)-lt$n
            ($word,$space)[$switch]
        }
    )
    $line
}
\$\endgroup\$
1
\$\begingroup\$

J, 49 bytes

3 :';"{((]<@{.y''''&[~2&|@+<:>)"+/e&-)|i:1-e=.#y'

Try it online!

How it works

3 :';"{((]<@{.y''''&[~2&|@+<:>)"+/e&-)|i:1-e=.#y'

3 :'...'       Explicit function definition; right arg(y) = given string
|i:1-e=.#y     e = length of y; create array of [e-1 .. 0 .. e-1]

((]<@{.y''&[~2&|@+<:>)"+/e&-)  Create boxed lemon shape:
                         e&-   Create array of [1 .. e .. 1]
 (                   )"+/      Outer product with [e-1 .. 0 .. e-1]
                               (left item = a, right item = b)
             2&|@+<:>          (a+b)%2 <= (a>b)
       y''&[~                  If above is true, use '' (empty string)
                               otherwise use y
  ]  {.                        Take first b chars from above
                               (fill with blanks if needed)
   <@                          Box it

;"{      Unbox and concatenate each row from the table (outer product)
         Result is the matrix of chars, giving the lemon shape
\$\endgroup\$
1
  • \$\begingroup\$ 3 :';"1((]<@{.y#~><2|+)"0/#@y-])|i:1-#y' seems to work \$\endgroup\$
    – FrownyFrog
    Feb 7, 2020 at 6:02
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\$
1
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\$
1
0
\$\begingroup\$

05AB1E, 27 26 bytes

ηεN>иygðש.ýIgN-<®и.ø}ûøJ»

Try it online or verify all test cases.

Explanation:

η           # Get a list of prefixes of the (implicit) input-String
 ε          # Map each prefix `y` to:
  N>        #  Get the (0-based) map-index, and increase it by 1 to make it 1-based
    и       #  Repeat the current substring that many times as list
  yg        #  Push prefix `y` again, and pop and push its length
    ð×      #  Create a string of that many spaces
      ©     #  Store this spaces-string in variable `®` (without popping)
       .ý   #  Intersperse the earlier list with this spaces-string
  Ig        #  Push the input, and then pop and push its length
    N-      #  Subtract the (0-based) map-index
      <     #  And decrease it by 1 more
       ®и   #  Repeat spaces-string `®` that many times as list
         .ø #  Surround the earlier list with this list as both leading and trailing portion
 }û         # After the map: palindromize (abc → abcba) the entire list of lists
   ø        # Zip/transpose; swapping rows/columns
    J       # Join each inner list together to a single string
     »      # And join those strings by newlines
            # (after which the result is output implicitly)
\$\endgroup\$
0
\$\begingroup\$

JavaScript (Node.js), 120 118 109 105 bytes

x=>(l=x.length,g=(F,i=1,w=F(i))=>i<l?w+g(F,i+1)+w:w)(y=>g(a=>a+y+l&a+y>l?x.slice(0,a):" ".repeat(a))+`
`)

Try it online!

A bunch of bytes are shaved thanks to the similar structures of the nesting functions. I was confident that this golf could save some bytes but not that much.

x=>(                   // Main function:
 l=x.length,           //  l = Length of x
 g=(                   //  Nesting function:
  F,                   //   Output-generating function
  i=1,                 //   Counter (initially 1)
  w=F(i)               //   The output at that counter value
 )=>
  i<l                  //   If not the center line/block:
  ?w+g(F,i+1)+w        //    Sandwich next iteration with output
  :w                   //   Otherwise: Return the output
)(                     //  Call the nesting function with
 y=>                   //  Outer nest: Generating lines
  g(                   //   Call the nesting function with
   a=>                 //   Inner nest: Generating blocks
    a+y+l&a+y>l        //    If the position should not be space:
    ?x.slice(0,a)      //     Output the first a characters of x
    :" ".repeat(a)     //    Otherwise: Output a spaces
  )+"\n"               //   Append the line with a newline
)

Original 118-byte answers:

F=(x,i=1,t=x.length,w=(G=(j,A,B,c=i+j+t&1&i+j>t?A:B)=>j<t?c+G(j+1,A+x[j],B+' ')+c:c)(0,'','')+`
`)=>i<t?w+F(x,i+1)+w:w

Try it online!

F=(x,i=1,t=x.length,w=(G=(j,c=i+j+t&1&i+j>t?x.slice(0,j):" ".repeat(j))=>j<t?c+G(j+1)+c:c)(1)+`
`)=>i<t?w+F(x,i+1)+w:w

Try it online!

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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