10
\$\begingroup\$

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  |
      \||_____|
    
\$\endgroup\$
10
  • \$\begingroup\$ the "clear the screen" bonus seems to be a language bonus rather than a code bonus... \$\endgroup\$ Aug 2, 2014 at 6:53
  • \$\begingroup\$ 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? \$\endgroup\$ Aug 2, 2014 at 6:54
  • \$\begingroup\$ I have noticed, thanks to your notice, that there are no trailing spaces. But are we required not to include them either? \$\endgroup\$ Aug 2, 2014 at 6:56
  • \$\begingroup\$ @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"? \$\endgroup\$ Aug 2, 2014 at 6:57
  • 1
    \$\begingroup\$ @JanDvorak, it seems to me to be more a "run the program in a POSIX terminal" bonus. \033[2J\033[;H \$\endgroup\$ Aug 5, 2014 at 15:22

2 Answers 2

4
\$\begingroup\$

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;
        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;
    }
}
\$\endgroup\$
4
\$\begingroup\$

Java, 1039 1001 993 953 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]);}
        // read file
        Scanner s=new Scanner(new FileReader(c[0]));while(s.hasNext()){t+=s.nextLine();}         
        l=t.length();
        // read input
        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.

\$\endgroup\$
2
  • \$\begingroup\$ I'm pretty sure you don't need the public keywords... Also, does import java.*; work? \$\endgroup\$
    – user16402
    Aug 7, 2014 at 16:29
  • \$\begingroup\$ @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. \$\endgroup\$
    – tim
    Aug 7, 2014 at 17:09

Your Answer

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

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