Escreva um escritor de livros

10

Aqui está uma descrição ASCII bastante simples de um livro aberto:

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

Observe que a parte do texto está apenas na página direita e tem 7 caracteres de largura por 5 de altura. Observe também que a borda superior do livro possui 5 barras invertidas e 10 sublinhados. O 10 vem da largura do texto mais 3 e o 5 é metade de 10.

Usando o mesmo formato de escala, podemos redimensionar o livro para ter uma área de texto com caracteres de largura eh alto, onde w é qualquer número inteiro positivo ímpar e h é qualquer número inteiro positivo.

Alguns livros w × h : 1 × 1, 1 × 2, 3 × 2

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

O número de sublinhados na parte superior é sempre w +3 e o número de barras invertidas é sempre ( w +3) / 2.

Objetivo

Escrever um progama que leva um nome de arquivo e w e h como argumentos de linha de comando, e produz um livro com essas dimensões de texto para stdout, exibindo o conteúdo do arquivo.

Quando o arquivo tiver mais texto do que caberá em uma página, a Nchave deverá imprimir a próxima página e Bvoltar uma página. Nada deve acontecer se Bfor pressionado na primeira página ou Npressionado na última página. O programa deve parar quando a Qtecla for pressionada.

Exemplo

Suponha que f.txtcontém Lorem ipsum dol?e o usuário tenha pressionado a sequência de teclas N N B N N Q. O programa deve executar algo como isto:

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

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

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

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

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

>>>

Observe que há uma nova linha após cada livro e não há espaços à direita. Isso é necessário.

Notas

  • Você pode assumir que o arquivo contém apenas caracteres ASCII imprimíveis (hex 20 a 7E).
  • Imprima um caractere em cada ponto disponível, independentemente dos limites das palavras.
  • w e h são opcionais argumentos que padrão a 7 e 5, respectivamente. Seu programa receberá um ou ambos. (Você pode assumir que a entrada está sempre bem formada.)
  • Preencha qualquer espaço de texto vazio na última página com espaços.
  • Q ainda será necessário sair se houver apenas uma página.

Ganhando

O programa mais curto em bytes após a aplicação dos bônus vence.

Bónus

  • Remova os espaços à esquerda para que cada linha comece com uma palavra (ou segmento de palavra). por exemplo, | amet, |no primeiro exemplo se tornaria | amet, c |. (-30 bytes)
  • Limpe a tela dos livros previamente desenhados depois Nou Bpressionada (e Tse você fizer o bônus depois disso) para que o livro pareça com as páginas em mudança. (-20 bytes)
  • Faça com que a Tchave alterne instantaneamente entre o texto que está sendo desenhado da esquerda para a direita, de cima para baixo (o padrão), de cima para baixo, da esquerda para a direita. Se você fez o primeiro bônus, ele deve funcionar para colunas no modo de cima para baixo. (-100 bytes)

    Então, por exemplo:

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

    torna-se

    |\
    | \
    |  \______
    |  ||     |
    \  || Lrm |
     \ || oe  |
      \||_____|
    
Passatempos de Calvin
fonte
o bônus de "limpar a tela" parece ser um bônus linguagem, em vez de um bônus código ...
John Dvorak
Você diz no texto que as dimensões do nome do arquivo e do livro vêm de STDIN, mas depois as aceita como argumentos. Qual é então?
John Dvorak
Percebi, graças ao seu aviso, que não há espaços à direita. Mas somos obrigados a não incluí-los também?
John Dvorak
@ JanDvorak Desculpe, eu quis dizer que eles são apenas argumentos. Você não precisa de espaços à direita. Você pode dar um exemplo de onde a compensação se torna um "bônus de código"?
Calvin Hobbies
11
@ JanDvorak, parece-me mais um bônus "execute o programa em um terminal POSIX". \033[2J\033[;H
Peter Taylor

Respostas:

3

C # 535bytes

A pontuação é 655 bytes de código -20 bytes de bônus para limpeza e -100 bytes de bônus para a chave T ... Acho que não posso dizer que tenho certeza de que não perdi algo nas especificações

Posso tentar recolher os loops fazendo com que o método W retorne o argumento s, mas isso exigiria esforço, portanto não há promessas.

Código de golfe:

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;}}

Formatado um pouco:

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;
    }
}
VisualMelon
fonte
4

Java, 1039 1001 993 953 946

Com bônus: Remova os espaços à esquerda (-30 bytes) -> 1009 971 963 923 916

Limpar a tela não vale a pena com java (exceto se eu imprimir algumas linhas novas. Mas o usuário precisará usar o tamanho correto do console)

Código:

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);}

Bonita:

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

Se o programa não precisar ser executado para sempre, eu também poderia salvar alguns bytes removendo o loop while e apenas chamando main.

Isso não é ideal, mas é um começo.

tim
fonte
Tenho certeza de que você não precisa das publicpalavras - chave ... Além disso, import java.*;funciona?
@professorfish pensei import java.*;também, mas não funciona. E o método principal precisa ser exatamente public static void main(String[]c)(inclusive public), caso contrário, não é reconhecido. Mas a turma, claro, não precisa ser pública, boa captura.
tim