Slowly converging zigzag

Given a single positive odd integer as input, return a converging zigzag as a list of strings, list of lists of characters, or newline-separated string, in this form:

#
#
#
#
#
#
#
#
#
#
#


You can replace # with any consistent non-whitespace character. Trailing whitespace on each line is allowed and a trailing newline is allowed.

The zig-zag starts at column 1 and for each row moves right one column, until it reaches column n (where n is the input). Then, it moves left to 2, then right to n-1, then left to 3, with the two bounds converging in until the zigzag ends in the middle column ((n+1)/2).

Test Cases

The example above is the test case for 5.

The following are individual test cases:

3
#
#
#
#


7
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#


1

#

• Is leading (but consistent i.e. not shape-breaking) whitespace allowed? – Erik the Outgolfer Jul 22 '17 at 17:19
• @EriktheOutgolfer I'm going to say no for that. – HyperNeutrino Jul 22 '17 at 18:26

C (gcc), 89 bytes

f(n,a,b){puts("0");for(a=n;--a>n/2;)for(b=n-2*a;b<=2*a-n;)printf(" %*d\n",a-abs(b++),0);}


Try it online!

Works by analyzing the sequence of number of spaces as (for n=7):

          0
1 2 3 4 5 6 5 4 3 2 1
2 3 4 5 4 3 2
3 4 3


And for n=3:

  0
1 2 1


We can see that the middle number (a in the code) runs from [n-1, n/2). Then, the difference between the first number and the middle number is:

a  n  b  2a-n
-------------
6  7  5  5
5  7  3  3
4  7  1  1
2  3  1  1


So, if we have b going through [-(2a-n), 2a-n], a-abs(b) will give us the desired sequence. This is essentially what the code does.

Charcoal, 10 8 bytes

ＦＮ«↗ι‖»/


Try it online! Link is to verbose version of code. Edit: Saved 2 bytes thanks to @dzaima for pointing out that I don't have to use #s.

• Finally, something that beats Jelly – JungHwan Min Jul 23 '17 at 4:42

Python 2, 78 bytes

l=range(1,input())
print 8
for i in l:
for i in l:print' '*i+'8'
l=l[-2::-1]


Try it online!

ṖṖṚ$ÐĿẎ0;⁶ẋp1Y  Try it online! Full program. Uses 1. -1 thanks to Jonathan Allan. -1 thanks to Jonathan Allan. • ’R -> Ṗ for a byte. – Jonathan Allan Jul 22 '17 at 18:07 • @JonathanAllan Ooh of course thanks. I had tried to avoid it in an earlier verison and forgot it... – Erik the Outgolfer Jul 22 '17 at 18:10 • ”X -> 1 for another. – Jonathan Allan Jul 22 '17 at 18:13 • @JonathanAllan Heh another overlook apparently...I tried to avoid integers too. – Erik the Outgolfer Jul 22 '17 at 18:15 Haskell, 72 bytes g[]=[] g a=a++g(reverse$init a)
r="#":map(' ':)r
("#":).g.tail.(taker)


Try it online!

We define an infinite list r being the diagonal of #s starting from the upper left hand corner.

We then define a function g which does the brunt of the work. g will take a list and repeatedly reverse it and remove its first element until the list is empty, then concatenate the result of each action.

Our main function here is a point-free function. This function starts by taking n elements from the infinite list r, it then chops of the first element and applies g. Last we have to add a # back to the beginning, this is because the specs for the question are a little weird, I'm not sure why the first diagonal is always one longer than it should be but, it is, so we have to add a a #.

• @nimi I ended up doing ("#":).g.init.(taker) but thanks! – Post Rock Garf Hunter Jul 22 '17 at 23:02

SOGL V0.12, 19 bytes

┘.»∫«I╝:±jk+jl0;±Iž


Try it Here!

05AB1E, 22 bytes

i8ë<LZFD¨R})˜0¸ìε8sú}»


Try it online!

Uses 8.

05AB1E, 6 bytes

LN71SΛ


Try it online!

     Λ     use the canvas function with

L          a range list [1 .. input] as lengths for each path

N         a "0" as character to be printed
(N is the index variable used by loops. If there was no loop yet, its
default value is 0. By using N, I avoid an extra space between 0 and 71)

71S      and the directions 7 and 1 (NW and NE), that alternate automatically until
the range list is finished.

• No, I tried that first, but it draws both directions, before it continues with the next element of the range list, when I remove the S. So the output will become twice as long. I didn't know about + and × yet. They make really interesting patterns when you combine them with numbers – Dorian Oct 7 '19 at 13:44
• Ah, you're indeed right. My bad. I saw it worked without the S, but didn't paid enough attention to the output.. >.> And the + and × are basically builtins for [0,4,4,0,2,6,6,2] and [1,5,5,1,3,7,7,3]. And 8 will reset to the origin where you started from. Here a bit more information. – Kevin Cruijssen Oct 7 '19 at 13:56

CJam, 29 bytes

ri,(;_,{_);W%}*]e_0\+Sf*8f+N*


Try it online!

Uses 8.

Pyth, 23 bytes

8JStQKdVQjbm+*\ d8J=_PJ


Try it here.

JavaScript, 127 bytes

Calculates the goal (g) to get to. When this goal is reached, turn around to the next goal. Also uses a trick to avoid using Math.round() by adding 0.5 to every uneven number.

f=n=>{c=0;for(i=0;i<n;i++){m=i/2;g=i%2==0?n-m:m+1.5;while(c!=g){c>g?c--:c++;console.log(' '.repeat(c-1)+'#'+' '.repeat(n-c))}}}


