# Make text triangle waves

I was messing around on my 'ol TI-84 CE and made a program that produced this output (it was actually bigger but that is not the point):

 *
*  *
*  *  *
*  *
*
*  *
*  *  *
*  *
*
...


I evolved it to take input text and make the triangle waves out of that. The final step was to also take a number to specify the size (n>0). But I am super lazy so you must do it for me!

# Challenge

Given a string and number (n > 0), output a triangle wave. This should be in the following format (with * as the string input)

 *
*  *
*  *  *
*  *  * *
*  *  * * (...)
*  *  * *
*  *  *
*  *
*
*
*  *
*  *  *
*  *  * *
*  *  * * (...)
*  *  * *
*  *  *
*  *
*
(...)

• Each line starts with 1 space on the left edge.

• The first line should have * on the right edge, for a full line of *.

• Every line after that, for the next n - 1 lines, you add *, <linenumber> times. So for n=3:

 *
*  *
*  *  *
*  *
*

• Then, output this full triangle infinitely:
 *
*  *
*  *  *
*  *
*
*  *
*  *  *
*  *
*


Note that you can't have something like this, for n=2:

 *
*  *
*
*
*  *
*


You must trim the repeated single *.

Another example, with a multichar string input:

'hi', 4 ->

hi
hi  hi
hi  hi  hi
hi  hi  hi  hi
hi  hi  hi
hi  hi
hi
hi  hi
hi  hi  hi
...


### Assorted other rules:

• Output must be immediately visible (i.e. it will wait to display until the program ends)

• You may take the input in any reasonable way, so ["hi",3] is allowed but ["h",1,"i"] is not. However, you may not use Ans to take input in TI-Basic programs.

• You must continue the pattern forever, or until the program ends due to memory limits.

• You do not need to have trailing spaces but leading spaces are required.

