# Draw diagonal lines of text

Given an input of a list of words, output the words with their letters arranged diagonally:

p
r
o
p  g
u  r
z  a
a  z  m
n  l  m
d  e  i
c     s  n
o        g
d
g  e
o
l
f


(The above should be the output for the input programming puzzles and code golf.)

To be precise, each word starts on the first column and three rows below the previous word, and each successive letter moves one column to the right and one row down.

The input may be provided as either a single string of words, separated by exactly one space, or a list/array of words. The words will only be composed of lowercase letters, a-z, and will always be at least one character long.

The output may be a single string, an array of lines, or an array of arrays of characters. Leading or trailing whitespace is not allowed, except for a single trailing newline.

Further test cases:

a bcd efgh i j

a

b
c
d
e
f
g
i  h

j


x

x


verylongword short

v
e
r
s  y
h  l
o  o
r  n
t  g
w
o
r
d


Since this is , the shortest code in bytes will win!

• I feel like I should be able to make a Python program for this in 5 minutes, but it always seems to be failing... ;_; – HyperNeutrino Nov 14 '16 at 3:58
• Wow, it seems like there are a lot of challenges seemingly designed for Turtlèd – Destructible Lemon Nov 15 '16 at 1:01
• Are terminal escape codes allowed? :) – Chromium Jun 28 '18 at 9:30

# Vim, 85, 76, 66, 52 keystrokes/bytes

When I first looked at this challenge, I thought "This is perfect for vim!" And then when I tried it everything went wrong. Here it is, in all of it's messy hacky glory:

:se ve=all|s/ /\r\r\r/g
qqGo<esc>?\<.\S
lDjP@qq@qG?.
jdG


Try it online, thanks to the (mostly) backwards compatible V interpreter.

# Explanation:

At first I thought I could do this beautifully simple 37 byte version:

:se ve=all
qq:g/\S\S/norm ^lDjP
@qq@q


Unfortunately, it's not that simple. Let's take it line by line:

:se ve=all


This enables a feature called 'virtual editing'. It allows the cursor to move to columns that don't exist yet. This answer would be basically impossible without it.

Now we need to separate out the words onto different lines. So we'll replace each space with 3 newlines. Since this is an ex command we can run it simultaneously with our last ex command :se ve=all by seperating the two with a bar.

|s/ /\r\r\r/g


Now the buffer looks like this:

Programming

Puzzles

and

code-golf


Here's where the fun begins. We set up the traditional recursive macro with: qq, and then call this:

G               " Move to the last line
o<esc>         " Append an extra newline

?               " Search backwards for
\<.            " Any character at the beginning of a word
\S          " Followed by a non-space character
l               " Move one character to the right
D              " Delete eveything until the end of this line
j             " Move down one line
P            " Paste what we just deleted


Then we finish the recursive macro with @qq@q. At this point, we have all of the diagonals, we just need to do a little clean up.

G                   " Move to the last line
?.                 " Search backwards for any character
j                   " Move down one line
dG                 " Delete until the end of the buffer

• Wow, JavaScript is (currently) shorter than Vim. That's quite a rare occurence these days... – ETHproductions Nov 14 '16 at 2:30
• @ETHproductions Not any more. :) – DJMcMayhem Nov 14 '16 at 3:04

# Turtlèd, 28 26 bytes

Oh my, I appear to be beating a language specifically designed for golfing. this is a great day.

!_4[*.[ rd+.]ul[ ul]r;_+]_


## Explanation

(write means writing to the cell on the grid, pointed char means char in input the string pointer points to)

!                         Take string input into variable
_                        Normally conditional, with >1 input (there will be), write ' '
4                       set register to 4
[*                   ] until the current cell is *
.                    Write pointed char, initially first char
[     ]             Until space is written on cell
rd+.              move right, down, string pointer++, write pointed char
ul[ ul]      Move back up to the top of the word
r;    Move right, down 4 (because this is register value)
_+  write * if end of input, else ' ', increment string pointer
_ will always write ' ', since it will always point at start char


