Write a program or function that takes in a string guaranteed to only contain printable ASCII characters except for space, and to be a positive triangular number (1, 3, 6, 10, 15, ...) in length.
Print or return the same string, but shaped into a triangle using spaces. Some examples will best show what I mean:
If the input is R then the output will be
R
If the input is cat then the output will be
c
a t
If the input is monk3y then the output will be
m
o n
k 3 y
If the input is meanIngfu1 then the output will be
m
e a
n I n
g f u 1
If the input is ^/\/|\/[]\ then the output will be
^
/ \
/ | \
/ [ ] \
If the input is
Thisrunofcharactersismeanttohavealengththatcanbeexpressedasatriangularnumber.Diditwork?Youtellme,Ican'tcountverywell,ok?
then the output will be
T
h i
s r u
n o f c
h a r a c
t e r s i s
m e a n t t o
h a v e a l e n
g t h t h a t c a
n b e e x p r e s s
e d a s a t r i a n g
u l a r n u m b e r . D
i d i t w o r k ? Y o u t
e l l m e , I c a n ' t c o
u n t v e r y w e l l , o k ?
Basically, newlines are inserted between the substrings of triangular length, spaces are added between all characters, and each line is indented with spaces to fit the triangle shape.
A single trailing newline and lines with trailing spaces are optionally allowed, but otherwise your output should exactly match these examples. The last line of the triangle should not have leading spaces.
The shortest code in bytes wins.
-
\$\begingroup\$ Is there an absolute max the length of the string can be? \$\endgroup\$geokavel– geokavel2015年11月30日 06:33:49 +00:00Commented Nov 30, 2015 at 6:33
-
\$\begingroup\$ @geokavel It should work for any length of string your language can normally handle. \$\endgroup\$Calvin's Hobbies– Calvin's Hobbies2015年11月30日 06:41:52 +00:00Commented Nov 30, 2015 at 6:41
-
14\$\begingroup\$ Here's a Christmas tree for anyone who hasn't put theirs' up yet. */\/|\/|o\/|o|\/o|o|\/||o|o\/o|||o|\/o||o|||\/||o|||o|\/|o|||o||o\ \$\endgroup\$Timmy– Timmy2015年11月30日 20:30:36 +00:00Commented Nov 30, 2015 at 20:30
-
\$\begingroup\$ potentially related \$\endgroup\$JohnE– JohnE2015年12月02日 00:13:04 +00:00Commented Dec 2, 2015 at 0:13
-
\$\begingroup\$ I don't think my brainfuck handbook covers that \$\endgroup\$Lucca Ferri– Lucca Ferri2025年11月06日 19:34:57 +00:00Commented Nov 6 at 19:34
24 Answers 24
Python, 81 bytes
def f(s,p=''):
i=-int(len(2*s)**.5)
if s:f(s[:i],p+' ');print p+' '.join(s[i:])
A recursive function. Goes from the end of s, chopping off and printing characters. The number of characters to take is computed from the length of s. The function is set up to prints in reverse order of the recursive calls, which terminate when s is empty and then resolve back up the line. Each layer, the prefix p has an extra space added.
In Python 3, the if can be done via short circuiting, though this doesn't seem to save chars:
def f(s,p=''):i=-int(len(2*s)**.5);s and[f(s[:i],p+' '),print(p+' '.join(s[i:]))]
An equally-long alternative with inequality chaining:
def f(s,p=''):i=-int(len(2*s)**.5);''<s!=f(s[:i],p+' ')!=print(p+' '.join(s[i:]))
Both print and f return None, which is hard to use.
-
1\$\begingroup\$ This is quite clever. By chopping off the string one row at a time, you still end up with a triangular length string to compute the number of leading spaces with. \$\endgroup\$xsot– xsot2015年11月30日 09:54:36 +00:00Commented Nov 30, 2015 at 9:54
Pyth, 22 bytes
jua+L\ GjdHfTczsM._UzY
Try it online: Demonstration or Test Suite
Explanation:
jua+L\ GjdHfTczsM._UzY implicit: z = input string
Uz create the list [0, 1, ..., len(z)-1]
._ all prefixes of this list: [[0], [0,1], [0,1,2], ...]
sM sum up each sublist: [0, 1, 3, 6, 10, ...]
cz split z at these indices
fT remove all the unnecessary empty strings
this gives us the list of strings of the triangle
u Y reduce this list, with the initial value G = []
+L\ G prepend a space to each string in G
jdH join the current string with spaces
a and append it to G
j print each string on a separate line
Retina, (削除) 108 (削除ここまで) (削除) 102 (削除ここまで) (削除) 94 (削除ここまで) (削除) 87 (削除ここまで) (削除) 82 (削除ここまで) (削除) 64 (削除ここまで) 63 bytes
Thanks to Sp3000 for making me pursue my original approach, which brought the byte count from 108 down to 82.
Massive thanks to Kobi who found a much more elegant solution, which allowed me to save another 19 bytes on top of that.
S_`(?<=^(?<-1>.)*(?:(?<=\G(.)*).)+)
.
0ドル
m+`^(?=( *)\S.*\n1円)
<space>
Where <space> represents a single space character (which would otherwise be stripped by SE). For counting purposes, each line goes in a separate file and \n should be replaced with an actual linefeed character. For convenience, you can run the code as is from a single file with the -s flag.
Explanation
Well... as usual I can't give a full introduction to balancing groups here. For a primer see my Stack Overflow answer.
S_`(?<=^(?<-1>.)*(?:(?<=\G(.)*).)+)
The first stage is a Split stage, which splits the input into lines of increasing length. The _ indicates that empty chunks should be omitted from the splitting (which only affects the end, because there will be a match in the last position). The regex itself is entirely contained in a look-around so it won't match any characters, but only positions.
This part is based on Kobi's solution with some additional golfitude I found myself. Note that lookbehinds are matched right-to-left in .NET, so the following explanation should best be read bottom to top. I've also inserted another \G in the explanation for clarity, although that isn't necessary for the pattern to work.
(?<=
^ # And we ensure that we can reach the beginning of the stack by doing so.
# The first time this is possible will be exactly when tri(m-1) == tri(n-1),
# i.e. when m == n. Exactly what we want!
(?<-1>.)* # Now we keep matching individual characters while popping from group <1>.
\G # We've now matched m characters, while pushing i-1 captures for each i
# between 1 and m, inclusive. That is, group <1> contains tri(m-1) captures.
(?:
(?<=
\G # The \G anchor matches at the position of the last match.
(.)* # ...push one capture onto group <1> for each character between here
# here and the last match.
) # Then we use a lookahead to...
. # In each iteration we match a single character.
)+ # This group matches all the characters up to the last match (or the beginning
# of the string). Call that number m.
) # If the previous match was at position tri(n-1) then we want this match
# to happen exactly n characters later.
I'm still admiring Kobi's work here. This is even more elegant than the prime testing regex. :)
Let's move on to the next stage:
.
0ドル
Simple: insert a space after every non-linefeed character.
m+`^(?=( *)\S.*\n1円)
<space>
This last stage indents all the lines correctly to form the triangle. The m is just the usual multiline mode to make ^ match the beginning of a line. The + tells Retina to repeat this stage until the string stops changing (which, in this case means that the regex no longer matches).
^ # Match the beginning of a line.
(?= # A lookahead which checks if the matched line needs another space.
( *) # Capture the indent on the current line.
\S # Match a non-space character to ensure we've got the entire indent.
.*\n # Match the remainder of the line, as well as the linefeed.
1円 # Check that the next line has at least the same indent as this one.
)
So this matches the beginning of any line which doesn't have a bigger indent than the next. In any such position we insert a space. This process terminates, once the lines are arranged in a neat triangle, because that's the minimal layout where each line has a bigger indent than the next.
-
\$\begingroup\$ @_@ What the heck does it do? \$\endgroup\$n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳– n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳2015年12月01日 07:30:42 +00:00Commented Dec 1, 2015 at 7:30
-
\$\begingroup\$ @n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ Now with 100% more amazingness, courtesy of Kobi. \$\endgroup\$Martin Ender– Martin Ender2015年12月01日 20:13:01 +00:00Commented Dec 1, 2015 at 20:13
Candy, (削除) 67 (削除ここまで) (削除) 59 (削除ここまで) 57 bytes
(削除) &iZ1-=yZ1+Z*2/>{0g}0=z@1i&{|.}bYR(" ";=)ZR(=a&{;}" ";)"\n";Y1-=ya1j (削除ここまで)
(削除) &1-8*1+r1-2/=y@1i&{|.}bYR(" ";=)ZR(=a&{;}" ";)"\n";Y1-=ya1j (削除ここまで)
&8*7-r1-2/=y@1i&{|.}bYR(" ";=)ZR(=a&{;}" ";)"\n";Y1-=ya1j
or:
&
8 *
7 - r
1 - 2 /
= y @ 1 i
& { | . } b
Y R ( " " ;
= ) Z R ( = a &
{ ; } " " ; ) "
\ n " ; Y 1 - = y a
1 j
long form:
stackSz
digit8 # Y = (sqrt((numCh - 1) * 8 + 1) - 1) / 2 using pythagorean
mult # Y = (sqrt(numCh * 8 - 7) - 1) / 2 equivalent but shorter
digit7
sub
root
digit1
sub
digit2
div
popA
YGetsA
label digit1
incrZ
stackSz # bail if we're out of letters
if
else
retSub
endif
stack2
pushY # print the leading spaces (" " x Y)
range1
while
" " printChr
popA
endwhile
pushZ
range1 # output this row of characters (Z of them)
while
popA
stack1
stackSz
if
printChr # bail on unbalanced tree
endif
" " printChr
endwhile
"\n" printChr
pushY
digit1
sub
popA
YGetsA
stack1
digit1 jumpSub # loop using recursion
-
\$\begingroup\$ Yea, I felt Christmas-y. \$\endgroup\$Dale Johnson– Dale Johnson2015年12月03日 09:06:15 +00:00Commented Dec 3, 2015 at 9:06
CJam, (削除) 27 (削除ここまで) 26 bytes
Thanks to Sp3000 for saving 1 byte.
Lq{' @f+_,)@/(S*N+a@\+\s}h
(削除) Surprisingly close to Pyth, let's see if this can be golfed... (削除ここまで)
Explanation
L e# Push an empty array to build up the lines in.
q e# Read input.
{ e# While the top of the stack is truthy (non-empty)...
' @f+ e# Prepend a space to each line we already have.
_,) e# Get the number of lines we already have and increment.
@/ e# Split the input into chunks of that size.
(S* e# Pull off the first chunk (the next line) and join with spaces.
N+ e# Append a linefeed.
a@\+ e# Append it to our list of lines.
\s e# Pull up the other chunks of the input and join them back into one string.
}h
-
\$\begingroup\$ Why doesn't it work if I change
'toS??? \$\endgroup\$geokavel– geokavel2015年11月30日 17:06:35 +00:00Commented Nov 30, 2015 at 17:06 -
\$\begingroup\$ @geokavel Because
Sis a string, not a character, sofwill map over that string instead of the list of lines. \$\endgroup\$Martin Ender– Martin Ender2015年11月30日 17:07:18 +00:00Commented Nov 30, 2015 at 17:07 -
\$\begingroup\$ That was my guess. Do you have any idea as to the rationale for making S a string? \$\endgroup\$geokavel– geokavel2015年11月30日 17:12:21 +00:00Commented Nov 30, 2015 at 17:12
-
\$\begingroup\$ @geokavel No I don't. \$\endgroup\$Martin Ender– Martin Ender2015年11月30日 17:13:09 +00:00Commented Nov 30, 2015 at 17:13
Ruby, (削除) 84 (削除ここまで) (削除) 77 (削除ここまで) 73 bytes
->v{1.upto(n=v.size**0.5*1.4){|i|puts" "*(n-i)+v[i*(i-1)/2,i].chars*" "}}
77 bytes
->v{0.upto(n=(v.size*2)**0.5-1){|i|puts" "*(n-i)+v[i*(i+1)/2,i+1].chars*" "}}
Reduced few more bytes by removing variable r as suggested by steveverrill.
84 bytes
->v{n=(v.size*2)**0.5-1;0.upto(n){|i|puts" "*(n-i)+v[(r=i*(i+1)/2)..r+i].chars*" "}}
Ungolfed:
->v {
1.upto(n=v.size**0.5*1.4) { |i|
puts" "*(n-i)+v[i*(i-1)/2,i].chars*" "
}
}
First calculating triangular number from the input string
n=v.size**0.5*1.4
i.e. for example input string size is 120 and our triangular number n, will be 15.
puts" "*(n-i)+v[i*(i-1)/2,i].chars*" "
In the above line, it prints spaces followed by series of string which are fetched from the input string using following pattern
[[0,0],[1,2],[3,5],[6,9]]
Usage:
f=->v{1.upto(n=v.size**0.5*1.4){|i|puts" "*(n-i)+v[i*(i-1)/2,i].chars*" "}}
f["Thisrunofcharactersismeanttohavealengththatcanbeexpressesasatriangularnumber.Diditwork?Youtellme,Ican'tcountverywell,ok?"]
T
h i
s r u
n o f c
h a r a c
t e r s i s
m e a n t t o
h a v e a l e n
g t h t h a t c a
n b e e x p r e s s
e s a s a t r i a n g
u l a r n u m b e r . D
i d i t w o r k ? Y o u t
e l l m e , I c a n ' t c o
u n t v e r y w e l l , o k ?
-
\$\begingroup\$ Wow, our approaches are very similar, but we seem to have complementary golfing knowledge. I didn't know
uptodoesn't require an integer argument, (timesmost certainly does.) I've incorporated some of your syntax into a revision of my answer. The biggest tip I have for you is, you don't need that variabler. Just use a,instead of..and the number after the comma is the total number of elements to return, rather than the end of the range. \$\endgroup\$Level River St– Level River St2015年11月30日 21:23:15 +00:00Commented Nov 30, 2015 at 21:23 -
\$\begingroup\$ True. Thanks for the tip i'm updating my answer right away :) \$\endgroup\$Vasu Adari– Vasu Adari2015年12月01日 06:58:32 +00:00Commented Dec 1, 2015 at 6:58
Pyth, 27 bytes
Js.IsSGlzWz+*-J=hZdjd<~>zZZ
z = input()
Z = 0
d = ' '
sSG G -> tri(G)
.I lz Find the (float) input whose output is len(z).
s Convert to int.
J Save as J.
Wz while z:
=hZ Z += 1
*-J Zd Generate J-Z spaces.
~>zZ Remove the first Z characters from z.
< Z Generate those first Z characters.
jd Join on spaces.
+ Add the two together and print.
An interesting approach - imperative, and uses .I. Probably golfable.
C, (削除) 138 (削除ここまで) (削除) 136 (削除ここまで) 134 bytes
Takes a string as an input :
j,r,k,a;f(char*s){j=strlen(s);r=k=sqrt(1+8*j)/2;for(;r--;printf("\n")){for(j=r;j--;)printf(" ");for(j=k-r;j--;)printf("%c ",s[a++]);}}
-
\$\begingroup\$ You seem to have beat JavaScript with C by 1 byte so far :D \$\endgroup\$Mark K Cowan– Mark K Cowan2015年11月30日 23:51:09 +00:00Commented Nov 30, 2015 at 23:51
-
\$\begingroup\$ @MarkKCowan yes, apparently. I hope I make it even smaller! :) \$\endgroup\$Sahil Arora– Sahil Arora2015年12月01日 09:30:21 +00:00Commented Dec 1, 2015 at 9:30
-
\$\begingroup\$ @SahilArora - You can replace
printf(" ")andprintf("\n")withputs(" ")andputs("\n"). Each substitution will save you 2 bytes.:) \$\endgroup\$enhzflep– enhzflep2015年12月02日 09:33:32 +00:00Commented Dec 2, 2015 at 9:33 -
\$\begingroup\$ @enhzflep I tried it already, it gave an ambiguous output! \$\endgroup\$Sahil Arora– Sahil Arora2015年12月02日 09:45:14 +00:00Commented Dec 2, 2015 at 9:45
-
\$\begingroup\$ Oh. :( Works fine here on win7 with gcc 4.7.1 - I guess it's to do with the way that the printf output is flushed to stdout. +1 for beating Javascript. \$\endgroup\$enhzflep– enhzflep2015年12月02日 09:56:52 +00:00Commented Dec 2, 2015 at 9:56
Ruby approach 2 rev 1, 76 bytes
->s{s=s.chars*' '
0.upto(w=s.size**0.5-1){|i|puts' '*(w-i)+s[i*i+i,i*2+2]}}
Optimized using syntax ideas from Vasu Adari's answer, plus a few twists of my own.
Ruby approach 2 rev 0, 93 bytes
->s{s=s.chars.to_a.join(' ')
w=(s.size**0.5).to_i
w.times{|i|puts' '*(w-i-1)+s[i*i+i,i*2+2]}}
Completely different approach. First we add spaces in between the characters of the input. Then we print out the rows line by line.
Ruby approach 1, 94 bytes
->s{n=-1;w=((s.size*2)**0.5).to_i
(w*w).times{|i|print i/w+i%w<w-1?'':s[n+=1],-i%w==1?$/:' '}}
this ended up far longer than anticipated.
w contains the number of printable characters in the bottom row, or equivalently, the number of lines.
Every line contains w whitespace characters (the last of which is the newline) so the idea is to print these whitespace characters and insert the printable characters where necessary.
Minkolang 0.14, 42 bytes
(xid2;$I2*`,)1-[i1+[" "o]lrx" "$ii-1-D$O].
Explanation
( Open while loop
x Dump top of stack
i Loop counter (i)
d2; Duplicate and square
$I2* Length of input times two
`, Push (i^2) <= (length of input)
) Close for loop; pop top of stack and exit when it's 0
1-[ Open for loop that repeats sqrt(len(input))-1 times
i1+[ Open for loop that repeats (loop counter + 1) times
" "o Push a space then read in character from input
] Close for loop
l Push 10 (newline)
r Reverse stack
x Dump top of stack
" " Push a space
$i Push the max iterations of for loop
i- Subtract loop counter
1- Subtract 1
D Pop n and duplicate top of stack n times
$O Output whole stack as characters
]. Close for loop and stop.
-
2\$\begingroup\$ Such a perfect byte count! good job! \$\endgroup\$TanMath– TanMath2015年11月30日 07:31:19 +00:00Commented Nov 30, 2015 at 7:31
-
1\$\begingroup\$ @TanMath but 42 is not a triangular number! \$\endgroup\$Paŭlo Ebermann– Paŭlo Ebermann2015年11月30日 21:16:07 +00:00Commented Nov 30, 2015 at 21:16
Python 2, (削除) 88 (削除ここまで) 85 bytes
s=t=raw_input()
i=1
while s:print' '*int(len(t*2)**.5-i)+' '.join(s[:i]);s=s[i:];i+=1
Thanks xnor for saving 3 bytes.
-
\$\begingroup\$ Doesn't shortening
smess up the number-of-spaces calculation? \$\endgroup\$xnor– xnor2015年11月30日 09:07:30 +00:00Commented Nov 30, 2015 at 9:07 -
\$\begingroup\$ Oh right. I removed a temporary variable before submitting but didn't realise that it invalidated the code. \$\endgroup\$xsot– xsot2015年11月30日 09:11:59 +00:00Commented Nov 30, 2015 at 9:11
-
\$\begingroup\$ What if you do like before but save a back-up
S=s=raw_input()? \$\endgroup\$xnor– xnor2015年11月30日 09:14:48 +00:00Commented Nov 30, 2015 at 9:14 -
\$\begingroup\$ Good suggestion. I think there's probably a shorter overall strategy though. \$\endgroup\$xsot– xsot2015年11月30日 09:17:37 +00:00Commented Nov 30, 2015 at 9:17
-
\$\begingroup\$ Crossed out 88 looks funny \$\endgroup\$pinkfloydx33– pinkfloydx332015年11月30日 18:17:02 +00:00Commented Nov 30, 2015 at 18:17
CJam, 50 Bytes
q:QQ,1>{,{),:+}%:RQ,#:IR2ew<{~Q<>:LS*L,I+(Se[N}%}&
Explanation
q:QQ,1>{ e# Only proceed if string length > 1, otherwise just print.
,{),:}%:R e# Generates a list of sums from 0 to k, where k goes from 0 to the length of the string [0,1,3,6,10,15,21,...]
Q,#:I e# Find the index of the length of the string in the list
R2ew< e# Make a list that looks like [[0,1],[1,3],[3,6],...,[?,n] ]where n is the length of the string
{~Q<>:L e# Use that list to get substrings of the string using the pairs as start and end indices
S* e# Put spaces between the substrings
L,I+(Se[N e# (Length of the substring + Index of string length in sum array -1) is the length the line should be padded with spaces to. Add a new line at the end.
%}&
JavaScript (ES6), 135 bytes
w=>{r='';for(s=j=0;j<w.length;j+=s++);for(i=j=0;w[j+i];j+=++i)r+=Array(s-i-1).join` `+w.slice(j,i+j+1).split``.join` `+'<br>';return r}
De-golf + demo:
function t(w) {
r = '';
for (s = j = 0; j < w.length; j += s++);
for (i = j = 0; w[j + i]; j += ++i) r += Array(s - i - 1).join` ` + w.slice(j, i + j + 1).split``.join` ` + '<br>';
return r;
}
document.write('<pre>' + t(prompt()));
-
\$\begingroup\$ What's the goal of
for (s = j = 0; j < w.length; j += s++);? Also, inside a<pre>, you can use\ninstead of<br>. Also, you forgot to mention that it is ES6. \$\endgroup\$Ismael Miguel– Ismael Miguel2015年12月01日 12:03:04 +00:00Commented Dec 1, 2015 at 12:03 -
\$\begingroup\$ The goal of the first loop is to count the length of the last line, so as to indent each line properly. \$\endgroup\$nicael– nicael2015年12月01日 12:29:53 +00:00Commented Dec 1, 2015 at 12:29
Java, (削除) 258 (削除ここまで) 194
Golfed:
String f(String a){String r="";int t=(((int)Math.sqrt(8*a.length()+1))-1)/2-1;int i=0,n=0;while(n++<=t){for(int s=-1;s<t-n;++s)r+=" ";for(int j=0;j<n;++j)r+=a.charAt(i++)+" ";r+="\n";}return r;}
Ungolfed:
public class TriangulatingText {
public static void main(String[] a) {
// @formatter:off
String[] testData = new String[] {
"R",
"cat",
"monk3y",
"meanIngfu1",
"^/\\/|\\/[]\\",
"Thisrunofcharactersismeanttohavealengththatcanbeexpressedasatriangularnumber.Diditwork?Youtellme,Ican'tcountverywell,ok?",
};
// @formatter:on
for (String data : testData) {
System.out.println("f(\"" + data + "\")");
System.out.println(new TriangulatingText().f(data));
}
}
// Begin golf
String f(String a) {
String r = "";
int t = (((int) Math.sqrt(8 * a.length() + 1)) - 1) / 2 - 1;
int i = 0, n = 0;
while (n++ <= t) {
for (int s = -1; s < t - n; ++s)
r += " ";
for (int j = 0; j < n; ++j)
r += a.charAt(i++) + " ";
r += "\n";
}
return r;
}
// End golf
}
Program output:
f("R")
R
f("cat")
c
a t
f("monk3y")
m
o n
k 3 y
f("meanIngfu1")
m
e a
n I n
g f u 1
f("^/\/|\/[]\")
^
/ \
/ | \
/ [ ] \
f("Thisrunofcharactersismeanttohavealengththatcanbeexpressedasatriangularnumber.Diditwork?Youtellme,Ican'tcountverywell,ok?")
T
h i
s r u
n o f c
h a r a c
t e r s i s
m e a n t t o
h a v e a l e n
g t h t h a t c a
n b e e x p r e s s
e d a s a t r i a n g
u l a r n u m b e r . D
i d i t w o r k ? Y o u t
e l l m e , I c a n ' t c o
u n t v e r y w e l l , o k ?
-
\$\begingroup\$ You could probably statically import System.out to save some bytes. \$\endgroup\$randers– randers2015年12月11日 17:43:42 +00:00Commented Dec 11, 2015 at 17:43
-
\$\begingroup\$
import static System.out;is 25 bytes, andSystem.is 7 bytes. It is used three times, and 21 < 25 so it would actually increase the size by 4 bytes. Good lead, though, static imports can save space and not everyone knows about them. \$\endgroup\$user18932– user189322015年12月11日 18:22:16 +00:00Commented Dec 11, 2015 at 18:22 -
1\$\begingroup\$ I was going through old answers when I found this one: "write a program or function" which I didn't realize at first. Stripping out the class stuff saved space. I made it into a proper function and found a few more bytes to shave off. \$\endgroup\$user18932– user189322016年08月09日 21:38:16 +00:00Commented Aug 9, 2016 at 21:38
JavaScript (ES6), 106 bytes
a=>(y=z=0,(f=p=>p?" ".repeat(--p)+a.split``.slice(y,y+=++z).join` `+`
`+f(p):"")(Math.sqrt(2*a.length)|0))
Uses recursion instead of a for loop to build the string.
To find the length of the longest row, use the formula for the nth triangular number T_n is T_n = (n^2 + n)/2. Given n and solving for T_n using the quadratic formula, we have:
1/2 * n^2 + 1/2 * n - T_n = 0
a = 1/2, b = 1/2, c = -T_n
-1/2 + sqrt(1/2^2 - 4*1/2*-T_n)
------------------------------- = sqrt(1/4 + 2*T_n) - 1/2
2*1/2
It turns out that after flooring, adding 1/4 inside the square root doesn't change the result, hence the formula for the longest row is Math.sqrt(2*a.length)|0.
TeaScript, 44 Bytes
r(m=$s(2*xn)|0)ßp.R(m-i)+x·.S(v,v+=Æw)jø+§)μ
This uses the same method as my JavaScript answer, but is a lot shorter.
Ungolfed
r(m=$s(2*xn)|0)m(#p.R(m-i)+xs``.S(v,v+=++w)j` `+`
`)j``
Powershell, 69 bytes
($args|% t*y|?{$r+="$_ ";++$p-gt$l}|%{$r;rv r,p;$l++})|%{' '*--$l+$_}
Less golfed test script:
$f = {
(
$args|% t*y|?{ # test predicate for each char in a argument string
$r+="$_ " # add current char to the result string
++$p-gt$l # return predicate value: current char posision is greater then line num
}|%{ # if predicate is True
$r # push the result string to a pipe
rv r,p # Remove-Variable r,p. This variables will be undefined after it.
$l++ # increment line number
}
)|%{ # new loop after processing all characters and calculating $l
' '*--$l+$_ # add spaces to the start of lines
} # and push a result to a pipe
}
@(
,("R",
"R ")
,("cat",
" c ",
"a t ")
,("monk3y",
" m ",
" o n ",
"k 3 y ")
,("meanIngfu1",
" m ",
" e a ",
" n I n ",
"g f u 1 ")
,("^/\/|\/[]\",
" ^ ",
" / \ ",
" / | \ ",
"/ [ ] \ ")
,("Thisrunofcharactersismeanttohavealengththatcanbeexpressedasatriangularnumber.Diditwork?Youtellme,Ican'tcountverywell,ok?",
" T ",
" h i ",
" s r u ",
" n o f c ",
" h a r a c ",
" t e r s i s ",
" m e a n t t o ",
" h a v e a l e n ",
" g t h t h a t c a ",
" n b e e x p r e s s ",
" e d a s a t r i a n g ",
" u l a r n u m b e r . D ",
" i d i t w o r k ? Y o u t ",
" e l l m e , I c a n ' t c o ",
"u n t v e r y w e l l , o k ? ")
,("*/\/|\/|o\/|o|\/o|o|\/||o|o\/o|||o|\/o||o|||\/||o|||o|\/|o|||o||o\",
" * ",
" / \ ",
" / | \ ",
" / | o \ ",
" / | o | \ ",
" / o | o | \ ",
" / | | o | o \ ",
" / o | | | o | \ ",
" / o | | o | | | \ ",
" / | | o | | | o | \ ",
"/ | o | | | o | | o \ ")
) | % {
$s,$expected = $_
$result = &$f $s
"$result"-eq"$expected"
$result
}
Output:
True
R
True
c
a t
True
m
o n
k 3 y
True
m
e a
n I n
g f u 1
True
^
/ \
/ | \
/ [ ] \
True
T
h i
s r u
n o f c
h a r a c
t e r s i s
m e a n t t o
h a v e a l e n
g t h t h a t c a
n b e e x p r e s s
e d a s a t r i a n g
u l a r n u m b e r . D
i d i t w o r k ? Y o u t
e l l m e , I c a n ' t c o
u n t v e r y w e l l , o k ?
True
*
/ \
/ | \
/ | o \
/ | o | \
/ o | o | \
/ | | o | o \
/ o | | | o | \
/ o | | o | | | \
/ | | o | | | o | \
/ | o | | | o | | o \
Vyxal C, 5 bytes
KÞṁvṄ
Þṁ # Mold (without repeating elements) to...
K # Prefixes
vṄ # Join each on spaces
# (C flag) center the result
C#, 202
string r(string s,List<string> o,int i=1){o=o.Select(p=>" "+p).ToList();o.Add(String.Join(" ",s.Substring(0,i).ToCharArray()));return s.Length==i?String.Join("\n",o):r(s.Substring(i,s.Length-i),o,i+1);}
I don't know if this is legal in code-golf but, does passing a list in the function count? I can't find a way to recurse this without a List< string> declared outside the function so I put it as a parameter.
Usage:
r("1",new List<string>());
r("123", new List<string>());
r("123456", new List<string>());
r("Thisrunofcharactersismeanttohavealengththatcanbeexpressedasatriangularnumber.Diditwork?Youtellme,Icanstcountverywell,ok?",new List<string>());
C, 102 bytes
i,j;main(n,s){for(n=sqrt(strlen(gets(s))*2);j<n;printf("%*.1s",i>1?2:i*(n-j),i++>j?i=!++j,"\n":s++));}
Bash + sed, 87
for((;i<${#1};i+=j));{
a+=(${1:i:++j})
}
printf %${j}s\\n ${a[@]}|sed 's/\S/ &/g;s/.//'
R, 142 bytes
Pretty sure I can get this down more. Still working on that though. I feel like I'm missing an easy recursion -- but I haven't been able to shorten it right.
f=function(a){n=nchar(a);l=which(cumsum(1:n)==n);w=strsplit(a,c())[[1]];for(i in 1:l){cat(rep(" ",l-i),sep="");cat(w[1:i],"\n");w=w[-(1:i)]}}
ungolfed
f=function(a){
n = nchar(a) #number of characters
l= which(cumsum(1:n)==n) #which triangle number
w= strsplit(a,c())[[1]] #Splits string into vector of characters
for (i in 1:l) {
cat(rep(" ",l-i),sep="") #preceeding spaces
cat(w[1:i],"\n") #Letters
w=w[-(1:i)] #Shifts removes letters (simplifies indexing)
}
}
Explore related questions
See similar questions with these tags.