Write a program or function that takes in a positive integer N and outputs the first N numbers of this amplifying zigzag pattern, using only the lines needed:

                                       25  27                                      .
         10                          24      28                                  .
        9  11                      23          29                              .
 2     8     12                  22              30                          44
1 3   7        13              21                  31                      43
   4 6           14          20                      32                  42
    5              15      19                          33              41
                     16  18                              34          40
                       17                                  35      39
                                                             36  38

So, if N is 1 the output is


If N is 2, the output is


If N is 3 the output is

1 3

If N is 4 the output is

1 3

If N is 10 the output is

 2     8
1 3   7
   4 6

If N is 19 the output is

        9  11
 2     8     12
1 3   7        13
   4 6           14
    5              15      19
                     16  18

and so on.


  • Each peak or trough of the zigzag reaches its point one more line away from the line with the 1 on it than the previous peak or trough.

  • N is not limited to 44. The zigzag grows in the same pattern and larger N should be supported.

  • Numbers with multiple digits should only "touch" at their corners, as depicted. Make sure this works when N is 100 and above.

  • There should be no empty (or space only) lines in the output except one optional trailing newline.

  • Any line may have any amount of trailing spaces.


The shortest code in bytes wins. Tiebreaker is earlier answer.

  • \$\begingroup\$ What's the maximum possible N? \$\endgroup\$ Jun 14, 2016 at 2:24
  • \$\begingroup\$ @JuliePelletier In theory there is none, but you can assume it will be less than 2^16. \$\endgroup\$ Jun 14, 2016 at 2:27
  • \$\begingroup\$ Is using control characters allowed or are we limited to digits spaces and linefeeds? \$\endgroup\$
    – Dennis
    Jun 14, 2016 at 3:31
  • 2
    \$\begingroup\$ @Dennis Let's say no. Just digits/spaces/newlines. \$\endgroup\$ Jun 14, 2016 at 3:52
  • 1
    \$\begingroup\$ Somebody should submit that to the OEIS in that format as a joke. \$\endgroup\$
    – DanTheMan
    Jun 16, 2016 at 20:03

7 Answers 7


Jelly, 41 37 29 bytes


Try it online!

How it works

RDµḌ’½Ċ-*_\x©L€Ṣ.ị®ạ€⁶ẋj"FZj⁷  Main link. Argument: n (integer)

R                              Range; yield [1, ..., n].
 D                             Decimal; yield A =: [[1], ..., [1, 0], ...].
  µ                            Begin a new, monadic chain. Argument: A
   Ḍ                           Undecimal; convert back to falt range.
    ’                          Decrement to yield [0, ..., n-1].
     ½Ċ                        Take the square root and round up (ceil).
       -*                      Elevate -1 to each rounded square root.
         _\                    Cumulatively reduce by subtraction.
                               This yields [1, 2, 1, 0, -1, 0, ...], i.e., the
                               vertical positions of the digits in A.
             L€                Compute the length of each list in A.
           x                   Repeat the nth position l times, where l is the
                               nth length.
            ©                  Copy the result to the register.
               Ṣ               Sort.
                .ị             At-index 0.5; yield the last and first element,
                               which correspond to the highest and lowest position.
                  ạ€®          Take the absolute difference of each position in the
                               register and the extrema.
                               This yields the number of spaces above and below
                               the integers in r as a list of pairs.
                     ⁶ẋ        Replace each difference with that many spaces.
                         F     Flatten the list A.
                       j"      Join the nth pair of strings of spacing, separating
                               by the nth digit in flat A.
                          Z    Zip/transpose the result.
                           j⁷  Join, separating by linefeeds.
  • 2
    \$\begingroup\$ Why not make a function in your language (Jelly) that can do that in a few chars while you're at it? \$\endgroup\$ Jun 14, 2016 at 7:00
  • 19
    \$\begingroup\$ @JuliePelletier The art of writing a good golfing language is about coming up with a set of instructions (and syntax/language semantics) which allow you to write short solutions for as many different tasks as possible, not about being able to solve one very specific and contrived challenge in a single byte. A good golfing language tends to be actually very powerful and expressive, as opposed to just being a collection of built-ins which are useless for anything but the specific function they compute. \$\endgroup\$ Jun 14, 2016 at 7:50
  • \$\begingroup\$ @JuliePelletier And it would also go against the rules of PPCG SE \$\endgroup\$
    – Bálint
    Jun 16, 2016 at 14:12

PHP, 211 177 164 163 bytes

Predict the peaks with $n and increase the array dynamically in either direction, using ($x, $y) output cursor.

Numbers are aligned with str_pad() and the final output is the implode() of that array of strings ($g).

for($x=0,$d=-1,$h=$n=2,$y=$a=1;$a<=$argv[1];$y+=$d){$g[$y]=str_pad($g[$y],$x).$a;$x+=strlen($a);if($a++==$n){$h+=2;$n+=$h-1;$d*=-1;}}ksort($g);echo implode(~õ,$g);

