71
\$\begingroup\$

Thanks to @KritixiLithos for helping me out with this challenge!


V is a programming language that I wrote so that I could use and extend vim for code-golf challenges. The very first commit was on March 3rd, 2016, meaning that today V turns one year old! Woo-hoo

Over V's first year of existence, there have been 176 commits from four different contributors, 140 answers from 12 different users, and too many broken duplicate operators to count. It has an online interpreter, generously hosted by @Dennis, which has been run almost 8,000 times since December.

Let's have a challenge to celebrate V's birthday! Since most features in V are designed with string manipulation and in mind, it just seems natural that any challenge celebrating V should be about ascii art. So your challenge for today is to take a word as input, and reshape that word in the shape of a V. For example, the input "Hello" should give the following V:

Hello         olleH
 Hello       olleH
  Hello     olleH
   Hello   olleH
    Hello olleH
     HellolleH
      HellleH
       HeleH
        HeH
         H

Here are some details about what your V should look like. If the input string is n characters long, the V should be n*2 lines tall. The very first line should consist of:

<input string><(n*2) - 1 spaces><input string reversed>

On each new line, one space is added to the beginning, and the two sides of the string move towards each other, removing any overlapping characters. Until the very last line, which is just the first character of input. Trailing whitespace on each line is acceptable, and a trailing newline is allowed too.

You can assume that the input will always be printable ASCII without any whitespace in it, and you may take input and output in any reasonable method. Here are some more sample inputs:

Happy:

Happy         yppaH
 Happy       yppaH
  Happy     yppaH
   Happy   yppaH
    Happy yppaH
     HappyppaH
      HapppaH
       HapaH
        HaH
         H

Birthday:

Birthday               yadhtriB
 Birthday             yadhtriB
  Birthday           yadhtriB
   Birthday         yadhtriB
    Birthday       yadhtriB
     Birthday     yadhtriB
      Birthday   yadhtriB
       Birthday yadhtriB
        BirthdayadhtriB
         BirthdadhtriB
          BirthdhtriB
           BirthtriB
            BirtriB
             BiriB
              BiB
               B

V!:

V!   !V
 V! !V
  V!V
   V

~:

~ ~
 ~

Of course, since this is , standard loopholes are banned and your goal is to write the shortest possible program to complete this task. Happy golfing!


For what it's worth, I have a soft spot for vim answers, so imaginary bonus points for using vim or V, although any language is acceptable. :)

\$\endgroup\$
  • \$\begingroup\$ Can I print a single null character (0x00) after every newline? \$\endgroup\$ – Sriotchilism O'Zaic Mar 3 '17 at 0:24
  • \$\begingroup\$ @wheatwizard Hmm. It's a little weird, but I guess that's fine as long as the output is visually same. \$\endgroup\$ – DJMcMayhem Mar 3 '17 at 0:36
  • 21
    \$\begingroup\$ The 5th birthday will be something else! (In roman numerals) \$\endgroup\$ – Albert Renshaw Mar 3 '17 at 10:57
  • 5
    \$\begingroup\$ Best wishes to the V language by the Vee :-) \$\endgroup\$ – The Vee Mar 6 '17 at 9:46

40 Answers 40

44
\$\begingroup\$

MATL, 21 14 bytes

MATL wishes V a happy birthday!

tnEXyY+c3MZvZ)

Try it online!

Explanation

Consider the input

'Hello'

of length n=5. The code computes the 2D convolution of this string with the identity matrix of size 2*n,

[1 0 0 0 0 0 0 0 0 0;
 0 1 0 0 0 0 0 0 0 0;
 0 0 1 0 0 0 0 0 0 0;
 0 0 0 1 0 0 0 0 0 0;
 0 0 0 0 1 0 0 0 0 0;
 0 0 0 0 0 1 0 0 0 0;
 0 0 0 0 0 0 1 0 0 0;
 0 0 0 0 0 0 0 1 0 0;
 0 0 0 0 0 0 0 0 1 0;
 0 0 0 0 0 0 0 0 0 1]

The result of the convolution, converted to char and with char 0 shown as space, is

['Hello         ';
 ' Hello        ';
 '  Hello       ';
 '   Hello      ';
 '    Hello     ';
 '     Hello    ';
 '      Hello   ';
 '       Hello  ';
 '        Hello ';
 '         Hello']

Then the columns [1, 2, ..., 2*n-1, 2*n, 2*n-1, ..., 2, 1] are selected from this char matrix, producing the desired result:

['Hello         olleH';
 ' Hello       olleH ';
 '  Hello     olleH  ';
 '   Hello   olleH   ';
 '    Hello olleH    ';
 '     HellolleH     ';
 '      HellleH      ';
 '       HeleH       ';
 '        HeH        ';
 '         H         ']

Commented code

t      % Implicitly input string. Duplicate
nE     % Length, say n. Multiply by 2
Xy     % Identity matrix of that size
Y+     % 2D convolution. This converts chars to ASCII codes
c      % Convert to char
3M     % Push 2*n, again
Zv     % Push symmetric range [1, 2, ..., 2*n, 2*n-1, ..., 1]
Z)     % Apply as column indices. This reflects the first 2*n columns
       % symmetrically, and removes the rest. Implicitly display
\$\endgroup\$
  • \$\begingroup\$ Very interesting approach! +1 \$\endgroup\$ – seshoumara Mar 3 '17 at 19:42
  • 3
    \$\begingroup\$ @seshoumara Thanks! As flawr says, convolution is the key to success :-) \$\endgroup\$ – Luis Mendo Mar 3 '17 at 20:49
38
\$\begingroup\$

V, 24, 23, 20 bytes

3Ù2Ò Íî
Xæ$òâÙHãêxx>

Try it online!

Much shorter now that V has a 'reverse' operator.

Not that impressive compared to the other golfing languages that have answered, but it had to be done. Hexdump:

