Build a Semi-Zigzag

You will be given a positive integer N as input. Your task is to build a Semi-Zigzag, of N sides, each of length N. Since it is relatively hard to clearly describe the task, here are some examples:

• N = 1:

O

• N = 2:

O
O O

• N = 3:

O       O
O     O
O O O

• N = 4:

O           O O O O
O         O
O       O
O O O O

• N = 5:

O               O O O O O
O             O         O
O           O           O
O         O             O
O O O O O               O

• N = 6:

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 O

• N = 7:

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 O O O O O O                       O O O O O O O

• A larger test case with N = 9

As you can see, a Semi-Zigzag is made of alternating diagonal and horizontal lines, and it always begins with a top-left to bottom right diagonal line. Take note that the characters on the horizontal lines are separated by a space.

Rules

• You may choose any non-whitespace character instead of O, it may even be inconsistent.

• You may output / return the result as a String or as a list of Strings, each representing one line.

• You may have a trailing or leading newline.

• Default Loopholes apply.

• You can take input and provide output by any standard mean.

• This is , so the shortest code in bytes in every language wins!

• Jul 30, 2017 at 11:02
• Do we have to put spaces between O that are horizontal ? Jul 30, 2017 at 13:27
• @HatsuPointerKun Take note that the characters on the horizontal lines are separated by a space. – Yes, you do have to put spaces. Jul 30, 2017 at 13:28
• Ah, yes. I should learn to read. Thanks Jul 30, 2017 at 13:37
• @JohnHamilton The answers should theoretically work for any number given as input. They must not worry about what a screen can hold. Jul 31, 2017 at 11:42

Charcoal, 24 bytes

ＦＮ«↶§7117ι×⁺#× ﹪ι²⁻Ｉθ¹»#


Try it online!

-5 thanks to Neil.

AST:

Program
├Ｆ: For
│├Ｎ: Input number
│└Program
│ ├↶: Pivot Left
│ │└§: At index
│ │ ├'7117': String '7117'
│ │ └ι: Identifier ι
│ └Print
│  └×: Product
│   ├⁺: Sum
│   │├'#': String '#'
│   │└×: Product
│   │ ├' ': String ' '
│   │ └﹪: Modulo
│   │  ├ι: Identifier ι
│   │  └2: Number 2
│   └⁻: Difference
│    ├Ｉ: Cast
│    │└θ: Identifier θ
│    └1: Number 1
└Print
└'#': String '#'

• It was too easy for Charcoal :) Jul 30, 2017 at 12:51
• @Mr.Xcoder This feels really ungolfed actually...not sure how to golf it. Jul 30, 2017 at 12:52
• The OP said that the character can be any and does not need to be consistent, so I was going for something along the lines of ＦＮ§⟦↘→↗→⟧ι⁻Ｉθ¹→ (15 bytes only), but lists of directions do not seem to work right in Charcoal. A pity. Jul 30, 2017 at 14:42
• @CarlosAlejo Tried that too but unfortunately it doesn't work. Jul 30, 2017 at 14:43
• @CarlosAlejo ＦＮ✳§⟦↘→↗→⟧ι⁻θ¹O will work after Dennis pulls, ✳ being cast to direction Aug 4, 2017 at 1:49

Python 2, 157 153 bytes

n=input()
o,s=q='O '
def p(k,t=q*n+s*(4*n-6)):print(t*n)[k*~-n:][:n*3/2*~-n+1]
p(2)
for i in range(n-2):p(0,i*s+s+o+s*(4*n-7-2*i)+o+s*(2*n+i-2))
n>1>p(5)


Try it online!

• n*3/2*~-n+1 is the width of each line: ⌊3n/2⌋ · (n−1) + 1 characters.
• The string q*n+s*(4*n-6) represents the top and bottom rows. If we repeat it and slice [2*(n-1):] we get the top row; if we slice [5*(n-1):] we get the bottom row. Hence the definition of p and the calls to p(2) and p(5). But since we need the repetition and line-length slicing for all other lines anyway, we reuse p in the loop.
• The i*s+s+o+… is just a boring expression for the middle rows.
• n>1>p(5) will short-circuit if n≯1, causing p(5) to not get evaluated. Hence, it’s shorthand for if n>1:p(5).
• Wow, awesome solution, so clever. You earned my upvote Jul 30, 2017 at 18:38
• Wow, never knew Python had short circuiting on comparisons like that, +1. Jul 30, 2017 at 19:01

Mathematica, 12612512111210489 86 bytes