Test it online!

Update: removed 34 bytes by getting rid of the unneeded array_pad(). Update2: followed @insertusernamehere's advice to shorten it a bit more. Update3: followed @Lynn's advice to save one more byte with ~õ which imposes the use of LATIN-1 charset. (not available in online PHP emulator so not included there)

  • \$\begingroup\$ Just a question about this code.. Don't you have to initialize the array $g before you access a specific element? I mean, giving it a length or inserting the rows? I'm not very experienced with PHP, so it just looks weird to me... Thanks. \$\endgroup\$ Jun 14, 2016 at 5:17
  • \$\begingroup\$ No. Once you define $arr = [];, you can refer to $arr[anything]. Some cases will output notices but those are ignored here. Note that reading stuff like this probably won't help you much to learn a language. Your comment made me realize I could make it shorter though as I initially thought I'd need to pad my array but I don't. :) \$\endgroup\$ Jun 14, 2016 at 5:26
  • \$\begingroup\$ Haha glad for helping ;) Just realized that in PHP an array and a dictionary are initialized in the same way and are completely the same when looking at the syntax (Why, PHP?!) \$\endgroup\$ Jun 14, 2016 at 5:28
  • \$\begingroup\$ Some minor improvements – 164 bytes: for($x=0,$d=-1,$h=$n=2,$y=$a=1;$a<=$argv[1];$y+=$d){$g[$y]=str_pad($g[$y],$x).$a;$x+=strlen($a);if($a++==$n){$h+=2;$n+=$h-1;$d*=-1;}}ksort($g);echo implode("⏎",$g); (Replace ⏎ with an actual newline.) \$\endgroup\$ Jun 14, 2016 at 6:56
  • \$\begingroup\$ I believe if you set up your encoding right (Latin-1, not UTF-8), is a two-byte alternative to "⏎". \$\endgroup\$
    – Lynn
    Jun 16, 2016 at 18:32

Pyth, 60 53 52 46 42 39 38 36 34 32 31 bytes

39: It is now on par with the bug-fixed version of Jelly, and I have out-golfed Dennis' competing version!

38: I have out-golfed Dennis!

36: I have out-golfed Dennis again!

34: Even lower than his bug-fixed version!

31: 32 -> 31 thanks to Dennis.

[email protected]++*]*dl`hkabhSK`hk*]*dl`hkabeSKKd
[email protected]*]*dl`hkhaeSKhSKabhSKhkKd
j-#dsMCmX*]*;l`hdyQ+Q=+Zsty%s@td2 2h

Try it online!

How it works

