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:

  • N = 2:

     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.


  • 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.

  • If possible, please add a testing link to your submission. I will upvote any answer that shows golfing efforts and has an explanation.

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

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

11 Answers 11


Charcoal, 24 bytes

FN«↶§7117ι×⁺#× ﹪ι²⁻Iθ¹»#

Try it online!

-5 thanks to Neil.


├F: For
│├N: Input number
│ ├↶: Pivot Left
│ │└§: At index
│ │ ├'7117': String '7117'
│ │ └ι: Identifier ι
│ └Print
│  └×: Product
│   ├⁺: Sum
│   │├'#': String '#'
│   │└×: Product
│   │ ├' ': String ' '
│   │ └﹪: Modulo
│   │  ├ι: Identifier ι
│   │  └2: Number 2
│   └⁻: Difference
│    ├I: Cast
│    │└θ: Identifier θ
│    └1: Number 1
 └'#': String '#'
  • \$\begingroup\$ It was too easy for Charcoal :) \$\endgroup\$ – Mr. Xcoder Jul 30 '17 at 12:51
  • \$\begingroup\$ @Mr.Xcoder This feels really ungolfed actually...not sure how to golf it. \$\endgroup\$ – Erik the Outgolfer Jul 30 '17 at 12:52
  • \$\begingroup\$ 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 FN§⟦↘→↗→⟧ι⁻Iθ¹→ (15 bytes only), but lists of directions do not seem to work right in Charcoal. A pity. \$\endgroup\$ – Charlie Jul 30 '17 at 14:42
  • \$\begingroup\$ @CarlosAlejo Tried that too but unfortunately it doesn't work. \$\endgroup\$ – Erik the Outgolfer Jul 30 '17 at 14:43
  • 1
    \$\begingroup\$ @CarlosAlejo FN✳§⟦↘→↗→⟧ι⁻θ¹O will work after Dennis pulls, being cast to direction \$\endgroup\$ – ASCII-only Aug 4 '17 at 1:49

Python 2, 157 153 bytes

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

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).
  • \$\begingroup\$ Wow, awesome solution, so clever. You earned my upvote \$\endgroup\$ – Mr. Xcoder Jul 30 '17 at 18:38
  • \$\begingroup\$ Wow, never knew Python had short circuiting on comparisons like that, +1. \$\endgroup\$ – Adalynn Jul 30 '17 at 19:01

Mathematica, 126 125 121 112 104 89 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
  • 1
    \$\begingroup\$ Very nice! you can replace StringJoin with ""<>#& to save 4 bytes \$\endgroup\$ – ZaMoC Jul 30 '17 at 16:29
  • \$\begingroup\$ @Jenny_mathy Thanks for the tip! That seems pretty useful. \$\endgroup\$ – Mark S. Jul 30 '17 at 16:33
  • 2
    \$\begingroup\$ You can also replace Switch[...] with {1,i,#,-i}[[j~Mod~4+1]] and save 9 bytes! \$\endgroup\$ – ZaMoC Jul 30 '17 at 17:44
  • 1
    \$\begingroup\$ 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. \$\endgroup\$ – JungHwan Min Jul 30 '17 at 21:50
  • 1
    \$\begingroup\$ {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. \$\endgroup\$ – JungHwan Min Jul 30 '17 at 22:02

C++, 321 234 bytes

-87 bytes thanks to Zacharý

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

  • \$\begingroup\$ I got it down to 318 bytes: repl.it/JpJ2 \$\endgroup\$ – Adalynn Jul 30 '17 at 18:04
  • \$\begingroup\$ Correction, I got it down to 239 bytes: repl.it/JpJ2/1 \$\endgroup\$ – Adalynn Jul 30 '17 at 18:21
  • \$\begingroup\$ Sorry for the spam, 234 bytes: repl.it/JpJ2/3 \$\endgroup\$ – Adalynn Jul 30 '17 at 18:29
  • 1
    \$\begingroup\$ What can I say except you're welcome! \$\endgroup\$ – Adalynn Jul 30 '17 at 20:13
  • \$\begingroup\$ @Zacharý thanks you very much sir \$\endgroup\$ – HatsuPointerKun Jul 30 '17 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

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

05AB1E, 21 20 19 bytes


Uses the new canvas mode:


Uses the 05AB1E encoding. Try it online!


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.

  • \$\begingroup\$ also note that canvas mode is in development and very unstable \$\endgroup\$ – Adnan Aug 3 '17 at 21:24
  • \$\begingroup\$ :O 05AB1E is mutating into Charcoal (also this is beating Charcoal O_o) \$\endgroup\$ – ASCII-only Aug 3 '17 at 23:03
  • \$\begingroup\$ @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 \$\endgroup\$ – Adnan Aug 3 '17 at 23:58
  • \$\begingroup\$ 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) \$\endgroup\$ – ASCII-only Aug 4 '17 at 0:50

SOGL V0.12, 36 bytes


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.



Set i and j to 1.


Set k to input - 1.


Set l to k*input + 1

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

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


Add the imaginary component of i to j...


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!

  • 1
    \$\begingroup\$ there is something wrong with case n=3 \$\endgroup\$ – ZaMoC Jul 30 '17 at 18:30
  • 1
    \$\begingroup\$ 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. \$\endgroup\$ – Mark S. Jul 30 '17 at 19:22
  • 1
    \$\begingroup\$ @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. \$\endgroup\$ – JungHwan Min Jul 30 '17 at 20:41
  • 1
    \$\begingroup\$ @MarkS. Also, this page has a lot of tricks on golfing Mathematica. \$\endgroup\$ – JungHwan Min Jul 30 '17 at 20:47
  • 1
    \$\begingroup\$ @JungHwanMin I edited my answer as you asked \$\endgroup\$ – ZaMoC Jul 30 '17 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):
 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
  • 1
    \$\begingroup\$ Very nice work. Congratulations! \$\endgroup\$ – Mr. Xcoder Jul 30 '17 at 16:51
  • \$\begingroup\$ @Mr.Xcoder Thank you. I must say this one was tough, especially had problems identifying the correct range. \$\endgroup\$ – officialaimm Jul 30 '17 at 16:54
  • 1
    \$\begingroup\$ Replace c+=i%(n-1)<1 with c+=i%~-n<1 for -2 bytes \$\endgroup\$ – Mr. Xcoder Jul 30 '17 at 16:55
  • 1
    \$\begingroup\$ 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. \$\endgroup\$ – Mr. Xcoder Jul 30 '17 at 17:39
  • 1
    \$\begingroup\$ Sorry for the very late improvement, 195 bytes \$\endgroup\$ – Mr. Xcoder Aug 8 '17 at 8:36

Haskell, 197 bytes

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.
  • \$\begingroup\$ 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. \$\endgroup\$ – Lynn Jul 31 '17 at 9:38
  • \$\begingroup\$ @Lynn thanks! with the spaces on horizontal segments, my method becomes cumbersome, but i wanted to fix the code anyway... \$\endgroup\$ – jferard Jul 31 '17 at 21:36
  • \$\begingroup\$ You can save quite a bit by using operators and removing unneeded spaces, see here. \$\endgroup\$ – ბიმო Jul 31 '17 at 22:47

Python 2, 155 151 146 137 bytes

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!

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.