00000000: 33d9 32d2 20cd ee0a 58e6 24f2 e2d9 48e3  3.2. ...X.$...H.
00000010: ea78 783e                                .xx>

Explanation:

3Ù                  " Make three extra copies of this current line
  2Ò                " Replace each character on this line and the next line with spaces
     Íî             " Join all lines together
X                   " Delete one space
 æ$                 " Reverse the word under the cursor

At this point, the buffer looks like this:

Happy         yppaH

No, we'll recursively build the triangle down.

ò                   " Recursively:
 â                  "   Break if there is only one non-whitespace character on this line
  Ù                 "   Make a copy of this line
   H                "   Move to the first line
    ã               "   Move to the center of this line
     ê              "   Move to this column on the last line
      xx            "   Delete two characters
        >           "   Indent this line

Here is where I get to show off one of my favorite features of V. Lots of commands require an argument. For example, the > command will indent a variable number of lines depending on the argument:

>>    " Indent this line (this command is actually a synonym for '>_')
>j    " Indent this line and the line below
>k    " Indent this line and the line above
6>>   " Indent 6 lines
>}    " Indent to the end of this paragraph
>G    " Indent to the last line
...   " Many many many more

but most commands will be forced to end with a default argument (usually the current line) if it is at the end of the program and not specified. For example, what V actually runs for our recursive loop is:

òâÙHãêxx>>ò

The second ò is implicitly filled in. The cool thing is that implicitly ended commands apply several layers deep, so even though we only wrote >, V will implicitly give _ for it's argument, and it will indent the current line.

\$\endgroup\$
  • \$\begingroup\$ I was working on it, but I think it's more fitting for you to answer! \$\endgroup\$ – nmjcman101 Mar 3 '17 at 2:33
29
\$\begingroup\$

Brainfuck, 152 bytes

This is such a momentous occasion, I decided to crack out the ol' BF interpreter and give this a spin.

++++++++++[->+>+++<<]>>++>>+>>>,[[<]<<+>>>[>],]<[<]<<-[->+>>[>]>++++[-<++++++++>]<[<]<<]>[->++<]>[-<+>]<[<[-<+<.>>]<[->+<]>+>->>[.>]<[-]<[.<]<<<<<.>>>>]

With Comments

++++++++++
[->+>+++<<] Insert 0 into the first buffer (Which we don't care about) 10 into the second and 30 into the thrd
>>++    Raise the third buffer to 32 making us our space
>   This buffer is reserved for the Insertable spaces counter
>
+>>>    Raise our incrementer This will be used to fill the other half of the string with spaces
,[  Read a byte
    [<]<<   Move to the back of the string buffer which is our incrementer
    +       increment it
    >>>[>]      And move to the next space of the string
    ,       And then read a new byte
]
<[<]<<-     Decrement the incrementer and begin to add spaces
[
    -       Decrement the incrementer
    >+      Raise the incrementer in the padding
    >>[>]   Move to a new part of the string buffer
    >++++[-<++++++++>]< Write a space
    [<]<<   Move all the way back to the string counter
]
BEGIN WRITING!!
>
[->++<]>[-<+>]<Double the incrementer
[
    <[  Move to the space counter
        -<+<.>> Decrement the space counter increment the temporary one to the left of it then print the space we stored to the left of that then return
    ]<[->+<]>+> Move the temporary space counter back
    -   Decrement the incrementer
    >>[.>]  Print every character from left to right
    <[-]    Snip the end off this
    <[.<]   Print every character from right to left
    <   Move back ot the incrementer
    <<<<.>>>> Print a newline aswell
]

Try it online!

\$\endgroup\$
23
\$\begingroup\$

><>, 221 bytes

I spent way too much time on this. Happy birthday, V!

l:2*01           p84*/v
 !@:$-1         /!?:$<
  1.v/ ^       v\~~>a
   vv\}o<     >ao  /
    1\/84/   :}o:$-
     \\!?<: l;!?\v
      p10-1:g10r\
       >  :>?\vv
        v:$-1/~
         </r+*
          </~
           l

You can try it online, but it's a lot more fun to get this interpreter and run it using the --play flag

python3 fish.py v.fish -s "ppcg" --tick 0.05 --play

which results in the animation below.

Example

Example fish run

(it takes a little under two minutes)

Explanation

Because the interesting part of this answer is wrapping it in the V shape, here is an explanation that conforms to it. We use following line-numbered version for reference.

1. l:2*01           p84*/v
2.  !@:$-1         /!?:$<
3.   1.v/ ^       v\~~>a
4.    vv\}o<     >ao  /
5.     1\/84/   :}o:$-
6.      \\!?<: l;!?\v
7.       p10-1:g10r\
8.        >  :>?\vv
9.         v:$-1/~
10.         </r+*
11.          </~
12.           l