j-#dsMCmX*]*;l`hdyQ=+Q^_1.E@d2h      input: Q
j-#dsMCmX*]*;l`hdyQ=+Q^_1.E@d2hdQ    implicit filling arguments

       m                        Q    for each number d from 0 to Q-1:
                           @d2           yield the square root of d.
                         .E              yield its ceiling.
                      ^_1                raise -1 to that power. this
                                         yields the desired direction.
                   =+Q                   increment Q by this amount.

               hd                        yield d+1.
              `                          yield its string representation.
             l                           yield its length.
           *;                            repeat " " for that number of times
          ]                              yield a list containing the string above.
         *       yQ                      repeat the list for Q*2 times.
                                         the Q has changed, but Q*2 is
                                         an overshoot that is high
                                         enough, so we don't have to
                                         worry about it.

        X                                in that list, replace the
                                         element with index being the
                                         number generated above
                              hd         with d+1.

      C                              transpose the resulting array.
    sM                               flatten each element.
 -#d                                 remove lines containing only spaces.
                                     (filter on truthiness of set difference with space)
j                                    join by newlines.
  • 2
    \$\begingroup\$ "39: On par with Jelly"; "38: I have out-golfed Dennis!" For a few hours you did, but it looks like @Dennis doesn't like to get beaten at code-golfing: Jelly 37 bytes ;) \$\endgroup\$ Jun 16, 2016 at 7:24
  • 1
    \$\begingroup\$ @KevinCruijssen Done. \$\endgroup\$
    – Leaky Nun
    Jun 16, 2016 at 13:50
  • \$\begingroup\$ Nice! xD M̶a̶y̶b̶e̶ I have a wild imagination, but now I imagine you've looked and looked in frustration for hours until you finally found this shorter solution, and now @Dennis will casually wake up and shorten his code again. (Jk, I hope you stay below Dennis!) \$\endgroup\$ Jun 16, 2016 at 14:05
  • \$\begingroup\$ @KevinCruijssen Tada! It's now lower than the bug-fixed version. \$\endgroup\$
    – Leaky Nun
    Jun 16, 2016 at 14:31

MATLAB, 148 bytes

n=input('');k=fix(n^.5);m=0;w=1;d=-1;for l=1:n;s=num2str(l);m(k+1,w:w+nnz(s)-1)=s;w=w+nnz(s);k=k+d;d=d*(-1)^(l^.5==fix(l^.5));end;[m(any(m,2),:),'']

Note that the spaces are missing in Octave, as MATLAB prints the the character indexed with 0 as a space, while octave does just omit that character.


k=fix(n^.5);                    %caculate starting height
m=0;w=1;d=-1;                   %initialize counters and output matrix
for l=1:n;
    m(k+1,w:w+nnz(s)-1)=s;      %insert current index as a string
    w=w+nnz(s);                 %current horizontal position
    k=k+d;                      %current vertical position
    d=d*(-1)^(l^.5==fix(l^.5)); %if we reached a square number, change direction
[m(any(m,2),:),'']              %delete all zero rows

Haskell, 144 142 bytes

g n|k<-take n$scanl(+)0$[1..]>>= \x->(-1)^x<$[2..2*x]=unlines[[1..n]>>= \x->show x#(k!!(x-1)==y)|y<-[minimum k..maximum k]]
s#g|g=s|1<2=' '<$s

Usage example:

*Main> putStr $ g 19
        9  11                
 2     8     12              
1 3   7        13            
   4 6           14          
    5              15      19
                     16  18  

How it works:

s#g|g=s|1<2=' '<$s              -- # is a helper function that expects a string s
                                -- and a boolean g. It returns s if g is True, else
                                -- as many spaces as there a characters in s 

k<-take n$                      -- bind k to the first n elements of
 [1..]>>= \x->(-1)^x<$[2..2*x]  -- 2*x-1 copies of (-1)^x for each x in [1,2,3,...]
                                -- i.e. [-1, 1,1,1, -1,-1,-1,-1,-1, 1,1,1,1,1,1,1..]
 scanl(+)0                      -- build partial sums, starting with 0
                                -- i.e. [0,-1,0,1,2,1,0,-1,-2,-3,-2,-1...]
                                -- -> k is the list of y coordinates for the
                                --    numbers 1,2,3,...

 [  |y<-[minimum k..maximum k]] -- for all y coordinates in k 
      \x->show x#(k!!(x-1)==y)  -- map the # function
  [1..n]>>=                     -- over [1..n] (the x coordinates)
                                -- where # is called with
                                --  s -> a string representation of x 
                                --  g -> True if k at index x equals the current y
unlines                         -- join with newlines

Edit: Thanks @Lynn for two bytes!


JavaScript (ES6), 213 bytes

with(Math)n=>(a=[...Array(n)].map((_,i)=>n-=1+sqrt(--i)&1||-1).map((e,_,a)=>e-min(...a))).map((e,i)=>r[e][i]=++i,r=[...Array(1+max(...a))].map(_=>a.map((_,i)=>` `.repeat(1+log10(++i)))))&&r.map(a=>a.join``).join`\n`

Where \n represents a literal newline character. Explanation:

with(Math)                          Bring functions into scope
 n=>                                Accepts one parameter
  (a=                               Intermediate result variable
   [...Array(n)].map(               For each number 0..n-1
    (_,i)=>n-=                      Accumulate index for each number
     1+sqrt(--i)&1||-1              Calculate the direction
    ).map((e,_,a)=>e-min(...a))     Scale the smallest index to zero
  ).map((e,i)=>r[e][i]=++i,         Overwrite the padding with 1..n
   r=[...Array(1+max(...a))].map(   Calculate number of lines
    _=>a.map((_,i)=>                For each number 1..n
     ` `.repeat(1+log10(++i)))))    Calculate the padding needed
  &&r.map(a=>a.join``).join`\n`     Join everything together

To shorten pow(-1,ceil(sqrt(i))) I rewrite it as sqrt(i-1)&1||-1 however this doesn't work for i=0 so to fix that I add 1 but this then flips the sign of the result which is why I end up with n-=.

  • \$\begingroup\$ heyyy you got a gold badge! nice job! and holy smokes you almost have as much rep as I do. keep it going! \$\endgroup\$ Jun 20, 2016 at 0:14
  • 1
    \$\begingroup\$ @CᴏɴᴏʀO'Bʀɪᴇɴ That's "merely" the Fanatic badge. Apparently I'm really close to getting the gold code-golf tag badge! \$\endgroup\$
    – Neil
    Jun 20, 2016 at 0:16
  • \$\begingroup\$ double holy smokes. I need to get moving XD \$\endgroup\$ Jun 20, 2016 at 0:17

Python 2, 137 bytes

for k in sorted(l):print l[k]

View the output on ideone.

  • \$\begingroup\$ Hm... It doesn't go on and on and on and on. \$\endgroup\$
    – Zizouz212
    Jun 20, 2016 at 0:30
  • \$\begingroup\$ @Zizouz212 It does, ideone just has a fixed output with and automatically breaks lines that are too long. \$\endgroup\$
    – flawr
    Jun 25, 2016 at 13:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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