f=n=>{c=0;for(i=0;i<n;i++){m=i/2;g=i%2==0?n-m:m+1.5;while(c!=g){c>g?c--:c++;console.log(' '.repeat(c-1)+'#'+' '.repeat(n-c))}}}

f(5);

f[x]=[x]
f s=s++tail(f$reverse$tail s)
g n=f[(' '<$[2..x])++"#"|x<-[1..n]]  Try it online! How it works:  [(' '<$[2..x])++"#"|x<-[1..n]]     -- build the first diagonal, e.g. for n=3:
-- ["#", " #", "  #"]
f                                      -- call f, which is

f s = s ++                               -- the input list, followed by
tail                          -- all but the first element of
f                        -- a recursive call with
reverse                -- the reverse of
tail s         -- all but the first element of the input
-- list
f[x]=[x]                                 -- base case: stop if the input list a
-- singleton list


Each recursive call to f appends the next diagonal.

Husk, 19 bytes

mo:'#R' ∫Ṙ¢e1_1tṫ


Try it online!

Explanation

This feels a bit clunky.

mo:'#R' ∫Ṙ¢e1_1tṫ  Input is n (e.g. 5)
ṫ  Range from input to 1: [5,4,3,2,1]
t   Drop first element: [4,3,2,1]
e1_1    The list [1,-1]
¢        repeated infinitely: [1,-1,1,-1,..
Ṙ         Clone with respect to the list above: [1,1,1,1,-1,-1,-1,1,1,-1]
∫           Cumulative sum: [0,1,2,3,4,3,2,1,2,3,2]
mo                   For each element k (e.g. 3) do this:
R'             Repeat space k times: "   "
:'#               Append '#': "   #"
Print implicitly separated by linefeeds.


Python 3, 82 bytes

def z(n):l=range(1,n);print(8);exec("[print(' '*i+'8')for i in l];l=l[-2::-1];"*n)


Try it online!

Retina, 71 bytes

.+
$* ^ :>$
:
;{*T:<>_#
( ) >(:)|( )<
$1<$2$3 (:)( )<|>( )$2$1$3>


Try it online! Explanation: The first three stages convert the input into the form :> : where the number of characters between the :s is the input number. The last two stages then bounce the > (or <, when moving leftward) between the :s. The fourth stage loops the bounce, printing the required parts of the string each time. The ; stops the string from being printed after the loop.

05AB1E, 16 bytes

Î<L¤FÂ¦})˜Ôð×X«»


Try it online!

Explanation

Î<L               # push 0 and range [1 ... input-1]
¤              # get the last element of the list
F             # that many times do
Â            # bifurcate
¦           # remove the head
})˜        # end loop and wrap in flattened list
Ô       # remove consecutive duplicates
ð×     # repeat space a number of times corresponding to each number in the list
X«   # append 1 to each
»  # join on newline


0:{|x$"#"}'1,,/{1_|x}\-2-!  Produces the underlying numeric sequence by repeatedly reversing and dropping the head of a vector until empty. • Welcome to PPCG.SE! Just so you know, you can put your code into an online interpreter called TIO (Try it online) and link to it so people can try your code. tio.run/#k-kona it will even provide you with a formatted PPCG post for you to submit here. – Notts90 supports Monica Jul 23 '17 at 11:55 PHP, 65 bytes <?while(--$n||$n=$d=--$argn)echo str_pad("X ",2+$x-=$d&1?:-1);?>X  Run as pipe with -nF or test it online. explanation: first iteration: $n is NULL, so --$n has no effect and evaluates to NULL --> set $n and $d to pre-decremented argument 1. increment $x for even $d, decrement for odd $d
2. print X, a newline and $x spaces further iterations: decrement $n; when it hits 0, reset $n (and $d) to pre-decremented argument

finale: print one more X.

Japt, 31 bytes

Ç+V ç +QÃê ¯-2 c´U?ß´UVÄ :Vç +Q


Recursive solution that returns an array of lines.

Try it online! using the -R flag to join output with newlines.

Python 2, 159145141 136 bytes

print"".join([" "*p+"#\n"for p in(lambda l:[sum(l[:i])for i in range(len(l))])(sum([i*[1-i%2*2]for i in range(input())[::-1]],[])+[1])])


There has already been quite nice Python versions to this problem but I thought I'd still post my awful one-liner. (Without semicolons though!)

Edit: 14 bytes down, using sum instead of double list comprehension

Edit: Just noticed in python 2 you can use input instead of raw_input. I've always just used the latter.

Mathematica, 142 102 bytes (independent)

This solution has a mathy flavor:

UnitVector[#,1-Sum[(-1)^Floor[#+1/2-Sqrt[9/4+#*#-#-2x]],{x,k}]]~Table~{k,0,#(#-1)/2}/.{0->" ",1->"X"}&

This basically calculates which segment we're in (by inverting the triangular number function) and then moving left or right by adding a power of -1.

You can test it on the Wolfram Code Sandbox by pasting code like UnitVector[#,1-Sum[(-1)^Floor[#+1/2-Sqrt[9/4+#*#-#-2x]],{x,k}]]~Table~{k,0,#(#-1)/2}/.{0->" ",1->"X"}&@6//MatrixForm and pressing Shift+Enter or Numpad Enter or clicking Gear->"Evaluate Cell".

This happens to be the same length as my original incorrect port of Erik's Python 2 solution (This port gives the output for an input one higher):

(Print[X];l=Range@#;Do[Do[Print[StringRepeat[" ",l[[j]]]<>"X"],{j,Length@l}];l=l[[-2;;1;;-1]],{i,#}])&`