• You must print up to one line at a time. (i.e. each line must be printed all at once, you can't print each triangle iteration by itself)

• The one space padding is before and after each instance of the text

Leading or trailing newlines are fine.

• Would it be acceptable to take the input with a trailing space? That is, the input * would be "*<space>", hi would be "hi<space>", etc. – DJMcMayhem Apr 20 '17 at 16:30
• @DownChristopher That is the standard method used for input for TI. Arbitrarily banning something a specific language uses just because you don't like it doesn't make sense. – mbomb007 Apr 20 '17 at 16:46
• Strange. How is this question unclear? It seems to be very well specified. – cleblanc Apr 20 '17 at 20:19
• @mbomb007 I personally don't like the use. I even posted my own answer to show how I believe it should work – Christopher Apr 21 '17 at 20:26
• @cleblanc, it wasn't me who cast that close vote, but I see the point of whoever it was. There isn't an actual spec: it has to be reverse engineered from two examples. – Peter Taylor Apr 22 '17 at 5:32

# 05AB1E, 13 12 bytes

1 byte saved thanks to Erik the Outgolfer

[¹ð.ø²Lû¨×€,


Try it online!

Run locally if you want the lines displayed 1 at a time.

Explanation

[              # start infinite loop
¹ð.ø          # surround the first input by a space on each side
²Lû¨      # construct the range [1 ... n ... 2]
×     # replace each number in the range by that many instances of the string
€    # for each string in the list
,   # print it on a separate line

• Could also point out that the 2 warning messages at the bottom are indicative of infinite recursion in this specific case. – Magic Octopus Urn Apr 21 '17 at 19:30

t#n=mapM putStrLn[[1..n-abs m]>>' ':t++" "|m<-[1-n..n-2]]>>t#n


Try it online! Example usage: "somestring" # 5.

Edit: Saved 6 bytes thanks to @Ørjan Johansen!

Given for example n=4, [1-n..n-2] constructs the list [-3,-2,-1,0,1,2]. For each element m in this list, [1..n-abs m] is a list of length n minus the absolute value of m, thus we get lists of length 4-3, 4-2, 4-1, 4-0, 4-1 and 4-2, that is 1, 2, 3, 4, 3 and 2. For each of this numbers >>' ':t++" " concatenates as many times the given string t with a space added to back and front.

This yields a list of strings with the first triangle. mapM putStrLn prints each of the strings in the list on a new line, then the function # calls itself again with the same arguments and starts over.

• You can save 2 bytes with a list comprehension, and 2 more by shifting the indices and moving one item so that you get ([2..n]++[n+1,n..3]). – Ørjan Johansen Apr 20 '17 at 18:33
• 2 more bytes: [1..n-abs m] and [1-n..n-2]. – Ørjan Johansen Apr 20 '17 at 23:31
• @ØrjanJohansen Thanks a lot! – Laikoni Apr 21 '17 at 18:14

# Scala, 79 Bytes

(s:String,n:Int)=>while(1>0)(1 to n)++(n-1 to 2 by-1)map(y=>println(s" $s "*y))  Try it online! My first attempt at one of these. The basic idea is to generate a sequence of numbers, from 1 to n, then concatenated with the reverse (minus the ends to avoid doubling up). Then just loop over those numbers and print the input plus spaces that many times for each number in our generated sequence. Ungolfed: (text: String, n: Int) => while(1 > 0) { //loop forever ((1 to n) ++ (n-1 to 2 by-1)) //Generate a sequence of numbers, from 1 to n //and then concatenate it with the sequence n-1 to 2 .map(y=>println(s"$text " * y))  //for each number y in the sequence we generated,
// print the input text, surrounded by spaces, y times
}

• Welcome to PPCG! Great first post! – Rɪᴋᴇʀ Apr 22 '17 at 1:37
• Very well done! I like it! – Christopher Apr 22 '17 at 13:02

# Java 7, 128129128 125 bytes

+1 byte: Missed the padding after each character

-1 byte: Changed k==1 to k<2

-3 byes thanks to Kevin Cruijssen

void a(String s,int i){s=" "+s;for(int j=-1,k=1,l;;k+=j){for(l=0;l<k;)System.out.print(s+(++l<k?" ":"\n"));j=k==i|k<2?-j:j;}}


First post here so let me know if I'm doing something wrong. Any golfing help is much appreciated.

Try it online! Note: this times out after 60 seconds and then prints the results, the actual code continually prints infinitely

Ungolfed

void a(String s,int i){
s= " " + s;

for(int j=-1, k=1, l;; k+=j){
for(l=0; l<k;)
System.out.print(s+ (++l < k ? " " : "\n"));

j = (k == i | k < 2) ? -j : j;
}
}


Prepends a space to the input string then starts an infinite loop. For each iteration it prints the string k times and then prints a new line. k is then incremented / decremented based on the sign of j

• Hi, welcome to PPCG! One thing you can golf is removing the int  from the second for-loop and adding ,l to the first for -2 bytes. Another thing you can golf is by changing if(k==i|k<2)j=-j; to j=k==i|k<2?-j:j; for -1 byte. – Kevin Cruijssen May 4 '17 at 15:21
• Thanks, I feel like I'm missing stuff that should be obvious, but I'm hopefully going to learn from this – PunPun1000 May 4 '17 at 15:30
• For your first answer you did great, a lot better than when I joined! You automatically learn along the way. Just keep mental notes of golfing tips you come across, and if you haven't already, take a look at Tips for golfing in <all languages> and Tips for golfing in Java. Enjoy your stay! :) – Kevin Cruijssen May 4 '17 at 18:17
• Thanks. I've done a bit (or a lot) of lurking around here so I've seen some of the standard things for golfing. I just haven't gotten used to applying them – PunPun1000 May 4 '17 at 18:19

# C (gcc), 127108107 102 bytes

The loop in MACRO P prints each line, the for(j) loops print up and down the wave.

-5 byte thanks to ceilingcat.

#define P for(i=j;i--;printf(" %s%c",s,i?32:10))
i,j;f(s,n){for(;j++<n;)P;for(--j;j^1&&j--;)P;f(s,n);}


Try it online!

• That is a mess. Can you explain? – Christopher Apr 20 '17 at 15:54
• 99 bytes – ceilingcat Apr 26 at 17:29

# Röda, 49 bytes

f n,s{{{seq 1,n;seq n-1,2}while[]}|print $s *_}  Try it online! # Jelly, 13 15 bytes +2 bytes to fix up to print each line separately. ⁶;WṁÐ€ŒḄṖK€Ṅ€ȧß  Try it online! (note that TIO produces the would-be constant output only after it times out, errors, or, as in this case most likely, exceeds the text limit; offline it prints line by line.) ### How? ⁶;WṁÐ€ŒḄṖK€Ṅ€ȧß - Main link: string s, integer n ⁶ - literal ' ' ; - concatenated with s W - wrap in a list ṁÐ€ - mould like mapped over n (mould like [[1],[1,2],[1,2,3],...,[1,2,3,...,n]] - half of a sawtooth) ŒḄ - bounce (reflect but only with one central element to make a triangle) Ṗ - pop (remove the last element since the sawtooth triangles only have one shortest element between them, not two) K€ - join with spaces for €ach Ṅ€ - print and yield for €ach ȧ - and ß - call this link with the same arity  • @Laikoni thanks - fixed – Jonathan Allan Apr 20 '17 at 16:19 ## C, 85 bytes i,c,d;f(s,n)char*s;{for(;;)for(i=c+=d=c^n?c<2?1:d:-1;i;printf(" %s%c",s,--i?32:10));}  # Python 3, 1241089490 89 bytes r=range x=lambda c,n:print('\n'.join(f' {c} '*i for i in[*r(1,n+1),*r(n-1,1,-1)]))+x(c,n)  Recursive lambda that would obviously error out if it ever got to evaluating itself (Adding an infinite sequence of Nones?). Thankfully, it doesn't! It will still crash relatively soon, because of the default recursion limit, which can be overwritten using sys.setrecursionlimit(large_number) Ungolfed: def triangles(char, N): print( '\n'.join( # f' {char} ' is like ' {char} '.format(char=char) f' {char} ' * i for i in [*range(1, N+1), *range(N-1, 1, -1)] # N=3 -> [1, 2, 3, 2, 1] ) ) + triangles(char, N)  • Nice! That one is cool – Christopher Apr 21 '17 at 10:04 # Python 3, 92 Bytes from itertools import* lambda b,a:[print(f" {b} "*(abs(i%(a*2-2)-(a-1))+1))for i in count()]  This code does require itertools, which is a native library in Python. I imported cycle as c. • @L3viathan That's what the question was asking? What do you mean? – Neil Apr 21 '17 at 15:54 • @L3viathan I suppose I really should have just edited my comments instead of deleting, but basically, I fixed it. – Neil Apr 21 '17 at 16:10 # PowerShell, 72 bytes param($a,$b)$a=" $a ";if($b-1){for(){1..$b+($b-1)..2|%{$a*$_}}}for(){$a}  Try it online! (TIO has a 60 second timeout, but please be nice to Dennis' server ... also note that TIO doesn't output (refresh the page) until the program completes, so you won't get on-the-fly output. Running this locally produces correct output.) Straightforward. Takes input $a as the string and $b as the integer. We then pad $a with spaces and save it back. We then have an if check to handle the special case of $b=1. If $b>1 then this test is $TRUE and we enter the if. Inside the if, we're entering an infinite for() loop. Inside the loop, we're constructing a range from 1 to $b and then $b-1 to 2. There are two possibilities here. If $b=2, this range is 1,2,1,2 and so we're actually constructing two triangles every for loop. If $b>2, then the range is something like 1,2,3,4,3,2 to construct one triangle every for loop. Inside the range loop, |%{}, we just string-multiply $a by the appropriate number.

If $b=1 then we don't enter the if, and so just enter a separate infinite for() loop that prints $a a bunch of times.

By default, PowerShell will "flush" the pipeline (for lack of a better term) on each for iteration, so that's where the implicit Write-Output happens.

• Wow. That is cool. Don't worry about TIO I talked to Dennis and he said that it won't matter unless we all do this at once – Christopher Apr 20 '17 at 16:00

# JavaScript ES6, 98 bytes

s=>n=>{while(1){for(i=0;i++<n;)eval(p="console.log( ${s} .repeat(i))");i--;for(;--i>1;)eval(p)}}  Try it online! # CJam, 30 bytes l~,:)_W%1>W<+S2*@*f*{_Nf+:o!}g  Try it online! (same as with other answers: TIO dumps all output after 60 seconds, you have to run it locally to see the proper behaviour) Explanation Example input: "hi" 4 l~ e# Read an eval a line of input e# STACK: ["hi" 4] ,:) e# Generate the range 1 ... N e# STACK: ["hi" [1 2 3 4]] _W% e# Duplicate and reverse it e# STACK: ["hi" [1 2 3 4] [4 3 2 1]] 1>W< e# Slice to remove the first and last elements of the copy e# STACK: ["hi" [1 2 3 4] [3 2]] + e# Concatenate e# STACK: ["hi" [1 2 3 4 3 2]] S2* e# Push " " e# STACK: ["hi" [1 2 3 4 3 2] " "] @* e# Bring the text to the top and join the space string with it e# STACK: [[1 2 3 4 3 2] " hi "] f* e# Repeat the resulting string by each number in the range e# STACK: [[" hi " " hi hi " " hi hi hi " .....]] { e# Do: _ e# Duplicate the top e# STACK: [[" hi " " hi hi "...] [" hi " " hi hi "...]] Nf+ e# Append a newline to each string in the top array e# STACK: [[" hi " " hi hi "...] [" hi \n" " hi hi \n"...]] :o e# Pop and print each string in the top array (one by one) e# STACK: [[" hi " " hi hi "...] []] ! e# Boolean negation e# STACK: [[" hi " " hi hi "...] 1] }g e# While the top of stack (popped) is truthy e# STACK: [[" hi " " hi hi " " hi hi hi " .....]]  ## Batch, 108 bytes @set f=@for /l %%i in (2,1,%1)do @call echo %%s:.= %2 %%^&call set s=%%s @set s=. %f%%%. %f%:~1%% @%0 %*  Conveniently I both need to use the current value of a string in a for loop and substitute into it with another variable. Ungolfed: @echo off setlocal enabledelayedexpansion set s=. :l for /l %%i in (2, 1, %1) do echo !s:.= %2 !&set s=!s!. for /l %%i in (2, 1, %1) do echo !s:.= %2 !&set s=!s:~1! goto l  # Jelly, 13 bytes ⁾ jẋŒḄ}ṖṄ€1¿  Try it online! ### How it works ⁾ jẋŒḄ}ṖṄ€¹¿ Main link. Left argument: s (string). Right argument: n (integer) ⁾ j Join " " with separator s, prepending and appending a space to s. ŒḄ} Bounce right; yield [1, ..., n, ..., 1]. ẋ Repeat (" "+s+" ") 1, ..., n, ..., 1 times, yielding a string array. Ṗ Pop; remove the last string. 1¿ While 1 is truthy: Ṅ€ Print each string, followed by a linefeed.  • That is some fast code. Good job – Christopher Apr 22 '17 at 18:15 # Excel VBA, 97 Bytes Anonymous VBE immediate Window Function that takes input of String from cell [A1] and variant/String of assumed type integer from cell [B1] and outputs a triangle wave using those values to the VBE immediate window. n=[b1]:Do:DoEvents:For i=1To 2*n-2:For j=1To i-2*Int(i/n)*(i Mod n):?[A1] &" ";:Next:?:Next:Loop  # Lua, 104 bytes p=print;function f(s,n)c=" "..s;while(0)do p(c)for i=2,n+n-2 do p(c:rep(i<=n and i or n+n-i))end end end  # Groovy, 82 80 bytes {s,n->s+=" ";a=0;x={println s*a};for(;;){for(;a<n;a++){x()};for(;a>1;a--){x()}}}  Previous answer {s,n->s+=" ";a=0;x={println s*a};for(;;){while(a<n){x();a++};while(a>1){x();a--}}}  Ungolfed (previous answer) h={s,n-> //A closure with two arguments, the input text and the size of the wave peak s+=" " //add a space after the input text a=0 // a counter we will use later x={println s*a} //another closure that prints the input text repeated "a" times for(;;){ //infinite loop while(a<n){ //two while loop that make "a" oscillate between 1 and "n", printing at each iteration x() a++ } while(a>1){ x() a-- } } }  • Groovy man groovy – Christopher Apr 21 '17 at 15:07 # ><>, 183152 138 bytes 1+&01-1001.1+bc+-*4b{~p@-$*8b}:g1$1: < >{:0)?v~{{1+$:@@:@)?v~>1+:&:&(?v>:c2*^
^   o:<v@-10oa0           v?(1:<
^      <    o" "@-10<.1*3b<


Try it online!

Takes a string and a number on the stack.

## Explanation

# Initialization
1+&01-1001.
1+          Add 1 to value on top of stack (number from input)
&         Store in register
01-      Push 0 - 1 (-1) to stack
10    Push 1 and 0 to stack
(repetitions on this line, repetitions done for this line)
(IP now on {)

# Output loop
>{:0)?v
^   o:<

{        Roll stack left
:       Duplicate top of stack
0      Push 0
)     Greater than
?    If top of stack is nonzero (value > 0)
v   Continue loop
:  Duplicate top of stack
o Output top of stack

# Line loop
>output~{{1+$:@@:@)?v ^ o" "@-10< output Output word ~ Delete -1 (end-of-word marker) {{ Roll stack left twice so the two repetition variables are on top 1+ Add one to repetitions done for this line$:@@:@            Duplicate both variables, preserving order
)           Greater than
?          If nonzero (repetitions needed > repetitions done)
v         Continue loop
01-      Push -1
@     Roll top three items right so end-of-word marker is in correct place
" "  Push char code for space
o Output space

0ao01-@
0       Push 0 (repetitions done)
a      Push charcode of newline (10)
o     Output newline
01-  Push -1
@ Roll top 3 items right so end-of-word marker is in correct place

# Check if repetitions < 1
:1(?v
:     Duplicate (repetitions needed)
1    Push 1
(   Less than
?  If nonzero (repetitions needed < 1)
v Continue loop (else add newline)

b3*1.
b3*            Push 11 * 3 (33)
1           Push 1
.          Jump to row 1 column 33 and move (IP was pointing left, so it is now on the second > in rebound loop)

# Rebound loop
.1+bc+-*4b{~p@-$*8b}:g1$1: <
~>1+:&:&(?v>:c2*^

~                                          Remove repetitions done for this line
>                                         Make IP travel right (needed later)
1+                                       Add 1 to top of stack (repetitions needed)
:                                      Duplicate
&:&                                   Get register value and store a copy back in register
(                                  Less than
?                                 If nonzero
(repetitions needed < input value + 1)
v                                Check if repetitions < 1 (see above)
>                               Make IP travel right (also needed later)
:                              Duplicate top of stack (???)
c2*                           Push 12 * 2 (24)
:                          Duplicate
1                         Push 1
$Swap top two values 1 Push 1 g Get value at row 1 column 24 (initially the + near the start of this loop) : Duplicate } Roll right to put duplicate at bottom of stack b8* Push 88$                Swap
-               Subtract (turns '+' into '-' and vice versa)
@              Roll top 3 items to put at correct position
p             Put new character at row 1 column 24
~            Delete ???
{           Roll stack left so original value of row 1 column 24 is back on top
b4*        Push 11 * 4 (44)
-       Subtract
cb+   Push 12 + 11 (23)
1  Push 1
. Jump to row 1 column 23 and move (IP was pointing left, so it is now on the first >)

• That is really cool. Right now you are going to win my bounty – Christopher May 9 '17 at 23:08

# TI Basic 210 Bytes

Prompt Str4
Prompt N
0->V
Lbl A
0->S
If (S=0
Then
0->B
1->S
Else
1->B
End
" "->Str1
Str1->Str2
Str1+Str4+Str1->Str5
0->P
Lbl B
If (S=1 and B<N)
Then
B+1->B
Str1+Str5->Str1
Disp Str1
0->P
End
Goto B
Else
For(H,N-1,2,-1)
0->R
" "->Str1
While (R<H)
Str1+Str5->Str1
End
Disp Str1
End
Goto A


Running it (video)

• The least you could do is remove the pointless parentheses – Zacharý Jan 3 '18 at 19:57
• @Zacharý they have to be there iirc – Christopher Jan 3 '18 at 20:05
• You remembered incorrectly, because right parens can be elided at the ends of lines, like you did on line 6 – Zacharý Jan 3 '18 at 21:49