# Write a book writer

Here is a fairly simple ASCII depiction of an open book:

|\
| \
|  \
|   \
|    \__________
|    ||         |
|    || Lorem i |
\    || psum do |
\   || lor sit |
\  ||  amet,  |
\ || consect |
\||_________|


Notice that the text portion is only on the right page and is 7 characters wide by 5 tall. Also notice that the top edge of the book has 5 backslashes and 10 underscores. The 10 comes from the text width plus 3 and the 5 is half of 10.

Using the same scaling format we can resize the book to have a text area w characters wide and h high, where w is any odd positive integer and h is any positive integer.

Some w×h books: 1×1, 1×2, 3×2

                    |\
|\        | \
|\        | \____   |  \______
| \____   | ||   |  |  ||     |
| ||   |  | || L |  \  || Lor |
\ || L |  \ || o |   \ || em  |
\||___|   \||___|    \||_____|


The number of underscores at the top is always w+3 and the number of backslashes is always (w+3)/2.

# Goal

Write a progam that takes a filename and w and h as command line arguments, and outputs a book with those text dimensions to stdout, displaying the contents of the file.

When the file has more text than will fit in one page the N key should print the next page and B should go back a page. Nothing should happen if B is pressed from the first page or N is pressed from the last page. The program should stop when the Q key is hit.

# Example

Suppose f.txt contains Lorem ipsum dol? and the user has pressed the key sequence N N B N N Q. The program should run something like this:

>>> bookmaker f.txt 3 2
|\
| \
|  \______
|  ||     |
\  || Lor |
\ || em  |
\||_____|

|\
| \
|  \______
|  ||     |
\  || ips |
\ || um  |
\||_____|

|\
| \
|  \______
|  ||     |
\  || dol |
\ || ?   |
\||_____|

|\
| \
|  \______
|  ||     |
\  || ips |
\ || um  |
\||_____|

|\
| \
|  \______
|  ||     |
\  || dol |
\ || ?   |
\||_____|

>>>


Notice that there is a newline after every book and no trailing spaces. This is required.

# Notes

• You may assume the file only contains printable ASCII characters (hex 20 to 7E).
• Print one character in each available spot, regardless of word boundaries.
• w and h are optional arguments that default to 7 and 5 respectively. Your program will either be given neither or both. (You may assume input is always well formed.)
• Fill any empty text space on the last page with spaces.
• Q should still be required to quit if there is only one page.

# Winning

The shortest program in bytes after bonuses are applied wins.

Bonuses

• Remove leading spaces so that every line starts with a word (or word segment). e.g. | amet, | in the first example would become | amet, c |. (-30 bytes)
• Clear the screen of previously drawn books after N or B is pressed (and T if you do the bonus after this) so the book looks like its changing pages in place. (-20 bytes)
• Make the T key instantly toggle between the text being drawn from left-to-right top-to-bottom (the default), to top-to-bottom left-to-right. If you did the first bonus it should work for columns in the top-to-bottom mode. (-100 bytes)

So for example:

|\
| \
|  \______
|  ||     |
\  || Lor |
\ || em  |
\||_____|


becomes

|\
| \
|  \______
|  ||     |
\  || Lrm |
\ || oe  |
\||_____|

