Print a booklet

Reading a book is easy, but printing a book can be a bit tricky. When printing a booklet, the printer needs to have the pages arranged in a certain manner in order to be read from left to right. The way this is done is using a pattern like below

n, 1, 2, n-1, n-2, 3, 4, n-3, n-4, 5, 6, n-5, n-6, 7, 8, n-7, n-8, 9, 10, n-9, n-10, 11, 12, n-11…

Test Cases

4 page booklet: 4, 1, 2, 3

8 page booklet: 8,1,2,7,6,3,4,5

12 page booklet: 12,1,2,11,10,3,4,9,8,5,6,7

16 page booklet: 16,1,2,15,14,3,4,13,12,5,6,11,10,7,8,9

20 page booklet: 20,1,2,19,18,3,4,17,16,5,6,15,14,7,8,13,12,9,10,11

Your task is to, given an integer n that is a multiple of 4, display an array of numbers that could be used to print a book of n pages.

Note: As long as the output generates the correct numbers, whether delimited by spaces, commas, hyphens, or parenthesis, any method to getting to a solution can be used

This is a question so answers will be scored in bytes, with the fewest bytes winning.

• Are we guaranteed that input will always be divisible by 4 or even an even number? Either way, could you add a few more test cases, please? And welcome to PPCG :) Aug 6 '17 at 23:51
• Welcome to PPCG and nice first challenge! Note that we recommend proposing new challenges in the sandbox before posting them. Aug 6 '17 at 23:57
• Your input needs to be a multiple of 4 Aug 6 '17 at 23:57
• Would be nice (but maybe trivial) to support any value, filling with blank pages if needed (another challenge, maybe?) Aug 7 '17 at 14:56
• Can we delimit the array with a space, hyphen, or other delimiter instead of a comma? Aug 7 '17 at 20:01

JavaScript (ES6), 49 45 bytes

Saved 4 bytes with help from @RickHitchcock

f=(n,k=1)=>n<k?[]:[n,k,k+1,n-1,...f(n-2,k+2)]

Demo

f=(n,k=1)=>n<k?[]:[n,k,k+1,n-1,...f(n-2,k+2)]

console.log(JSON.stringify(f(4)))
console.log(JSON.stringify(f(8)))
console.log(JSON.stringify(f(12)))
console.log(JSON.stringify(f(16)))
console.log(JSON.stringify(f(20)))

Non-recursive, 51 bytes

n=>[...Array(n)].map((_,i)=>[2*n-i,,++i][i&2]+1>>1)

Demo

let f =

n=>[...Array(n)].map((_,i)=>[2*n-i,,++i][i&2]+1>>1)

console.log(JSON.stringify(f(4)))
console.log(JSON.stringify(f(8)))
console.log(JSON.stringify(f(12)))
console.log(JSON.stringify(f(16)))
console.log(JSON.stringify(f(20)))

• 47 bytes: f=(n,a=1)=>n<a+3?[]:[n,a,a+1,n-1,...f(n-2,a+2)] Aug 7 '17 at 13:32
• @RickHitchcock n<a is actually enough, so that's 4 bytes saved. Thanks! Aug 7 '17 at 13:51

05AB1E, 98 7 bytes