Sometimes arrows (→↓←) are used to indicate the direction in which a snippet is reached.

  1. Initialisation

       1.→l:2*01           p84*/v
       2.  !@:$-1   X     /!?:$<
       3.   1.            \~~>a
    

    The first line will push 2n to [0,1], leave n on the stack and append one space. Next, we go up and wrap around to the second line on the right, where we will start going left. There is a loop for appending n + 1 spaces. This works as follows.

                    Initial:                 "ppcg4 "
    !@:$-1 /!?:$<
               $     Swap.                   "ppcg 4"
              :      Duplicate.              "ppcg 44"
             ?       If more spaces to add:
        -1            Subtract 1.            "ppcg 3"
       $              Swap.                  "ppcg3 "
      :               Duplicate.             "ppcg3  "
     @                Rotate top 3.          "ppcg 3 "
    !                 Jump over stored value
                             and wrap around.
                    Else:
            /         Go to next part.
    

    After this is finished, it bounces down to line 3. There the top two stack elements (0 and a space) are removed (~~) and we jump to the X at location [10,1] (a1.), continuing rightwards. We bump up at the /, wrap around to line 7 and start the main program loop.

  2. Main loop (2n times do)

     6.              ;!?\
     7.       p10-1:g10r\   ←
    

    This is the loop condition. At first, the stack is reversed for printing. Then we get the counter from [1,0] (01g) and store a decremented version (:1-01p). By wrapping around and bumping up and right, we encounter the conditional for terminating the program. If we don't terminate, we jump into the first printing loop.

    • First printing loop (left half)

      5.    1\   /   :}o:$-
      6.     \\!?<: l         ←
      

      We start with the length on top of the stack and execute the following code as long as the top element is not 0.

      1-$:o}
      
      1-        Subtract 1.    "ppcg3"
        $       Swap.          "ppc3g"
         :      Duplicate.     "ppc3gg"
          o     Output.        "ppc3g"
           }    Rotate right.  "gppc3"
      

      This will print the stack without discarding it. If the loop terminates, we jump to the right on line 5, preparing for the next printing loop.

    • Preparation of right half

      5.  →    /84/   
      6.       \     
      7.            :    
      8.            >
      9.         v:$-1/~
      10.         </r+*
      11.          </~
      12.           l
      

      This was one of the hardest parts to fit. Below is a version stripped of all direction wrapping to indicate what happens.

                   Initial stack:   "    gcpp0"
      84*+r~
      84*          Push 32 == " ".  "    gcpp0 "
         +         Add 32 and 0.    "    gcpp "
          r        Reverse.         " gcpp    "
           ~       Remove top.      " gcpp   "
      

      We then push the length of what is to be printed and start the second printing loop (with an initial duplicate not part of the loop).

    • Second printing loop (right half)

      3.     / ^ 
      4.     \}o<
      5.    
      6.           ↓   
      7.           
      8.       >  :>?\vv
      9.        v:$-1/~ 
      

      The code being executed is completely the same as in the first printing loop, with the o} being placed a bit further because there were available locations. Upon finishing, we have a few things left to do before we can verify the main loop invariant again. After the ~ on line 9 is executed we wrap around vertically, ending up at the following piece of code.

                      ↓
      2.          X     / 
      3.  1.v/             >a
      4.              >ao  /
      

      First ao will print a newline. Then we bounce up and arrive at exactly the same spot from after the initialisation, namely jumping to the X.

\$\endgroup\$
  • \$\begingroup\$ you should probably make the golfed version the main version \$\endgroup\$ – Destructible Lemon Mar 8 '17 at 22:23
  • 1
    \$\begingroup\$ @DestructibleWatermelon the post is more about the V version though, as it was much harder to mold everything in a specific shape with only a limited number of available bytes. Explanation will therefore follow for the V version, rather than the plain one. I might make an actually golfed one later. \$\endgroup\$ – PidgeyUsedGust Mar 9 '17 at 8:16
  • \$\begingroup\$ This is gold just gold \$\endgroup\$ – Christopher Jul 23 '17 at 1:34
  • \$\begingroup\$ I appreciate that this answer is in a language whose name consists exclusively of rotated 'V's. \$\endgroup\$ – Sellyme Sep 16 '18 at 10:17
19
\$\begingroup\$

Brain-Flak, 486 + 1 = 489 bytes

Happy Birthday V from Brain-Flak!

Also a Thank you to 0 ' who provided some of the code used in this answer

+1 due to the -c flag which is required for ASCII in and out

((([]<{({}<>)<>}<>([]){({}[()]<(([][()])<{({}[()]<({}<>)<>>)}{}><>)<>({}<<>{({}[()]<({}<>)<>>)}{}><>)(({})<>)<>>)}{}([][][()]){({}[()]<((((()()()()){}){}){})>)}{}<>{({}<>)<>}<>>){}[()])<{((({})<((({}){}())){({}[()]<(({}<(({})<>)<>>)<(({}<({}<>)<>>[()])<<>({}<<>{({}[()]<({}<>)<>>)}{}>)<>>){({}[()]<({}<>)<>>)}{}<>>)>)}{}{}((()()()()()){})(<()>)<>>)<{({}[()]<({}<>)<>>)}{}{}{}{({}<>)<>}<>>[()])}{}>()())([][()]){{}(({}[()])<{({}[()]<((((()()()()){}){}){})>)}{}{({}<>)<>}{}>)([][()])}{}<>

Try it online!

This is without a doubt the hardest thing I have ever done in Brain-Flak.

Brain-Flak is notoriously terrible at duplicating and reversing strings and this challenge consists of nothing but duplicating and reversing strings.

I managed to get this almost working snippet in just under an hour of hard work, but adding in the last few spaces turned out to be one of the most difficult things I have ever done in Brain-Flak.

Explanation

The basic Idea is that we will create the top of the V first and each iteration remove two characters from the middle and add a space to the beginning.

In practice this becomes quite difficult.

Existing algorithms exist for copy and reverse so I used one of those to create a reversed copy of the code on the offstack. Once I've done that I put 2n-1 spaces on top of the original stack and move the offstack back onto the onstack to create a sandwich.

Test 1

Now we have our top row. Now we want to remove two characters from the beginning and add a space to the front. This turns out to be the most difficult part. The reason for this is that we need to essentially store two values, one for the depth of the current snippet and one for the depth to the center of the V where the deletion has to occur.

This is hard.

Because of all the duplication and reversal that is going on both of the stacks are in full use all of the time. There really is nowhere on these stacks to put anything. Even with all of the Third Stack Magic in the world you can't get the type of access you need to solve this problem.

So how do we fix it? In short we don't really; we ignore the spaces for now and patch them in later we will add zeros to the code to mark where the spaces are intended to go but other than that we won't really do anything.

So on each iteration we make a copy of the last iteration and put it onto the offstack. We use the depth we stored to split this in half so we have the left half of the V on the right stack and the right half of the V on the left stack. We remove two elements and patch the two back together. We add a newline for good measure and start the next iteration. Each time the depth to the center of the V decreases by one and when it hits zero we stop the loop.