note trailing space.

Input also needs trailing space. seeing as python can take a list, this is a lot like taking a list in Turtlèd

# MATL, 28 bytes

c!t&n:q3_*ts_b+5M4$XdZ!cZ{Zv  Input is a cell array of strings, with commas as optional separators: {'programming' 'puzzles' 'and' 'code' 'golf'}  or {'programming', 'puzzles', 'and', 'code', 'golf'}  Try it online! Or verify all test cases: 1, 2, 3, 4. ### Explanation Consider the following input as an example: {'aaaa' 'bb' 'ccc'}  You can view the partial results (stack contents) inserting the comment symbol % at any point in the code. For example, view the stack contents after the fourth function (&n). c % Input cell array of strings implicitly. Convert to 2D char array, % right-padding with spaces % STACK: ['aaaa'; 'bb '; 'ccc'] ! % Transpose % STACK: ['abc' 'abc' 'a c' 'a '] t % Duplicate % STACK: ['abc' 'abc' 'a c' 'a '], ['abc' 'abc' 'a c' 'a '], &n % Number of rows and of columns % STACK: ['abc' 'abc' 'a c' 'a '], 4, 3 :q % Range, subtract 1 % STACK: ['abc' 'abc' 'a c' 'a '], 4, [0 1 2] 3_* % Multiply by -3 % STACK: ['abc' 'abc' 'a c' 'a '], 4, [0 -3 -6] ts_ % Duplicate, sum, negate % STACK: ['abc' 'abc' 'a c' 'a '], 4, [0 -3 -6], 9 b % Bubble up in stack % STACK: ['abc' 'abc' 'a c' 'a '], [0 -3 -6], 9, 4 + % Add % STACK: ['abc' 'abc' 'a c' 'a '], [0 -3 -6], 13 5M % Push second input of last function again % STACK: ['abc' 'abc' 'a c' 'a '], [0 -3 -6], 13, 4 4$Xd     % Buld numerical sparse matrix from the above four arguments. The
% columns of the first input argument will be the diagonals of the
% result, with indices given bu the second input (negative is below
% main diagonal). The matrix size is the third and fourth arguments
% STACK: [97  0  0  0
0 97  0  0
0  0 97  0
98  0  0 97
0 98  0  0
0  0 32  0
99  0  0 32
0 99  0  0
0  0 99  0
0  0  0 32
0  0  0  0
0  0  0  0
0  0  0  0]
Z!c      % Convert from sparse to full, and then to char. Character 0 is
% displayed as space
% STACK: ['a   '
' a  '
'  a '
'b  a'
' b  '
'    '
'c   '
' c  '
'  c '
'    '
'    '
'    '
'    ']
Z{       % Split into cell array, with each row in a cell
% STACK: {'a   ', ' a  ', '  a ', 'b  a', ' b  ', '    ', 'c   ', ' c  ', '  c ', '   ', '   ', '   ', '   '}
Zv       % Deblank: remove trailing space from each string. Implicitly display,
% each string on a different line. Empty strings do not generate
% a newline
% STACK: {'a   ', ' a', '  a', 'b  a', ' b', '', 'c', ' c', '  c', '', '', '', ''}


## JavaScript (ES6), 118109 84 bytes

Takes input as an array of words. Returns an array of arrays of characters.

s=>s.map((w,y)=>[...w].map((c,x)=>(a[p=y*3+x]=a[p]||Array(x).fill(' '))[x]=c),a=[])&&a


### Alternative version, 109 bytes

Returns a string.

let f =

s=>s.map((w,y)=>[...w].map((c,x)=>(a[p=y*3+x]=a[p]||Array(x).fill )[x]=c),a=[])&&a.map(s=>s.join).join

console.log(f(["programming", "puzzles", "and", "code", "golf"]))

# Common Lisp, 673668 597 bytes

Terrible solution, I know. I'll probably edit this more after some sleep.

(defun f(&rest z)(let((l)(a 0)(s)(o)(b)(c 0))(loop(setf b(length l))(setf l"")(loop for w in z for i from 0 do(if(>(+(length w)(* i 3))c)(setf c(+(length w)(* i 3))))(setf s(+(* i -3)a))(when(and(>= s 0)(< s(length w)))(setf o(format nil"~v@{~a~:*~}"s" "))(if(and(>=(- s 3)0)(not(equal i(-(length z)1))))(setf o(subseq o(- s 2))))(setf l(concatenate'string o(string(char w s))l)))(when(>= s(length w))(setf l(concatenate'string"   "l))))(if(<=(length l)b)(setf l(concatenate'string(format nil"~v@{~a~:*~}"(- b(length l)-1)" ")l)))(print(string-right-trim" "l))(if(>= b c)(return))(setf a(1+ a)))))


Usage:

* (f "ppcg" "is" "pretty" "ok")

"p"
" p"
"  c"
"i  g"
" s"
""
"p"
" r"
"  e"
"o  t"
" k  t"
"     y"
""
NIL


This loops over every word in the provided list and adds appropriate characters to the current line. Appropriate padding is provided by my subpar usage of format.

Note: I'm new to Common Lisp, but I know enough to realize that this could use a lot of improvement.

• >:( "ppcg ... ok"!? – Destructible Lemon Dec 3 '16 at 13:47

# C#, 336 Bytes:

Golfed:

string D(string[]s){int x=0,y=0,r=0,q=2*(s.Max().Length+s.Length)+1;var a=new char[q, q];for(int i=0;i<s.Length;i++){y=r;for(int j=0;j<s[i].Length;j++){a[y,x]=s[i][j];x+=1;y+=1;}x=0;r+=3;}var o="";for(x=0;x<q;x++){var t="";for(y=0;y<q;y++)t+=a[x,y];o+=t==string.Join("",Enumerable.Repeat('\0',q))?"":(t.TrimEnd('\0')+"\r\n");}return o;}


Ungolfed:

public string D(string[] s)
{
int x = 0, y = 0, r = 0, q = 2 * (s.Max().Length + s.Length) + 1;
var a = new char[q, q];
for (int i = 0; i < s.Length; i++)
{
y = r;
for (int j = 0; j < s[i].Length; j++)
{
a[y, x] = s[i][j];
x += 1;
y += 1;
}
x = 0;
r +=3;
}
var o = "";
for (x = 0; x < q; x++)
{
var t = "";
for (y = 0; y < q; y++)
t += a[x, y];
o += t == string.Join("", Enumerable.Repeat('\0', q)) ? "" : (t.TrimEnd('\0') + "\r\n");
}
return o;
}


Testing:

  var codeGolf = new DrawDiagonalLinesOfText();
Console.WriteLine(codeGolf.E(new string[] { "programming", "puzzles", "and", "code", "golf" }));
Console.WriteLine(codeGolf.E(new string[] { "a", "bcd", "efgh", "i", "j" }));
Console.WriteLine(codeGolf.E(new string[] { "verylongword", "short" }));

p
r
o
p  g
u  r
z  a
a  z  m
n  l  m
d  e  i
c     s  n
o        g
d
g  e
o
l
f

a
b
c
d
e
f
g
i  h
j

v
e
r
s  y
h  l
o  o
r  n
t  g
w
o
r
d

• This appears to output trailing whitespace at the ends of lines, which is not allowed by the challenge specification. Also, requiring strings of spaces to separate the words in the input array is not an allowed input format. – Doorknob Nov 15 '16 at 1:12
• @Doorknob Oops, sorry... Fixed, only cost me 2 Bytes :) – Pete Arden Nov 15 '16 at 8:36
• Compile to a Func<string[], string> and make various other changes for 297 bytes s=>{int i=0,x=0,y=0,r=0,l=s.Length,q=2*(s.Max().Length+l)+1,j;var a=new char[q,q];for(;i<l;i++){y=r;for(j=0;j<s[i].Length;)a[y++,x++]=s[i][j++];x=0;r+=3;}var o="";for(;x<q;x++){var t="";for(y=0;y<q;)t+=a[x,y++];o+=t==string.Join("",Enumerable.Repeat('\0',q))?"":(t.TrimEnd('\0')+"\n");}return o;}; however you need to add 18 bytes for using System.Linq; – TheLethalCoder Nov 15 '16 at 11:06
• @TheLethalCoder Thanks, but I don't really want to take your entire solution :) – Pete Arden Nov 15 '16 at 11:49
• It's not mine its yours I just golfed some of the stuff away i.e. moving thwe i and j to the int declaration at the top and moving some of the ++ so they are used on the last use of the variable – TheLethalCoder Nov 15 '16 at 11:53

# Python 2, 146 bytes

s=input()
k=max(map(len,s))
a=[k*[' ']for x in range(k+len(s)*3+3)]
for x in range(len(s)):
for y in range(len(s[x])):a[x*3+y][y]=s[x][y]
print a


Note: the indentations for the last two lines are <space> and <tab>, which saves one byte since I don't need to double-indent.

Input is to be entered as an array of strings like so: ["hello", "world"] or ['hello', 'world']. Output is an array of arrays of characters.

There's probably a better way to do this...

EDIT Thanks to Doorknob for pointing out a missing close square bracket. I placed it before the *k... in the third line.

• There's a syntax error in your code on the third line; there's two open brackets but only one close bracket. However I fix it (either by adding an extra closing bracket or removing the extra opening bracket), the program gives an error when run. – Doorknob Nov 15 '16 at 1:10
• This now appears to output trailing whitespace at the ends of lines and at the end of the output, which is not allowed by the challenge specification. – Doorknob Nov 16 '16 at 3:57
• trivial golfs – Leaky Nun Jun 23 '17 at 16:58
• @LeakyNun Thanks. Are you just going through and golfing all of my answers? :P – HyperNeutrino Jun 23 '17 at 17:04

# Mathematica, 146 bytes

P=PadRight;T=Transpose;R=Riffle;Select[Rest@T@P@MapIndexed[""~Table~#2~Join~#1&,T@P@R[Characters/@#~R~{},{},3]]//.{0->"",{x__,""}->{x}},#!={""}&]&


I'm disappointed by this bytecount, but oh well.

Defines an anonymous function that takes a list of words (e.g. {"this","that","these"}) and returns a two-dimensional array of characters. To view in grid form, add a //Grid at the end.

Converts the strings to an array, adds extra lines, transposes the array, prepends the necessary shifts, then transposes again.

Example result (formatted as grid):

# Jelly, 24 bytes

z⁶j€⁾  µJ’⁶ẋ;"z⁶œr€⁶Yœr⁷


Try it online!

### How?

z⁶j€⁾  µJ’⁶ẋ;"z⁶œr€⁶Yœr⁷ - Main link: a list of strings
z                        - transpose with filler...
⁶                       -     space character
j€                     - join €ach with
⁾                    -     two spaces
µ                 - monadic chain separation, call the result x
J                - range(length(x)) [1,2,...,x]
’               - decrement (vectorises) [0,1,...x-1]
ẋ             - repeat (vectorises)
⁶              - a space ['', ' ',...,'x spaces']
"           - zip with
;            - concatenation (prefixes with the space strings)
z          - transpose with filler...
⁶         -     space character
œr€⁶     - trim spaces from the right of €ach
Y    - join with line feeds
œr⁷ - trim line feeds from the right
- implicit print


# Python 2, 182 bytes

def f(s):
M=max(map(len,s));p=' '*M;L=[p]+s+M*[p];r='';k=0
while k/M<len(s)*3+M:
i=k%M;w=k/M-i+1;r+=(L[(w/3+1)*(w%3==1)]+p)[i];k+=1
if i==M-1:r=r.rstrip()+'\n'
return r.strip()


A bit long, but on the positive side, it returns a string with no trailing white space on each line, and no trailing white space or returns at the end; constraints that some other entries don't obey.

A list of words is passed into the function; some 'blanks' are aded to this list and then the algorithm maps a row,column pair to a wordNumber, characterNumber in the expanded list. (This is a bit of the inverse of the usual strategy seen in other solutions).

If we allow trailing white space on all lines except the last, we can do a bit better (163 bytes):

def f(s):
M=max(map(len,s));p=' '*M;L=[p]+s+M*[p];r='';k=0
while k/M<len(s)*3+M:i=k%M;w=k/M-i+1;r+=(L[(w/3+1)*(w%3==1)]+p)[i]+'\n'*(i==M-1);k+=1
return r.strip()


# q/kdb+, 130109949086 84 bytes

Solution:

f:{-1(+)a rtrim(til(#)E){raze(x#" "),y,\:"  "}'E:(+)(a:{(max(#:)each x)$x})" "vs x;}  Examples: q)f "programming puzzles and code golf" p r o p g u r z a a z m n l m d e i c s n o g d g e o l f q)f "a bcd efgh i j" a b c d e f g i h j q)f (),"x" x q)f "verylongword short" v e r s y h l o o r n t g w o r d  Explanation (ungolfed): The basic gist is to create a bunch of equal length strings from the input string, flip (rotate) them, then add appropriate whitespace to get something that looks like this: "p p a c g " " r u n o o " " o z d d l " " g z e f" " r l " " a e " " m s " " m " " i " " n " " g "  which is flipped again, and printed to stdout. Here's a line-by-line breakdown of the concept: A:"programming puzzles and code golf"; // original input B:" " vs A; // split on " " C:max count each B; // find length of the longest string D:C$B;                                 // pad each string to this length
E:flip D;                              // flip (rotate) string
F:{raze(x#" "),y,\:"  "};              // appends each char with "  " and prepends an increasing number of " "
G:(til count E)F'E;                    // execute function F with each pair of 0..n and item in list E
H:max count each rtrim G;              // find longest string (ignoring right whitespace)
I:H$G; // pad each of the strings to this length J:flip I; // flip to get result -1 J; // print to stdout, swallow return value  Notes: A few ways to shave off some (11) easy bytes if we really wanted to: • Could save 2 bytes by dropping the f: and leaving as an anonymous function • Could save 3 bytes by dropping the -1 and ; and returning a list of strings rather than printing to stdout • Could save 6 bytes if we passed in a list of strings rather than space-separated string Edits: • -11 bytes, use rtrim to find max length to pad, removed need for storing C variable • -15 bytes, switching out the max count each for a lambda function a which is created once and used twice • -4 bytes, moving the raze into the lambda function to save a raze each • -4 bytes, simplified the core lambda function that adds the whitespace • -2 bytes, use (+) as shorthand for flip # Charcoal, 16 9 bytes ＷＳ«Ｐ↘ιＭ³↓  My first Charcoal answer. Thanks to @DLosc for suggestion Ｐ and Ｍ instead of using Ｓ and Ｊ (Jump) to go back to the start of the line (and three down). Explanation: Loop while there is still a next input-string: While(InputString()){ ... } ＷＳ« ...  Print this string without moving the cursor in a down-right direction: Multiprint(:DownRight, i); Ｐ↘ι  And then move three positions down for the next iteration: Move(3, :Down); Ｍ³↓  • When the challenge needs a single input consisting of an array, Charcoal fails as it splits the input string taking every single word as a separate input. But in Charcoal the θ variable represents the first input, so I just assign the test input to that variable in the header and then write the rest of the code, so you can get rid of the α variable and iterate over the splitted items of θ. Try it online! (Non-competing due to leading spaces.) – Charlie Jun 30 '17 at 10:30 • At least, nobody complained when I used that trick here. :-) – Charlie Jun 30 '17 at 10:34 • @CarlosAlejo I indeed came across your answer when I was looking for inspiration on existing Charcoal answers. :) – Kevin Cruijssen Jun 30 '17 at 10:41 • IDK, the method I usually use is just strings + empty string at the end, if any are multiline then input as a python array – ASCII-only Jul 27 '17 at 2:36 • @CarlosAlejo It's been a while, but I've just used multiple lines now with an empty line to break the while (and golfed 7 bytes at the same time). Saw it being used in one of Neil's answers, and I now see ASCII-only suggested the same thing (somehow missed that comment). – Kevin Cruijssen Aug 14 '17 at 14:47 # Japt -Rx, 1716 13 bytes Takes input as an array of words. If trailing whitespace on each line were allowed then the last 4 characters could be removed to tie with the Charcoal solution. yÈmú3)iYçÃmx1  ## Explanation y :Transpose È :Map each word at 0-based index Y m : Map each character ú3 : Right pad with spaces to length 3 ) : End mapping i : Prepend Yç : Space repeated Y times Ã :End mapping and transpose m :Map x1 : Trim right :Implicitly join with newlines, trim and output  # K4, 58 bytes Solution: +(|/{0+/|\|~^x}@'x)$x:(2-(!c)+3*#x)$" "/:'$+(c:|/#:'x)$x:  Examples: q)k)+(|/{0+/|\|~^x}@'x)$x:(2-(!c)+3*#x)$" "/:'$+(c:|/#:'x)$x:("programming";"puzzles";"and";"code";"golf") "p " " r " " o " "p g " " u r " " z a " "a z m " " n l m " " d e i " "c s n " " o g" " d " "g e " " o " " l " " f " q)k)+(|/{0+/|\|~^x}@'x)$x:(2-(!c)+3*#x)$" "/:'$+(c:|/#:'x)$x:(,"a";"bcd";"efgh";,"i";,"j") "a " " " " " "b " " c " " d " "e " " f " " g " "i h" " " " " "j " q)k)+(|/{0+/|\|~^x}@'x)$x:(2-(!c)+3*#x)$" "/:'$+(c:|/#:'x)$x:("verylongword";"short") "v " " e " " r " "s y " " h l " " o o " " r n " " t g " " w " " o " " r " " d"  Explanation: Right-pad strings so they are the same length, transpose, join with " ", left-pad to generate diagonals, then right-pad to correct lengths and transpose back. Takes a list of strings and returns a list of strings. Probably golfable but still shorter than my q/kdb+ solution. +(|/{0+/|\|~^x}@'x)$x:(2-(!c)+3*#x)$" "/:'$+(c:|/#:'x)$x: x: / save as variable x$        / pad
(        )         / do this together
#:'x          / count (#:) each (') x
|/              / max
c:                / save as variable c
+                   / flip / transpose
$/ string ($)
"  "/:'                     / join each with "  "
$/ pad ( ) / do this together #x / count (#) x 3* / multiply by 3 + / add to ( ) / do this together !c / range 0..c 2- / subtract from 2 x: / save as x:$                                            / pad
(                )                                             / do all this together
{         }@'x                                              / apply (@) lambda {} to each x
^x                                                  / null (^) x (" " is considered null)
~                                                    / not
|                                                     / reverse
|\                                                      / max (|) scan (\), maxs
0+/                                                        / sum (+) over (/) starting with 0
|/                                                            / max (|) over (/), max
+                                                               / transpose


{my@t;for .kv ->\i,\w{for w.comb.kv {@t[3*i+$^a][$^a]=$^b}};@t »||»" "}  Try it online! The input argument is a list of words. The output is an array of array of characters. # PHP, 100 bytes <?foreach($_GET as$k=>$v)for($x=0;$y=$v[$x];$t[$x++]=$y)($t=&$s[$k*3+$x])?:$t=" ";echo join("
",\$s);


Try it online!