(m=" "&~Array~{#,#^2-#+1};Do[m[[1[i,#,-i][[j~Mod~4]],j#-#+i+1-j]]="X",{j,#},{i,#}];m)&

• # is the input number for an anonymous function (ended by the final &).
• m=" "&~Array~{#,#^2-#+1}; makes a matrix of space characters of the right size by filling an array of given dimensions #,#^2-#+1 with the outputs of the constant anonymous function "output a space" " "&.
• Do[foo,{j,#},{i,#}] is a pair of nested do loops, where j ranges from 1 to # and inside of that i ranges from 1 to #.
• m[[1[i,#,-i][[j~Mod~4]],j#-#+i+1-j]]="X" sets the the corresponding part of the matrix to be the character X based on j and i. The -i uses negative indexing to save bytes from #-i+1. (I forgot to write Mod[j,4] as j~Mod~4 in the original version of this code.) Jenny_mathy pointed out that we can use the modular residue to index into the list directly (rather than using Switch) to save 9 bytes, and JungHwan Min pointed out that we didn't need to use ReplacePart since we can set a part of an array and that 1[i,#,-i][[j~Mod~4]] uses the odd behavior and generality of [[foo]] to save bytes over {1,i,#,-i}[[j~Mod~4+1]]
• Since meta established that a list of characters is a string (as JungHwan Min pointed out) we don't need to map any function across the rows of the matrix of characters since it's already a list of "string"s.

You can test this out in the Wolfram Cloud sandbox by pasting code like the following and hitting Shift+Enter or the numpad Enter:

(m=" "&~Array~{#,#^2-#+1};Do[m[[1[i,#,-i][[j~Mod~4]],j#-#+i+1-j]]="X",{j,#},{i,#}];m)&@9//MatrixForm

• Very nice! you can replace StringJoin with ""<>#& to save 4 bytes Jul 30, 2017 at 16:29
• @Jenny_mathy Thanks for the tip! That seems pretty useful. Jul 30, 2017 at 16:33
• You can also replace Switch[...] with {1,i,#,-i}[[j~Mod~4+1]] and save 9 bytes! Jul 30, 2017 at 17:44
• You don't actually need ReplacePart here. m=ReplacePart[...] can be m[[{1,i,#,-i}[[j~Mod~4+1]],j#-#+i+1-j]]="X" -- You can Set a Part of a list. That gets rid of 15 bytes. Jul 30, 2017 at 21:50
• {1,i,#,-i}[[j~Mod~4+1]] can also be 1[i,#,-i][[j~Mod~4]]. This trick works because [[0]] returns the Head of an expression. Jul 30, 2017 at 22:02

C++, 321 234 bytes

-87 bytes thanks to Zacharý

#include<vector>
#include<string>
auto z(int n){std::vector<std::string>l;l.resize(n,std::string(n*n+n/2*(n-1),32));l[0][0]=79;int i=0,j,o=0;for(;i<n;++i)for(j=1;j<n;++j)l[i%4?i%4-1?i%4-2?0:n-j-1:n-1:j][i*n+j-i+(o+=i%2)]=79;return l;}


Returns a vector of strings

• I got it down to 318 bytes: repl.it/JpJ2 Jul 30, 2017 at 18:04
• Correction, I got it down to 239 bytes: repl.it/JpJ2/1 Jul 30, 2017 at 18:21
• Sorry for the spam, 234 bytes: repl.it/JpJ2/3 Jul 30, 2017 at 18:29
• What can I say except you're welcome! Jul 30, 2017 at 20:13
• @Zacharý thanks you very much sir Jul 30, 2017 at 20:16

Mathematica, 179 bytes

Rotate[(c=Column)@(t=Table)[{c@(a=Array)[" "~t~#<>(v="o")&,z,0],c@t[t[" ",z-1]<>v,z-1],c@a[t[" ",z-2-#]<>v&,z-1,0],c@t[v,z-Boole[!#~Mod~4<1]-1]}[[i~Mod~4+1]],{i,0,(z=#)-1}],Pi/2]&


edit for @JungHwanMin

• I didn't expect it to be that short, well done! Jul 30, 2017 at 12:32
• Just a question: Can Mod[z,4]==0 be replaced with Mod[z,4]<1? Jul 30, 2017 at 12:33
• yes, I can golf some things down... Jul 30, 2017 at 12:38
• I don't really know Mathematica, but can you replace Mod[#,4] with #~Mod~4 for -1 bytes? Jul 30, 2017 at 16:22
• Oops... accidentally downvoted. Could you edit the answer so I can flip that upside down? Jul 30, 2017 at 20:44

05AB1E, 2120 19 bytes

Code

Uses the new canvas mode:

Fx<)Nè'ONÉúR3212NèΛ


Uses the 05AB1E encoding. Try it online!

Explanation:

F                      # For N in range(0, input)
x<)                   #   Push the array [input, 2 × input - 1]
Nè                 #   Retrieve the Nth element
'ONÉúR           #   Push "O" if N is odd, else "O "
3212Nè     #   Retrieve the Nth element of 3212
Λ    #   Write to canvas


For input 6, this gives the following arguments (in the same order) for the canvas:

[<num>, <fill>, <patt>]
[6,     'O',     3]
[11,    'O ',    2]
[6,     'O',     1]
[11,    'O ',    2]
[6,     'O',     3]
[11,    'O ',    2]


To explain what the canvas does, we pick the first set of arguments from the list above.

The number 6 determines the length of the string that will be written into the canvas. The filler is used to write on the canvas, which in this case is O. It cyclically runs through the filler string. The direction of the string is determined by the final argument, the direction. The directions are:

7  0  1
\ | /
6- X -2
/ | \
5  4  3


This means that the 3 sets the direction to south-east, which can also be tried online.

• also note that canvas mode is in development and very unstable Aug 3, 2017 at 21:24
• :O 05AB1E is mutating into Charcoal (also this is beating Charcoal O_o) Aug 3, 2017 at 23:03
• @ASCII-only Yeah, I saw the rise of all the ASCII-based languages (Charcoal, SOGL, V, etc.) and saw 05AB1E sink into the background, so I had to do something about it :p Aug 3, 2017 at 23:58
• so you copied charcoal? :P 05ab1e even has a canvas and directional printing (although charcoal only supports this style of printing with length via python) Aug 4, 2017 at 0:50

SOGL V0.12, 36 bytes

╝.H∫2\?.╝}F2%?№@.┌Ο};1w⁄Hh1ž}.4%1>?№


Try it Here!

The basic idea is to for each number of the input range choose either adding a diagonal or the horizontal dotted part, in which case it will turn the array around for easier adding on. Explanation:

╝                                     get a diagonal from the bottom-left corner with the length of the input - the starting canvas
.H∫                        }         for each number in the range [1,inp-1] do, pushing counter
2\?  }                              if it divides by 2, then
.╝                                 create another diagonal of the input
F2%                           push counter % 2
?     }                    if that [is not 0]
№                           reverse the current canvas upside down
@.┌Ο                       get an alternation of spaces and dashes with the dash amount of the input length
;                   get the canvas on top of the stack
1w⁄                get its 1st element length
H               decrease it
h              swap the bottom 2 items - the canvas is now at the bottom and the current addition ontop
1             push 1
ž            at 1-indexed coordinates [canvasWidth-1, 1] in the canvas insert the current part made by the Ifs
.4%1>?   if input%4 > 1
№    reverse the array vertically


If the input of 1 wasn't allowed, then ο.∫2%?.╝}F2\?№@.┌Ο};1w⁄Hh1ž}.4%1>?№ would work too. If random numbers floating around were allowed .∫2%?.╝}F2\?№@.┌Ο};1w⁄Hh1ž}.4%1>?№ would work too. If I were not lazy and implemented ‼, }F2%? could be replaced with ‼ for -4 bytes

Mathematica, 106 87 bytes

SparseArray[j=i=1;k=#-1;Array[{j+=Im@i;k∣#&&(i*=I);j,#+1}->"o"&,l=k#+1,0],{#,l}," "]&


Returns a SparseArray object of Strings. To visualize the output, you can append Grid@. Throws an error for case 1, but it's safe to ignore.

Explanation

j=i=1


Set i and j to 1.

k=#-1


Set k to input - 1.

l=k#+1


Set l to k*input + 1

Array[ ..., l= ...,0]


Iterate l times, starting from 0, incrementing by 1 each time...

j+=Im@i


Add the imaginary component of i to j...

k∣#&&(i*=I)


If the current iteration is divisible by k, multiply i by the imaginary unit...

{... j,#+1}->"o"


Create a Rule object that changes element at position {j, current iteration + 1} to "o"

SparseArray[ ...,{#,l}," "]


Create a SparseArray object using the generated Rule objects, with dimension {input, l}, using " " as blank.

Try it on Wolfram Sandbox!

• there is something wrong with case n=3 Jul 30, 2017 at 18:30
• n=2, 4,5,6 also have correctness problems, but I think this works for 7 and above. I'm curious: is there precedent as to whether a SparseArray counts as an array? It can be visualized using Grid or MatrixForm, but I wouldn't normally count it as "a list of strings" here. If a 2D array of characters suffices, that cuts 8 bytes off of my solution (12 before Jenny_mathy's help), for instance. Jul 30, 2017 at 19:22
• @MarkS. Also, an array of string is okay per meta consensus. If something is unclear, please ask the OP (as he/she makes the rules, not us). A simple search of "SparseArray" in this site gives an abundance of SparseArray responses, so I presume it's fine. Jul 30, 2017 at 20:41
• @MarkS. Also, this page has a lot of tricks on golfing Mathematica. Jul 30, 2017 at 20:47
• @JungHwanMin I edited my answer as you asked Jul 30, 2017 at 22:31

Python 3, 228 226 224 215 197 195 bytes

-11 bytes Thanks to @Mr. Xcoder

-2 bytes Thanks to @Mr. Xcoder

def f(n,s=range):
x=y=t=c=0;z=[]
for i in s(n*n-n+2):c+=i%(n-(2<=n))<1;z+=[[x,y]];t=max(t,x);x+=2-c%2;y+=[-1,1][c%4<3]*(c%2)
return'\n'.join(''.join(' O'[[k,j]in z]for k in s(t))for j in s(n))


Try it online!

Explanation and less-golfed code:

def f(n):
x=y=t=c=0;z=[]                       #initialize everything
for i in range(n*n-n+2):             #loop n*n-n+2 times which is the numberr of 'o's expected
c+=i%[~-n,n]<n-1                  #if one cycle has been completed, increase c by 1, if n>1.
z+=[[x,y]]                        #add [x,y] to z(record the positions of 'o')
t=max(t,x)                        #trap maximum value of x-coordinate(to be used later while calculatng whole string)
r=[[2,0],[1,1],[2,0],[1,-1]][c%4] #r gives direction for x and y to move, adjust it as per c i.e. cycles
x+=r[0];y+=r[1]                   #yield newer values of x and y
return '\n'.join(''.join(' o'[[k,j]in z]for k in range(t))for j in range(n)) #place space or 'o' accordingly as per the recorded posititons in z

• Very nice work. Congratulations! Jul 30, 2017 at 16:51
• @Mr.Xcoder Thank you. I must say this one was tough, especially had problems identifying the correct range. Jul 30, 2017 at 16:54
• Replace c+=i%(n-1)<1 with c+=i%~-n<1 for -2 bytes Jul 30, 2017 at 16:55
• 215 bytes, if 2>n:return'o' is quite redundant. I made a work-around with c+=i%[~-n,n][2>n]<1 instead of c+=i%~-n<1. Jul 30, 2017 at 17:39
• Sorry for the very late improvement, 195 bytes Aug 8, 2017 at 8:36

a n c=take(2*n)$cycle$c:" "
r i n x y=take(div(3*n)2*(n-1)+1)$(' '<$[1..i])++(cycle$"O "++(a(2*n-i-3)y)++"O "++(a(n+i-2)x)) z n=take n$(r 0 n 'O' ' '):[r i n ' ' ' '|i<-[1..n-2]]++[r(n-1)n ' ' 'O']


Try it online!

Thanks to @Lynn : fixed the spaces between Os on horizontal segments of the zigzag, but it costed a lot of bytes!

Some explanations:

• r is a row of the output: it has the 0 y y y y y 0 x x x 0 y ... format, the number of xand y depending on the row and the initial n
• for the top row, x='0'and y=' '
• for the middle rows, x=' 'and y=' '
• for the bottom row, x=' 'and y='0'
• take(div(3*n)2*(n-1)+1) cuts an infinite row at the right place
• every output has one top row and one bottom row except when n=1: take n handles this case.
• Nicely golfed! You can drop a couple of those spaces, I think. And replicate n x can be replaced by x<\$[1..n]. Also, your answer lacks the spaces between Os on horizontal segments of the zigzag.
– Lynn
Jul 31, 2017 at 9:38
• @Lynn thanks! with the spaces on horizontal segments, my method becomes cumbersome, but i wanted to fix the code anyway... Jul 31, 2017 at 21:36
• You can save quite a bit by using operators and removing unneeded spaces, see here. Jul 31, 2017 at 22:47

Python 2, 155151146 137 bytes

m=input()
n=m-1
r=range(n+2)
for L in zip(*[' '*i+'O'+n*' 'for i in(r+[n,m]*~-n+r[-2::-1]+([m,0]*n)[:-1])*m][:1+3*m/2*n]):print''.join(L)


Try it online!

• @Mr.Xcoder Ahh. I see now. Aug 3, 2017 at 7:19
• @Mr.Xcoder Fixed now. Aug 3, 2017 at 7:35
• I am one year late to the golfing party, but L[2::5] saves a byte over ''.join(L) Jul 20, 2018 at 10:28