Now we have the bulk of the V constructed. We are however lacking proper spaces and our V is currently a bit (read: completely) upside-down.

Test 2

So we flip it. To flip it onto the other stack we have to move each element over one by one. As we are moving elements we check for zeros. If we encounter one we have to put the spaces back in where they belong. We chuck the zero and add in a bunch of spaces. How do we know how many? We keep track; flipping a stack unlike duplicating or reversing one is a very un-intensive task so we actually have the memory to store and access an additional counter to keep track of how many spaces to add. Each time we add some spaces we decrement the counter by one. The counter should hit zero at the last newline (the top of the V) and thus we are ready to print.

Lastly we clean up a few things hanging around and terminate the program for implicit output.

Test 3

\$\endgroup\$
  • \$\begingroup\$ Very impressive that you managed to get it working at all! Do you think you could save bytes by leaving it reversed and adding the -r flag? \$\endgroup\$ – DJMcMayhem Mar 3 '17 at 3:41
  • \$\begingroup\$ @DJMcMayhem I don't think so. The reversal process and the insertion of spaces happen at the same time, so if I added the -r flag I would need to actually reverse it another time. It is getting to be late where I am but I think I will work on trying to golf this down substantially tomorrow. If I can fix the spaces problem I will definitely use the -r flag. \$\endgroup\$ – Sriotchilism O'Zaic Mar 3 '17 at 3:47
16
\$\begingroup\$

Jelly, 15 12 bytes

⁶ṁ⁸;;\Uz⁶ŒBY

Try it online!

How it works

⁶ṁ⁸;;\Uz⁶ŒBY  Main link. Argument: s (string)

⁶ṁ            Mold ' ' like s, creating a string of len(s) spaces.
  ⁸;          Prepend s to the spaces.
    ;\        Cumulative concatenation, generating all prefixes.
      U       Upend; reverse each prefix.
       z⁶     Zip/transpose, filling empty spots with spaces.
         ŒB   Bounce; map each string t to t[:-1]+t[::-1].
           Y  Join, separating by linefeeds.
\$\endgroup\$
  • \$\begingroup\$ It is 12 characters, but is there any encoding where it would come out as just 12 bytes? \$\endgroup\$ – kasperd Mar 5 '17 at 13:06
  • 1
    \$\begingroup\$ Yes, Jelly uses it own custom code page. \$\endgroup\$ – Dennis Mar 5 '17 at 15:15
16
\$\begingroup\$

Python 3, 65 bytes

s=input();s+=' '*len(s)
for _ in s:s=' '+s[print(s+s[-2::-1]):-1]

Try it online!


Python 2, 65 bytes

s=input();s+=' '*len(s)
for _ in s:print s+s[-2::-1];s=' '+s[:-1]

Try it online!

\$\endgroup\$
16
\$\begingroup\$

JavaScript (ES6), 108 106 98 94 bytes

f=
s=>s.repeat((j=l=s.length*4)*2).replace(/./g,_=>--j?s[j+j<l?j-i:l-i-j]||` `:(j=l,++i,`
`),i=1)
<input oninput=o.textContent=f(this.value)><pre id=o>

\$\endgroup\$
  • \$\begingroup\$ Would you be able to make a post explaining this? I'm a bit confused by the replacement, and regular expressions. \$\endgroup\$ – Jacob Persi Mar 3 '17 at 18:00
  • \$\begingroup\$ @JacobPersi They're a red herring. All I need is an output area of size n*2 by n*4 (including the newlines at the end of each line). I then calculate the character that should appear in each cell. \$\endgroup\$ – Neil Mar 3 '17 at 19:31
  • \$\begingroup\$ Nice! You can shave off a byte by removing the newline between f= and s=>. \$\endgroup\$ – yummypasta Mar 10 '17 at 2:58
  • \$\begingroup\$ @yummypasta The f= is only part of the snippet, not the answer. As such, it isn't included in the byte count. \$\endgroup\$ – Neil Mar 10 '17 at 8:34
11
\$\begingroup\$

Retina, 51 47 bytes

Happy birthday from a fellow string-processing language!

Byte count assumes ISO 8859-1 encoding.

$
$.`$* 
$
¶$`
O$^r`.\G

;{*`.¶

(\S.*).¶.
 $1¶

Try it online!

Explanation

$
$.`$* 

This appends n spaces (where n is the string length), by matching the end of the string, retrieving the length of the string with $.`, and repeating a space that many times with $*.

$
¶$`

We duplicate the entire string (separated by a linefeed), by matching the end of the string again and inserting the string itself with $`.

O$^r`.\G

This reverses the second line by matching from right-to-left (r), then matching one character at a time (.) but making sure that they're all adjacent (\G). This way, the matches can't get past the linefeed. This is then used in a sort-stage. By using the sort-by mode ($) but replacing each match with an empty string, no actual sorting is done. But due to the ^ option, the matches are reversed at the end, reversing the entire second line.

;{*`.¶

This stage is for output and also affects the rest of the program. { wraps the remaining stages in a loop which is repeated until those stages fail to change the string (which will happen because the last stage won't match any more). The ; disables output at the end of the program. The * turns this stage into a dry-run which means that the stage is processed and the result is printed, but afterwards the previous string is restored.

The stage itself simply removes a linefeed and the preceding character. Which gives us one line of the desired output (starting with the first line).

(\S.*).¶.
 $1¶

Finally, this stage turns each line into the next. This is done by inserting a space in front of the first non-space character, removing the last character on the first line, as well as the first character on the second line. This process stops once there is only one non-space character left on the first line, which corresponds to the last line of the output.

\$\endgroup\$
  • \$\begingroup\$ Would love an explanation of how this works. I know sed's syntax is less compact, but my draft is twice longer. Reversing string and putting together the first output line is most of it. \$\endgroup\$ – seshoumara Mar 3 '17 at 9:51
  • \$\begingroup\$ @seshoumara Sure, there you go. \$\endgroup\$ – Martin Ender Mar 3 '17 at 10:04
  • \$\begingroup\$ Thanks. Now I know a double length sed script is not bad :)) due to extra s/// chars that add up, to lengthier string reversal and other operations that lack the niceties of Retina. Good read. +1 \$\endgroup\$ – seshoumara Mar 3 '17 at 10:47