L[Žˆrˆ

Try it online!

Explanation

L           # push range [1 ... input]
# split as separate to stack
[Ž        # loop until stack is empty
ˆ       # add top of stack to global list
r      # reverse stack
ˆ     # add top of stack to global list
# implicitly display global list

Python 2, 9993885856 55 bytes

f=input()
for i in range(1,f/2,2):print-~f-i,i,i+1,f-i,

Try it online!

-6 bytes by removing unneeded indentation, thanks Oliver Ni

-5 bytes by changing the conditional, thanks Luis Mendo

-30 bytes by optimizing the print statements, thanks Arnold Palmer

-2 bytes by putting the loop on one line, thanks nedla2004

-1 byte by doing some wizardry, thanks Mr. Xcoder

• Save bytes by using 1 space instead of 4. Aug 7 '17 at 0:20
• Oh yeah, I always forget about that. Thanks. Aug 7 '17 at 0:21
• -29 bytes using a lambda (although this might be different enough to warrant a separate answer). Aug 7 '17 at 0:37
• @notjagan Go ahead and post that yourself if you want. Aug 7 '17 at 0:45
• 58 bytes by changing your print up just a bit. It now prints f-i+1,i,i+1,f-i in each loop instead of conditionally printing the last value. This also allowed removing the initial print f,. Aug 7 '17 at 2:09

Python 2, 46 bytes

lambda n:map(range(1,n+1).pop,n/4*[-1,0,0,-1])

Try it online!

Generates the range [1..n] and pops from the front and back in the repeating pattern back, front, front, back, ...

Python 2, 49 bytes

f=lambda n,k=1:n/k*and[n,k,k+1,n-1]+f(n-2,k+2)

Try it online!

Generates the first 4 elements, then recursively continues with the upper value n decreased by 2 and the lower value k increased by 2.

Python 2, 49 bytes

lambda n:[[n-i/2,i/2+1][-i%4/2]for i in range(n)]

Try it online!

Directly generates the i'th value of the list, using -i%4/2 as a Boolean for whether to take the lower or higher value.

Python 3, 6863 62 bytes

−5 bytes thanks to @notjagan (removing spaces and using [*...] instead of list()).

−1 byte thanks to @ovs (*1 instead of [:]).

def f(n):r=[*range(1,n+1)];return[r.pop(k%4//2-1)for k in r*1]

Try it online!

• -5 bytes. Aug 7 '17 at 1:26
• You can use r*1 instead of r[:] for -1 byte
– ovs
Aug 7 '17 at 5:42

MATL, 1917 10 bytes

:t"0&)@o?P

Try it online!

Explanation

:          % Implicitly input n. Push range [1 2 ... n]
t          % Duplicate
"          % For each (that is, do n times)
0&)      %   Push last element, and then subarray with remaining elements
@        %   Push 1-based iteration index
o?       %   Is it odd? If so
P      %     Reverse subarray of remaining elements
%   Implicit end
% Implicit end
% Implicitly display stack

Jelly,  12  11 bytes

Improved to 11 bytes, "Combinatorial Methods":

9Bṁ×ḶṚÆ¡‘Œ?

Try it online!

How?

This uses permutation calculations and the factorial number system:

9Bṁ×ḶṚÆ¡‘Œ? - Link n                        e.g. 16
9B          - nine in binary                     [1,0,0,1]
ṁ         - mould like n                       [1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1]
Ḷ       - lowered range(n)                   [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
×        - multiply                           [0,0,0,3,4,0,0,7,8,0,0,11,12,0,0,15]
Ṛ      - reverse                            [15,0,0,12,11,0,0,8,7,0,0,4,3,0,0,0]
Æ¡    - convert from factorial base        19621302981954 (=15*15!+12*12!+...+3*3!)
‘   - increment                          19621302981955 (we actually wanted 1*0! too)
Œ? - shortest permutation of natural numbers [1,2,...] that would reside at that
-   index in a sorted list of all permutations of those same numbers
-                                    [16,1,2,15,14,3,4,13,12,5,6,11,10,7,8,9]

Unimproved 12 byter, "Knitting Patterns":

RṚ‘żRs2Z€FḊṁ

Try it online!

How?

This is the simple approach, it creates two strands, interleaves them and then trims the loose ends:

RṚ‘żRs2Z€FḊṁ - Link: n                      e.g. 8
R            - range(n)                          [1,2,3,4,5,6,7,8]
Ṛ           - reverse                           [8,7,6,5,4,3,2,1]
‘          - increment                         [9,8,7,6,5,4,3,2]
R        - range(n)                          [1,2,3,4,5,6,7,8]
ż         - zip (interleave)                  [[9,1],[8,2],[7,3],[6,4],[5,5],[4,6],[3,7],[2,8]]
s2      - split into chunks of length 2     [[[9,1],[8,2]],[[7,3],[6,4]],[[5,5],[4,6]],[[3,7],[2,8]]]
Z€    - transpose €ach (cross-stitch?!)   [[[9,8],[1,2]],[[7,6],[3,4]],[[5,4],[5,6]],[[3,2],[7,8]]]
F   - flatten                           [9,8,1,2,7,6,3,4,5,4,5,6,3,2,7,8]
Ḋ  - dequeue (removes excess start)    [8,1,2,7,6,3,4,5,4,5,6,3,2,7,8]
ṁ - mould like n (removes excess end) [8,1,2,7,6,3,4,5]
• This is clever. +1 Aug 7 '17 at 10:14

Octave, 43 36 bytes

A port of this answer in C (gcc) can be found here.

@(n)[n-(k=1:2:n/2)+1;k;k+1;n-k](:)';

Explanation

1. k=1:2:n/2: Generates a linear sequence from 1 to n/2 in steps of 2. Note that this is immediately used in the next step.
2. [n-k+1;k;k+1;n-k]: Creates a 4 row matrix such that the first row creates the sequence n, n-2, n-4... down to n-(n/2)+2, the second row is 1, 3, 5... up to n/2 - 1, the third row is the second row added by 1 and the fourth row is the first row added by 1.
3. [n-k+1;k;k+1;n-k](:)': This stacks all of the columns of this matrix together from left to right to make a single column vector, and we transpose it to a row vector for easy display. Stacking the columns together this way precisely creates the sequence desired.

Note that this is an anonymous function, so you can assign it to a variable prior to using it, or you can use the built-in ans variable that gets created after creating the function.

Try it online!

• Hi, I think you can even shorten it by making it a anonymous function, so you don't have to call input. See this link: gnu.org/software/octave/doc/v4.0.3/… Aug 7 '17 at 13:10
• @Michthan True. I originally did it that way because the code was more than one statement. I took another crack at it so remove the call to input and I abused the syntax a bit more by storing the base incremental vector as I was creating the first row and taking the input n from the actual anonymous function input itself so I can now fit it into one statement. Thanks! Aug 7 '17 at 14:50

R, 48 bytes (improved)

Thanks to @Giuseppe for -7 bytes!

n=scan();(x=order(1:n%%2))[order(-(n/2+.5-x)^2)]

The trick is that x=1:n;x[order(x%%2)] is equivalent to order(1:n%%2).

Try it online!

R, 55 bytes (original)

Golfed

n=scan();x=1:n;x=x[order(x%%2)];x[order(-(n/2+.5-x)^2)]

n=scan()

Define x as sequence of pages from 1 to n.

x=1:n

Order pages so even pages are before uneven pages.

x=x[order(x%%2)]

Order pages in descending order with respect to the centre of the book computed by n/2+.5.

x[order(-(n/2+.5-x)^2)]

Example with 8 pages:

• centre is 4.5;
• pages 1 and 8 are the most distant from the centre, but 8 comes first because 8 is even;
• pages 2 and 7 are the next most distant from the centre, but 2 comes first as 2 is even;
• and so on.

Try it online!

• nice, way better than my (stolen) solution Aug 7 '17 at 21:34
• 48 bytes! Aug 7 '17 at 21:44
• The trick was noticing that (1:n)[order(1:n%%2)] is the same as order(1:n%%2) Aug 7 '17 at 21:45

Mathematica, 5453 45 bytes

Join@@Range[#][[(-1)^k{k,-k}]]~Table~{k,#/2}&

Explanation

Join@@Range[#][[(-1)^k{k,-k}]]~Table~{k,#/2}&  (* Input: # *)
~Table~{k,#/2}   (* Iterate from k=1 to #/2 *)
Range[#][[            ]]                 (* From {1..#}, take... *)
{k,-k}                   (* k-th and negative k-th element *)
(* negative k-th = k-th from the end *)
(-1)^k                         (* Reversed for odd k *)
Join@@                                         (* Join the result *)

Python 2, 64 63 bytes

-1 byte thanks to ovs!

lambda n:sum([[i,i+1,n-i,n+~i]for i in range(1,n/2,2)],[n])[:n]

Try it online!

• n-i-1 can be n+~i
– ovs
Aug 7 '17 at 5:40

n#a|n<a=[]|x<-n-2=n:a:a+1:n-1:x#(a+2)
(#1)

Try it online!

One byte longer:

f n=[1,3..div n 2]>>= \x->[n-x+1,x,x+1,n-x]

Java 8, 84 72 bytes

n->{for(int j=0;++j<n;System.out.printf("%d,%d,%d,%d,",n--,j++,j,n--));}

or

n->{for(int j=0;++j<n;System.out.print(n--+","+j+++","+j+","+n--+","));}

-12 bytes thanks to @TheLethalCoder's comment on the C# answer.

n->{int r[]=new int[n],i=1,N=n,J=1;for(r=n;i<n;r[i]=-~i++%4<2?J++:--N);return r;}

Explanation:

Try it here.

n->{                  // Method with integer parameter and no return-type
for(int j=0;++j<n;  //  Loop from 1 to n (exclusive)
System.out.printf("%d,%d,%d,%d,",n--,j++,j,n--)
//   Print four numbers simultaneously
);                  //  End of loop
}                     // End of method

Perl 5, 47 + 1 (-n) = 48 bytes

$,=$";print$_--,$i+++1,$i+++1,$_--,''while$_>$i

Try it online!

• Managed to find a slightly different approach, but ended up with the exact same byte count! Try it online! Aug 7 '17 at 12:04

Swift 3, 74 bytes

func g(f:Int){for i in stride(from:1,to:f/2,by:2){print(f-i+1,i,i+1,f-i)}}

Try it online!

Swift 3, 60 bytes

{f in stride(from:1,to:f/2,by:2).map{(f-$0+1,$0,$0+1,f-$0)}}

For some reason, this does not work in any online environment I have tried so far. If you want to test it, put var g= in front of it, and call it with print(g(12)) in Xcode (Playgrounds).

Here is a picture after I've ran it in an Xcode playground, version 8.3.1 (Running Swift 3.1): QBIC, 25 bytes

[1,:/2,2|?b-a+1,a,1+a,b-a

Although the input is %4, the actual rhythm is 2-based.

Explanation

[1,:/2,2|   FOR ( b=1; b <= <input>/2; b=b+2)
?           PRINT
b-a+1,     n
a,         1
1+a,       2
b-a        n-1

C (gcc), 66 bytes

A port of my Octave answer to C (gcc):

f(n,i){for(i=1;i<n/2;i+=2)printf("%d %d %d %d ",n-i+1,i,i+1,n-i);}

Try it online!

cQuents, 21 bytes

=n::n-z+1,z+1,x-1,z-1

Try it online!

Explanation

Implicit input n
=n                          First item in the sequence is n
::                        Mode :: (Sequence 2): print sequence from 1 to n
Comma delimited items are rotated through
n-z+1,                    n - previous + 1
z+1,                previous + 1
x-1,            third-previous - 1
z-1         previous - 1

R, 64 60 bytes

Devastatingly outgolfed by djhurio! His answer is quite elegant, go upvote it.

n=scan();matrix(c(n-(k=seq(1,n/2,2))+1,k,k+1,n-k),4,,T)[1:n]

A port of rayryeng's Octave answer.

Try it online!

original solution (64 bytes):

f=function(n,l=1:n)if(n,c(l[i<-c(n,1,2,n-1)],f(n-4,l[-i])),{})

Recursive function.

Try it online!

• First time someone's ever used an answer of mine as inspiration. Thanks :) Aug 7 '17 at 16:12
• It was hard to beat you, but I managed this with 55 byte answer (codegolf.stackexchange.com/a/138045/13849). Aug 7 '17 at 21:35

Bash + Perl + Groff + Psutils, 48 bytes

perl -nE'say".bp
"x--$_'|groff|psbook>/dev/null Shows output on stderr. Output contains some trailing garbage. Example of use:$ echo 20 | perl -nE'say".bp
> "x--$_'|groff|psbook>/dev/null                     Wrote 20 pages, 4787 bytes Pyth, 21 20 bytes sm[hK-QddhdK):1/Q2 2 Test Suite. If outputting as a nested list is allowed: Pyth, 20 19 bytes m[hK-QddhdK):1/Q2 2 Test Suite. Explanation sm[hK-QddhdK):1/Q2 2 - Full program. m :1/Q2 2 - Map over range(1,input()/2,2) with a variable d. [ ) - Construct a list with: hK-Qd - Input - d + 1, d - d, hd - d + 1 and K - Input - d. s - Flattens the list and prints implicitly. Ruby, 40 bytes ->n{1.step(n/2,2){|x|p n-x+1,x,x+1,n-x}} Try it online! C#, 107 bytes int[]F(int p){var a=new int[p];for(int i=0,q=1;q<p;a[i++]=p--){a[i++]=p--;a[i++]=q++;a[i++]=q++;}return a;} Keep two counters, one starting at 1, one at p. In each loop iteration, write four elements and just increment or decrement counters after each entry. When the counters meet in the middle, stop. int[] F(int p) { var a = new int[p]; for(int i = 0, q = 1; q < p; a[i++] = p--) { a[i++] = p--; a[i++] = q++; a[i++] = q++; } return a; } • You can save a few bytes by placing the method in a delegate. Your code would then look like this: p=>{var a=new int[p];for(int i=0,q=1;q<p;a[i++]=p--){a[i++]=p--;a[i++]=q++;a[i++]=q++;}return a;};, with the System.Func<int, int[]> f = not having the included into the bytecount. Also you can add a link to TIO, which is very useful when trying to allow people to try your code out by themselves! Aug 7 '17 at 7:16 • @IanH. When using a lambda the trailing semi colon can be omitted. Aug 7 '17 at 10:04 • Initialise q to 0 and pre increment at q<p -> ++q<p and then remove the second post increment to save a byte. Move the two trailing loop statements into the last stage of the for loop so you can remove the curly braces. Aug 7 '17 at 10:09 • If a trailing comma is allowed the following works for 71 bytes p=>{for(int q=0;++q<p;)System.Console.Write(p--+$",{q++},{q},{p--},");}. TIO. Aug 7 '17 at 10:16

(x:y:r)#(a:b:s)=x:y:a:b:r#s
f n=take n$n:[1..]#[n-1,n-2..] Try it online! Pyth, 2724 23 bytes -3 bytes by printing throughout instead of at the end. -1 Thanks to Mr. Xcoder V:1/Q2 2pjd[-QtNNhN-QNk Try it online! Or on the online Compiler/Executor This is my first real program in Pyth, so there's probably better methods that I don't know about. Explanation V:1/Q2 2pjd[-QtNNhN-QNk V:1/Q2 2 # For N in range(1, Q/2, 2): pjd # print " ".join(...), [-QtNNhN-QNk # The list [n - (N-1), N, N + 1, n - N, ""] (n is input) • I found some improvements, and decided they deserved their own answer. Aug 7 '17 at 5:58 • By the way, replace FN with V for -1 byte Aug 7 '17 at 5:59 C++ (gcc), 8984 68 bytes As unnamed generic lambda. n is #pages (%4==0) and C is a reference parameter for the result, an empty container like vector<int> (only push_back is needed). [](int n,auto&C){for(int i=0,j=0;i<n;C.push_back(++j%4<2?n--:++i));} previous solution: #define P C.push_back( [](int n,auto&C){for(int i=0;i<n;P n--),P++i),P++i),P n--));} Try it online! Slightly ungolfed: auto f= [](int n,auto&C){ for(int i=0,j=0; i<n; C.push_back(++j%4<2 ? n-- : ++i)); } previous solution slightly ungolfed: auto f= [](int n, auto&C){ for( int i=0; i<n; P n--), P++i), P++i), P n--) ); } ; It was quite straightforward developed and there are sure some minor optimizations in the arithmetics. • Edit1: unification of the arithmetics saved 5 byte • Edit2: after the unification the 4 steps were combined Usage: std::vector<int> result; f(n, result); Print-Variant, 77 bytes out-dated If you insist on printing the values, there is this solution: [](int n,auto&o){for(int i=0;i<n;o<<n--<<' '<<++i<<' '<<++i<<' '<<n--<<' ');} Where o is your desired std::ostream, like std::cout Usage (if 2nd lambda was assigned to g): g(n, std::cout); Common Lisp, 79 bytes (defun f(n &optional(k 1))(and(> n k)(,n,k,(1+ k),(1- n),@(f(- n 2)(+ k 2))))) Try it online! Lua, 94 bytes For this challenge I actually came up with 2 different methods that are both 94 bytes. Method 1: function f(n,i)i=i or 1 return n>i and('%s,%s,%s,%s,%s'):format(n,i,i+1,n-1,f(n-2,i+2))or''end Commented Code: function f(n,i) i=i or 1 -- On the first iteration i will be nil so I'm setting it's value to 1 if it is. return n>i and ('%s,%s,%s,%s,%s'):format(n,i,i+1,n-1,f(n-2,i+2)) or '' -- Here i return a ternary statement -- If n>i is true, it will return a string using string.format() and part of this is recursion -- If it's false, it will just return an empty string end Method 2: function f(n,i)i=i or 1 return n>i and n..','..i..','..i+1 ..','..n-1 ..','..f(n-2,i+2)or''end This method is similar to the first method however I'm instead returning a concatenated string instead of string.format() In both methods I have used the concept of n and i getting closer together PHP, 51+1 bytes while($i<$k=&$argn)echo$k--,_,++$i,_,++$i,_,$k--,_;

prints page numbers separated by underscore with a trailing delimiter.
Run as pipe with -nR or try it online.

J, 22 bytes

($,)_2|.]\1+],@,.&i.- Try it online! Explanation ($,)_2|.]\1+],@,.&i.-  Input: integer n
]          Identity
-  Negate
&i.   Form the ranges [0, 1, ..., n-1] and [n-1, ..., 1, 0]
,.      Interleave
,@        Flatten