• the "clear the screen" bonus seems to be a language bonus rather than a code bonus... Aug 2, 2014 at 6:53
• You say in text that the filename and book dimensions come from STDIN, but then you proceed to take them as arguments. Which is it, then? Aug 2, 2014 at 6:54
• I have noticed, thanks to your notice, that there are no trailing spaces. But are we required not to include them either? Aug 2, 2014 at 6:56
• @JanDvorak Sorry, I meant they are only arguments. You you need to have NO trailing spaces. Can you give an example of where the clearing becomes a "code bonus"? Aug 2, 2014 at 6:57
• @JanDvorak, it seems to me to be more a "run the program in a POSIX terminal" bonus. \033[2J\033[;H Aug 5, 2014 at 15:22

## C# 535bytes

Score is 655bytes of code -20byte bonus for clearing, and -100byte bonus for T key... I think, can't say I'm sure I haven't missed something in the spec

I may try and collapse the loops by having the W method return the s argument, but that would require effort, so no promises.

Golfed code:

using C=System.Console;using K=System.ConsoleKey;class P{static void W(int x,int y,string s){C.SetCursorPosition(x,y);C.Write(s);}static void Main(string[]a){int b=a.Length,w=b>0?int.Parse(a[0]):7,h=b>1?int.Parse(a[1]):5,p=0,i,j,o,T=1;var F=System.IO.File.ReadAllText("f.txt");b=(w+3)/2;S:C.Clear();for(i=0;i<w+3;i++){W(o=i+b+1,b-1,"_");W(o,h+b+1,"_");}for(i=0;i<h+2;){W(0,i,"|");W(b,o=i+++b,"||");W(b+w+4,o,"|");}for(i=0;i<b;){W(i+1,i,"\\");W(i,++i+h+1,"\\");}for(i=0;i<w;i++)for(j=0;j<h;)if((o=T>0?j++*w+p+i:i*h+p+j++)<F.Length)W(i+b+3,j+b,F[o]+"");K k=C.ReadKey(1>0).Key;p+=k==K.N&p<F.Length-w*h?w*h:k==K.B&p>0?-w*h:0;T=k!=K.T?T:-T;if (k!=K.Q)goto S;}}


Formatted a bit:

using C=System.Console;
using K=System.ConsoleKey;

class P
{
static void W(int x,int y,string s)
{
C.SetCursorPosition(x,y);
C.Write(s);
}

static void Main(string[]a)
{
int b=a.Length,w=b>0?int.Parse(a[0]):7,h=b>1?int.Parse(a[1]):5,p=0,i,j,o,T=1;
b=(w+3)/2;

S:
C.Clear();

for(i=0;i<w+3;i++)
{
W(o=i+b+1,b-1,"_");
W(o,h+b+1,"_");
}

for(i=0;i<h+2;)
{
W(0,i,"|");
W(b,o=i+++b,"||");
W(b+w+4,o,"|");
}

for(i=0;i<b;)
{
W(i+1,i,"\\");
W(i,++i+h+1,"\\");
}

for(i=0;i<w;i++)
for(j=0;j<h;)
if((o=T>0?j++*w+p+i:i*h+p+j++)<F.Length)
W(i+b+3,j+b,F[o]+"");

p+=k==K.N&p<F.Length-w*h?w*h:k==K.B&p>0?-w*h:0;
T=k!=K.T?T:-T;
if (k!=K.Q)
goto S;
}
}


# Java, 10391001993953 946

With bonus: Remove leading spaces (-30 bytes) -> 1009 971 963 923 916

Clearing the screen is not worth it with java (except if I just print a couple of newlines. But then the user has to use the correct console size)

Code:

import java.io.*;import java.util.*;class B {static int w=7,h=5,p,l;static String t="",o,u=" ",y="\\";public static void main(String[]c)throws Exception{if(c.length>1){w=Integer.valueOf(c[1]);h=Integer.valueOf(c[2]);}Scanner s=new Scanner(new FileReader(c[0]));while(s.hasNext()){t+=s.nextLine();}l=t.length();s = new Scanner(System.in);while(true){int q=w+3,z=q/2,i=0,j=0,a=w*h;o="";for(;i<z;i++)o+="\n|"+r(u,i)+y;o+=r("_", q);for(;j<h+2-z;j++){o+="\n|"+r(u,i-1)+"||";if(j==0)o+=r(u,w+2);else o+=u+t()+u;o+="|";}for(;i>0;i--){o+="\n"+r(u,z-i)+y+r(u,i-1)+"||";if(i>1)o+=u+t()+" |";}o+=r("_",w+2)+"|";System.out.print(o);switch(s.next().charAt(0)){case'Q':return;case'B':p=p>a?p-2*a:p-a;break;case'N':p=p>l?p-a:p;}}}static String t(){int e=p+w>l?l:p+w;String r="";if(p<=e)r=t.substring(p,e);r=r.replaceAll("^\\s+","");int y=r.length();p+=w;return y==w?r:r+r(u,w-y);}static String r(String s,int i){return new String(new char[i]).replace("\0",s);}


Pretty:

import java.io.*;import java.util.*;
class B {
static int w=7,h=5,p,l; // w = text width, h = text height, p = current position in text
static String t="",o,u=" ",y="\\";
public static void main(String[]c)throws Exception{
// get w and h of text, default to 7x5
if(c.length>1){w=Integer.valueOf(c[1]);h=Integer.valueOf(c[2]);}
l=t.length();
s = new Scanner(System.in);
while(true){
// print book
int q=w+3,z=q/2,i=0,j=0,a=w*h; // q = number of underscores at the top, z = number of backslashes
o="";
// print top of book
for(;i<z;i++)o+="\n|"+r(u,i)+y;
o+=r("_", q);
// print middle of book (hp-z lines). right now: i = z -1
for(;j<h+2-z;j++){o+="\n|"+r(u,i-1)+"||";if(j==0)o+=r(u,w+2);else o+=u+t()+u;o+="|";}
// print bottom of book
for(;i>0;i--){o+="\n"+r(u,z-i)+y+r(u,i-1)+"||";if(i>1)o+=u+t()+" |";}
o+=r("_",w+2)+"|";
System.out.print(o);
// user input
switch(s.next().charAt(0)){
case'Q':return;
case'B':p=p>a?p-2*a:p-a;break;
case'N':p=p>l?p-a:p;
}
}
}

/** return w characters of string t, from given position p. increase p*/
static String t(){
int e=p+w>l?l:p+w;
String r="";
if(p<=e)r=t.substring(p,e);
r=r.replaceAll("^\\s+",""); // remove leading spaces (cost:28 chars)
int y=r.length();
p+=w;
return y==w?r:r+r(u,w-y);
}
static String r(String s,int i){return new String(new char[i]).replace("\0",s);} // repeat given string i times


If the program does not have to run forever, I could also save some bytes by removing the while loop and just calling main.

This is not optimal, but it's a start.

• I'm pretty sure you don't need the public keywords... Also, does import java.*; work?
– user16402
Aug 7, 2014 at 16:29
• @professorfish I thought about import java.*; as well, but it doesn't work. And the main method does need to be exactly public static void main(String[]c) (including public), otherwise it is not recognized. But the class of course doesn't need to be public, good catch.
– tim
Aug 7, 2014 at 17:09