9
\$\begingroup\$

05AB1E, 12 bytes

Dgð×J.p€ûR.c

Try it online!

Explanation

D             # duplicate input
 g            # length of copy
  ð×J         # append that many spaces to input
     .p       # get a list of all prefixes
       €û     # turn each into a palindrome
         R    # reverse the list
          .c  # pad each line until centered

Or for the same byte count from the other direction.

Âsgú.sí€ûR.c

Explanation

             # push a reversed copy of input
 s            # swap the input to the top of the stack
  g           # get its length
   ú          # prepend that many spaces
    .s        # get a list of all suffixes
      í       # reverse each
       €û     # turn each into a palindrome
         R    # reverse the list
          .c  # pad each line until centered
\$\endgroup\$
  • 2
    \$\begingroup\$ If you indent the comments incrementally, then even the source looks like a V :) \$\endgroup\$ – aross Mar 3 '17 at 10:55
9
\$\begingroup\$

Japt, 22 20 16 14 + 2 bytes

Japt wishes V many more successful years of golfing!

²¬£²îU²ç iYU)ê

Requires the -R flag. Test it online!

Explanation

This makes use of the ç and î functions I added a few days ago:

²¬£²îU²ç iYU)ê    Implicit: U = input string
²                 Double the input string.
 ¬                Split into chars.
  £               Map each char X and index Y by this function:
     U²             Take the input doubled.
       ç            Fill this with spaces.
         iYU        Insert the input at index Y.
    î       )       Mask: repeat that string until it reaches the length of
   ²                the input doubled.
                    This grabs the first U.length * 2 chars of the string.
             ê      Bounce the result ("abc" -> "abcba").
                  Implicit: output result of last expression, joined by newlines (-R flag)

Dennis's technique is a byte longer:

U+Uç)å+ mw y mê
\$\endgroup\$
5
\$\begingroup\$

GNU sed, 110 100 + 1(r flag) = 101 bytes

Edit: 9 bytes shorter thanks to Riley

As another string manipulation language, sed wishes V the best!

h;G
:;s:\n.: \n:;t
h;:r;s:(.)(\n.*):\2\1:;tr
H;x
s:\n\n ::
:V
h;s:\n::p;g
s:^: :;s:.\n.:\n:
/\n$/!tV

Try it online!

Explanation: assuming the input is the last test case ('V!'). I will show the pattern space at each step for clarity, replacing spaces with 'S's.

h;G                       # duplicate input to 2nd line: V!\nV!
:;s:\n.: \n:;t            # shift each char from 2nd line to 1st, as space: V!SS\n
h;:r;s:(.)(\n.*):\2\1:;tr # save pattern space, then loop to reverse it: \nSS!V
H;x                       # append reversed pattern to the one saved V!SS\n\n\nSS!V
s:\n\n ::                 # convert to format, use \n as side delimiter: V!SS\nS!V
:V                        # start loop 'V', that generates the remaining output
h;s:\n::p;g               # temporarily remove the side delimiter and print pattern
s:^: :;s:.\n.:\n:         # prepend space, delete char around both sides: SV!S\n!V
/\n$/!tV                  # repeat, till no char is left on the right side
                          # implicit printing of pattern left (last output line)
\$\endgroup\$
  • \$\begingroup\$ @Riley Answer updated, thanks! \$\endgroup\$ – seshoumara Mar 7 '17 at 17:18
4
\$\begingroup\$

Python, 110 bytes

Try it online!

I'm sure this isn't optimal, but it's pretty Pythonic at least:

def f(s):n=len(s)*2-1;return''.join(i*' '+s[:n+1-i]+(n-2*i)*' '+s[n-i-1::-1]+'\n'for i in range(n))+n*' '+s[0]
\$\endgroup\$
4
\$\begingroup\$

Jolf, 31 bytes

Jolf begrudgingly wishes V a happy birthday!

RΜwzΒώlid+γ_pq_ l+*␅Hi0ΒΒ␅ L_γ1S

Try it here! should be 0x05.

Explanation

RΜzΒώlid+γ_pq_ l+*␅Hi0ΒΒ␅ L_γ1S  i = input
     li                                  i.length
    ώ                                2 * 
   Β                             Β =
  z                              range(1, Β + 1)
 Μ     d                         map with: (S = index, from 0)
                +                 add:
                 *␅H               S spaces
                    i              and the input
               l                  slice (^) from
                     0Β            0 to Β
           pq_         Β␅         pad (^) with spaces to the right
         γ_                       γ = reverse (^)
        +                 L_γ1    γ + behead(γ)
R                             S  join with newlines
\$\endgroup\$
4
\$\begingroup\$

Charcoal, 29 bytes

Happy birthday V, from your fellow disappointingly-long-for-this-challenge ASCII-art language!

SσF…·¹Lσ«Fι§σκMι←↖»Fσ«Pσ↖»‖O→

Try it online!

Explanation

Our strategy: print the left half of the V, starting from the bottom and moving to the upper left; then reflect it.

Sσ                                    Input σ as string
                                       The bottom len(σ) half-rows:
   F…·¹Lσ«           »               For ι in inclusive range from 1 to length(σ):
            Fι                          For κ in range(ι):
               §σκ                         Print character of σ at index κ
                  Mι←                   Move cursor ι spaces leftward
                      ↖                  Move cursor one space up and left
                                       The top len(σ) half-rows:
                        Fσ«    »      For each character ι in σ:
                            Pσ          Print σ without moving the cursor
                               ↖         Move cursor one space up and left
                                 ‖O→  Reflect the whole thing rightward, with overlap

(If only Charcoal had string slicing... alas, it appears that hasn't been implemented yet.)

\$\endgroup\$
4
\$\begingroup\$

Pip, 32 25 bytes

a.:sX#aL#a{OaDQaPRVaaPUs}

Takes the input string as a command-line argument. Try it online!

Explanation

                           a is 1st cmdline arg, s is space (implicit)
     #a                    Len(a)
   sX                      Space, string-multiplied by the above
a.:                        Concatenate that to the end of a
       L#a{             }  Loop len(a) times (but NB, a is now twice as long as it was):
           Oa                Output a (no trailing newline)
             DQa             Dequeue one character from the end of a
                PRVa         Print reverse(a) (with trailing newline)
                    aPUs     Push one space to the front of a
\$\endgroup\$
4
\$\begingroup\$

R with stringi package, 225 Bytes

library(stringi)
f=function(){
s=scan(,'',1,sep="\n")
m=2*nchar(s)
l=stri_pad(sapply(1:m-1,function(x)substr(paste(paste(rep(" ",x),collapse=""),s),1,m)),m,"right")
r=substr(stri_reverse(l),2,m)
message(paste0(l,r,"\n"))}
f()

If you run R in interactive code, after pasting my answer just input anything. You will need the stringi R package to be installed (I hope it's not against the rules).

Explanation:

The basic idea is to add spaces to the left side, then cut it to the right length. After that, paste it with its reversed version as the right side. Here is a longer, human-readable version of the function:

library(stringi)
make_V <- function(){                  # declaring the function
  string <- scan(, '', n=1, sep="\n")  # reading input
  max_length <- 2*nchar(string)        # number of chars in each half row

  # creating the left side of the V

  left <- stri_pad(                    
            sapply(1:max_length-1,     # for each row
                   function(x){     
                    substr(            
                      paste0(
                        paste0(rep(" ", x),
                               collapse=""), string), # add spaces to left side
                           1,
                           max_length) # cut the unneeded end
                    }),
            width=max_length,
            side="right")              # add spaces to the right side

  # creating the right side of the V

  right <- substr(stri_reverse(left), 2, max_length)

  # print it without any symbols before the strings 
  message(paste0(left, right, "\n"))
}

# run the function
make_V()
\$\endgroup\$
  • \$\begingroup\$ Welcome to the site! :) \$\endgroup\$ – DJMcMayhem Mar 3 '17 at 17:30
4
\$\begingroup\$

Ruby, 92 89 85 bytes

s=gets.chomp
s<<" "*n=s.size*2
n.times{s=s[0..(n-1)]
puts s+s.reverse[1..-1]
s=" "+s}

My process was to remove the first character from the right half of each line after reversing the first half. Like this:

Hello     |    olleH
 Hello    |   olleH 
  Hello   |  olleH  
   Hello  | olleH   
    Hello |olleH    
     Hello|lleH     
      Hell|leH      
       Hel|eH       
        He|H        
         H|         

I'm not used to trying to golf things so let me know if there's anything I can do to get it shorter.

\$\endgroup\$
  • \$\begingroup\$ Welcome to the site, this is a nice answer! Unfortunately, I really don't know a whole lot about ruby, so I can't offer any tips. You might be able to find something on this page though. \$\endgroup\$ – DJMcMayhem Mar 3 '17 at 19:03
  • \$\begingroup\$ Thanks! There are a lot of interesting things on that page but I seem to already be doing a lot of them. I did realize I could save some bytes via side-effects and order of operations though. \$\endgroup\$ – user3334690 Mar 3 '17 at 21:02
  • 1
    \$\begingroup\$ I assume [Ruby] is just Ruby, the more-or-less well-known programmign language? \$\endgroup\$ – Rɪᴋᴇʀ Mar 8 '17 at 17:28
  • \$\begingroup\$ You can save 8 bytes by making this a lambda. \$\endgroup\$ – Jordan Nov 1 '17 at 21:16
4
\$\begingroup\$

Batch, 186 185 bytes

@set e=@set 
%e%/ps=
%e%t=%s%
%e%r=
:l
%e%s=%s% 
%e%r= %r%%t:~-1%
%e%t=%t:~,-1%
@if not "%t%"=="" goto l
:g
%e%r=%r:~1%
@echo %s%%r%
%e%s= %s:~,-1%
@if not "%r%"=="" goto g

Lines 1 and 6 have a trailing space. Edit: Saved 1 byte thanks to @ConorO'Brien.

\$\endgroup\$
  • 1
    \$\begingroup\$ Here's a convoluted way to save a byte. (create an alias for @set and remove @echo off, inserting @ as necessary. \$\endgroup\$ – Conor O'Brien Mar 8 '17 at 19:48
  • \$\begingroup\$ @ConorO'Brien Thanks, I'd never have guessed that 8 sets would have saved me enough bytes to make it worthwhile. \$\endgroup\$ – Neil Mar 8 '17 at 20:03
3
\$\begingroup\$

Haskell, 76 bytes

v is the main function, taking a String argument and giving a String result.

v i=unlines.r$i++(' '<$i)
r""=[]
r s|t<-init s=(s++reverse t):map(' ':)(r t)

Try it online!

Notes:

  • i is the initial argument/input.
  • s is initially i with length i spaces appended.
  • v i calls r s, then joins the result lines.
  • r returns a list of String lines.
  • t is s with the last character chopped off.
  • The recursion r t produces the lines except the first, minus the initial space on each line.
\$\endgroup\$
  • 2
    \$\begingroup\$ +1 for naming the main function v. :D \$\endgroup\$ – DJMcMayhem Mar 3 '17 at 3:39
  • 1
    \$\begingroup\$ @DJMcMayhem: not naming the main function is one byte longer: unlines.r.((++)<*>(' '<$)). \$\endgroup\$ – nimi Mar 4 '17 at 10:02
  • 1
    \$\begingroup\$ @nimi I assume he liked which name I chose. Technically a lambda ties... When I wrote the answer, I didn't know you could use top level declarations for some functions, but not name the main function. Although I saw someone else do it, I find it somewhat disturbing. These days it works in GHCi at least. \$\endgroup\$ – Ørjan Johansen Mar 4 '17 at 19:07
3
\$\begingroup\$

Jelly, 13 bytes

⁶ṁ;@µḣJUz⁶ŒBY

Try it online!

How?

⁶ṁ;@µḣJUz⁶ŒBY - Main link: string s
⁶             - space character
 ṁ            - mould like s: len(s) spaces
  ;@          - concatenate s with that
    µ         - monadic chain separation (call that t)
      J       - range(length(t))
     ḣ        - head (vectorises): list of prefixes from length to all
       U      - upend: reverse each of them
        z     - transpose with filler:
         ⁶    -     space: now a list of the left parts plus centre
          ŒB  - bounce each: reflect each one with only one copy of the rightmost character
            Y - join with line feeds
              - implicit print
\$\endgroup\$
  • \$\begingroup\$ Alike minds think great. :P \$\endgroup\$ – Dennis Mar 3 '17 at 2:20
  • \$\begingroup\$ Oh my I didn't think about a cumulative concatenation! Charcoal has a V direction, maybe some investigation thereabouts... \$\endgroup\$ – Jonathan Allan Mar 3 '17 at 2:25
3
\$\begingroup\$

Ruby, 85 83 bytes

edit: removed excess whitespace

s=ARGV[0];s+=' '*s.length;s.length.times{|i|puts s+s[i..-2].reverse;s=' '+s[0..-2]}

I actually found it pretty difficult to golf this one down in Ruby. After adding whitespace, it expands to a pretty readable snippet of code:

s = ARGV[0]
s+=' ' * s.length

s.length.times do |i|
  puts s + s[i..-2].reverse
  s = ' ' + s[0..-2]
end
\$\endgroup\$
  • 1
    \$\begingroup\$ You could probably save a bit by setting s.length to a variable like I did? Also, I think you should consider doing size instead of length? \$\endgroup\$ – user3334690 Mar 3 '17 at 20:26
  • \$\begingroup\$ Doing what @user3334690 suggested and moving the .times statement, 79 bytes: s=ARGV[0];(s+=' '*s.size).size.times{|i|puts s+s[i..-2].reverse;s=' '+s[0..-2]} \$\endgroup\$ – Conor O'Brien Mar 3 '17 at 22:30
  • \$\begingroup\$ You can save five bytes by making this a lambda. \$\endgroup\$ – Jordan Nov 2 '17 at 14:38
3
\$\begingroup\$

MATLAB (R2016b), 223 183 bytes

r=input('');l=nnz(r)*2;for i=1:l;m=l+1-2*i;c={' '};s=cell(1,i-1);s(:)=c;x=cell(1,m);x(:)=c;e=r;y=flip(r);if(m<1);e=r(1:2*end-i+1);y=r(l/2+end-i:-1:1);end;disp(cell2mat([s e x y]));end

First time Code Golfing. Tips are welcome!

Program Output:

MATLAB Code Golf

Edit:

Saved 40 bytes thanks to Luis Mendo.

\$\endgroup\$
  • 2
    \$\begingroup\$ Welcome to PPCG, and nice first answer! Unfortunately I know nothing about MATLAB so I'm not able to help you golf this, but perhaps you will find some of the tips helpful :-) \$\endgroup\$ – ETHproductions Mar 6 '17 at 0:53
  • 1
    \$\begingroup\$ Inputting a string including its enclosing quotes is allowed by default. So you can remove 's' from input. Also, I don't see why you are using evalc(disp(...)), but I think you can just use cell2mat this way \$\endgroup\$ – Luis Mendo Mar 6 '17 at 14:49
  • 1
    \$\begingroup\$ Also, flip is shorter than end:-1:1, see here \$\endgroup\$ – Luis Mendo Mar 6 '17 at 14:56
3
\$\begingroup\$

PHP, 95 92 85 80 78 77 bytes

Note: uses IBM-850 encoding

for($s.=strtr($s^$s=$argn,~ ,~▀);~$s[$i++];)echo$s,strrev($s=" $s"^$s^$s),~§;
          # Note that this ^ char is decimal 255 (negating it yields "\0")

Run like this:

echo "Hello" | php -nR 'for($s.=strtr($s^$s=$argn,"\0",~▀);~$s[$i++];)echo$s,strrev($s=" $s"^$s^$s),~§;'
> Hello         olleH 
>  Hello       olleH  
>   Hello     olleH   
>    Hello   olleH    
>     Hello olleH     
>      HellolleH      
>       HellleH       
>        HeleH        
>         HeH         
>          H          

Explanation

for(
  $s.=strtr(             # Set string to the input, padded with spaces.
    $s^$s=$argn,         # Input negated with itself, leads to string with
                         # only null bytes with the same length.
    ~ ,                  # Replace null bytes...
    ~▀                   # ... with spaces.
  );
  ~$s[$i++];             # Iterate over the string by chars, works because 
                         # there are just as many lines as the padded
                         # string has chars.
)
  echo                   # Output!
    $s,                  # The string.
    strrev(              # The reverse of the string.
      $s=" $s"^$s^$s     # After each iteration, prefix string with a
    ),                   # space, and trim the last character.
    ~§;                  # Newline.

Tweaks

  • Saved 3 bytes by getting rid of the pad character (str_pad defaults to space, which is what we need)
  • Saved 7 bytes by using binary operations on the string to truncate it instead of substr
  • Saved 5 bytes by rotating the string when printing the reverse. Prevents the need for printing a backspace, but results in a trailing space on each line.
  • Saved 2 bytes by padding string using a more convoluted, but shorter method.
  • Saved a byte due to the fact that there is no need to account for the ~"0" case (ASCII 207), as all input may be assumed to be printable ascii (Thx @Titus)
\$\endgroup\$
  • \$\begingroup\$ echo$s,strrev($s=" $s"^$s^$s),~§; saves 5 bytes. \$\endgroup\$ – Titus Mar 7 '17 at 23:44
  • \$\begingroup\$ @Titus, thx. Usually I avoid trailing whitespace, but OP said it's acceptable \$\endgroup\$ – aross Mar 8 '17 at 9:12
  • \$\begingroup\$ ~$s[$i++] is sufficient (input is printable ASCII, and so is $s) \$\endgroup\$ – Titus Jul 23 '17 at 4:28
  • \$\begingroup\$ @Titus, thx, good catch. I tend to code on the safe side \$\endgroup\$ – aross Jul 24 '17 at 7:27
2
\$\begingroup\$

JavaScript (ES6), 169 157 bytes

(-10 bytes thanks to Conor O'Brien)

V=(j,i=0,p="")=>i<(f=j.length)*2?V(j,-~i,p+" ".repeat(i)+j.slice(0,f-i*(i>f))+" ".repeat(i<f?(f-i)*2-1:0)+[...j.slice(0,f+~i*(i>=f))].reverse().join``+`
`):p

A recursive solution. I am new to JavaScript, so please be gentle! Any golfing tips are greatly appreciated. :)

And, of course, a very happy birthday to you V!

Test Snippet

V=(j,i=0,p="")=>i<(f=j.length)*2?V(j,-~i,p+" ".repeat(i)+j.slice(0,f-i*(i>f))+" ".repeat(i<f?(f-i)*2-1:0)+[...j.slice(0,f+~i*(i>=f))].reverse().join``+`
`):p
<input oninput=o.textContent=V(this.value)><pre id=o>

\$\endgroup\$
  • 1
    \$\begingroup\$ This is pretty good! Usually, s.split("") can be changed to [...s], and a.join("") can become a.join followed by a pair of backticks. You can save an additional 3 bytes by replacing [r='repeat'] and [r] with plain ol' repeat, same with slice. \$\endgroup\$ – Conor O'Brien Mar 3 '17 at 4:43
  • \$\begingroup\$ @ConorO'Brien Thanks for the tips! They are much appreciated. :) \$\endgroup\$ – R. Kap Mar 3 '17 at 4:53
2
\$\begingroup\$

CJam, 26 bytes

Happy birthday from your old pal CJam!

q_,2*:L,\f{LS*+m>L<_W%(;N}

Try it online!

Explanation

q                           Push the input
 _,2*:L                     Push 2 times the length of the input, store it in L
       ,                    Take the range from 0 to L-1
        \                   Swap top stack elements
         f{                 Map over the range, using the input as an extra parameter
           LS*+               Append L spaces to the input
               m>             Rotate the resulting string right i positions (where i is the
                               current number being mapped)
                 L<           Take the first L characters of the string
                   _W%        Duplicate it and reverse it
                      (;      Remove the first character from the copy
                        N     Add a newline
                         }  (end of block)
                            (implicit output)
\$\endgroup\$
2
\$\begingroup\$

PowerShell, 126 bytes 124 bytes

$l=($s="$args")|% Le*;$r=-join$s[-1..-$l];0..($l*2-1)|%{' '*$_+($s+' '*$l).substring(0,$l*2-$_)+(' '*$l+$r).substring($_+1)}

Call it with a single parameter, such as .\V.ps1 Hello.

Edit: 2 bytes saved with tip from AdmBorkBork

\$\endgroup\$
  • 1
    \$\begingroup\$ A Try it online! link, in case you're interested. \$\endgroup\$ – Dennis Mar 3 '17 at 2:47
  • \$\begingroup\$ Oh I didn't know about that little tool, thanks! \$\endgroup\$ – Tor Mar 3 '17 at 3:55
  • \$\begingroup\$ Hi there! A couple small golfs on the front. Take the input as a string, and use encapsulation to pass the variable along. Saves two bytes. $l=($s="$args")|% Le*; \$\endgroup\$ – AdmBorkBork Mar 3 '17 at 14:44
  • \$\begingroup\$ Wow, didn't know about those 2 golfs, thanks! \$\endgroup\$ – Tor Mar 3 '17 at 16:12
2
\$\begingroup\$

Pyke, 14 bytes

l}j Fd*R+j^j<s

Try it online!

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

JavaScript (ES6), 94 bytes

f=(s,y=0,x=0,l=s.length*2-1)=>(s[(x>l?l*2-x:x)-y]||' ')+(x<l*2?f(s,y,x+1):y<l?`
`+f(s,y+1):'')

Test cases

f=(s,y=0,x=0,l=s.length*2-1)=>(s[(x>l?l*2-x:x)-y]||' ')+(x<l*2?f(s,y,x+1):y<l?`
`+f(s,y+1):'')

console.log(f('Happy'))
console.log(f('Birthday'))
console.log(f('V!'))
console.log(f('~'))

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

J, 44 Bytes

(([(,}.@|.)@{."1-@i.@[|."0 1(,#&' ')~)~+:@#)
\$\endgroup\$
  • 1
    \$\begingroup\$ Hmm, I can't figure out how to run this online. Try it online! Am I just calling it wrong? (I'm a J newb) \$\endgroup\$ – DJMcMayhem Mar 3 '17 at 21:37
  • \$\begingroup\$ @DJMcMayhem That's a function, not a program. tio.run/nexus/… \$\endgroup\$ – Dennis Mar 3 '17 at 21:39
  • \$\begingroup\$ Golf: |."0 1 to |."{ (saved 2 bytes) \$\endgroup\$ – Conor O'Brien Mar 3 '17 at 22:20
  • \$\begingroup\$ Also, you don't have to have the outer parentheses. \$\endgroup\$ – Conor O'Brien Mar 3 '17 at 22:25

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.