Letreiro de rolagem


13

Após minha entrada no Hello World Ofuscado, pensei que seria divertido compartilhar o código subjacente. Mas por que apenas mostrar o código, vamos torná-lo também um golfe!

Desafio

Escreva um script que role uma corda pelo terminal, da direita para a esquerda, estabelecendo-se no lado esquerdo.

Entrada

Leva uma string como argumento.

Resultado

Imprime a marca de rolagem em STDOUT. Largura máxima de ~ 50 caracteres. Começa com 0 ou 1 caractere sendo exibido. Algum espaço entre as letras durante a rolagem. Pára quando resolvido (sem espaço extra entre caracteres de palavras). Rolagem lenta, mas não muito lenta (<1s por iteração).

Exemplo

Executando script com arg 'Hello World'

                                                   H

mais tarde

                H    e    l    l    o         W    o

mais tarde

H    e    l    l    o          W    o    r    l    d

mais tarde

Hell    o         W    o    r    l    d

finalmente

Hello World

Para um exemplo em execução, tente meu código no desafio "Hello World". Eventualmente eu vou postar o meu. Atualmente, são 202 caracteres em Perl. Agora que existem alguns concorrentes, postei o meu nas respostas.

Vencedora

Não quero que as restrições sejam absolutas, por isso as deixei um pouco vagas. O roteiro mais curto que segue o espírito do meu original vencerá.

Notas

Este jogo assume um xtermambiente. Caso outro ambiente seja útil, apenas ambientes semelhantes serão comparados e um vencedor separado poderá ser declarado para cada um.

Adendo (25 de abril de 2012)

Para resolver alguns problemas, estou tomando uma decisão. Sua contagem de caracteres deve incluir o código necessário para:

  1. Flush STDOUT (olhando para você, Ruby)
  2. Implementar sleepcom atraso de tempo <1s (olhando para você, Perl)

Isso pode ser feito quando a linha de comando alterna para um intérprete, mas esses caracteres contam no total (sem o espaço em branco).


Estou um pouco preocupado com comportamentos terminais para esse tipo de coisa ... xterm, vt102...?
— dmckee --- ex-moderador gatinho

Estou assumindo o xterm, mas não acho que isso importe muito. Talvez eu não entenda sua preocupação?
— Joel Berger

Esses truques geralmente são produzidos com base na maneira como vários terminais lidam com alguns dos caracteres que não são de impressão, e os terminais diferem no que eles podem fazer e em quais sequências produzem os efeitos. Para reprodutibilidade, pode ser bom ter um ambiente de terminal especificado.
— dmckee --- ex-moderador gatinho

1
Isso ajudará você se alguém postar uma resposta muito curta que depende de um terminal obscuro para o qual você não tem um emulador, mas tudo bem.
— dmckee --- gatinho ex-moderador

ok, acho que tenho agora. Graças para os pensamentos :-)
— Joel Berger

Respostas:


5

python 2 - 146 caracteres

edit: transformou uma função em vez de entrada através de stdin. o primeiro argumento é a sequência e o segundo argumento é o comprimento que você deseja que seja. então a invocação seria f('Hello World', 50). Eu também fiz muito mais suave; quando cada personagem 'pousou' houve uma pausa estranha

import os,time
def f(x,n):
 y=' '*n+'  '.join(x);z=0
 while y:w=y[0]==x[z];y=y[1+w:];z+=w;os.system('cls');print((x[:z]+y)[:n]);time.sleep(0.1)

velho, 158 caracteres:

import os,time,sys
x=' '.join(sys.argv[1:])
y=' '*50+'  '.join(x)
z=0
while y:z+=y[0]==x[z];y=y[1:];os.system('cls');print((x[:z]+y)[:50]);time.sleep(0.1)

Usando o bash (pelo menos em uma instalação recente do MacOSX e CentOS), o comando shell usado para limpar a tela do terminal deve ser 'clear' e não 'cls'.
— Paolo

'cls' para windows, 'clear' para compilações OSX / Linux, eu acho
— Blazer

Aconselhamento sobre como iniciar o programa para aqueles que não lidam com python diariamente, seria útil. Inicie o python. colar código, ligar f("Hello World, 40)funcionou para mim.
— usuário desconhecido

@user eu hum. Eu coloquei invocação lá em cima?
— Blazer

4

Ruby, 93 91 89 caracteres

u="\1";s=u*50+[*$*[0].chars]*(u*3);$><<s.tr(u," ")[0,50]+" \r"while s.sub!u,""*sleep(0.1)

O texto a ser exibido deve ser fornecido como argumento de linha de comando, por exemplo

ruby marquee.rb "Hello World"

para o exemplo mostrado acima. Infelizmente não posso mostrar a animação aqui, então você deve experimentar o código por conta própria.

Versão anterior:

s=" "*67+[*$*[0].chars]*"   ";(s.size*3/4).times{|j|s[j/3]='';$><<s[16,50]+" \r";sleep 0.1}

Tamanho impressionante. Não é muito bom, porém, sou eu (estou em uma máquina de baixa potência no momento) ou é assim que o código funciona?
— Joel Berger

Descobri isso, eu tinha que definir STDOUT.sync=true;para que ele autoflushes. O Perl equiv é $|++. São 17 caracteres adicionais, mas ainda bem abaixo do meu. Bem, eu não posso ter Ruby batendo Perl! Vou ter que trabalhar. Agradável.
— Joel Berger

Se eu ligar ruby1.8 "Hello World", recebo, não exatamente para minha surpresa, um erro dizendo:ruby1.8: No such file or directory -- Hello World (LoadError)
— usuário desconhecido

@userunknown talvez você deve colocar o caminho para o arquivo de origem lá, também: ruby foo.rb args;-)
— Patrick Oscity

@padde: Sim, eu deveria. Infelizmente, Howard editou seu post sem me informar sobre sua alteração. Dê uma olhada na história para entender minha pergunta.
— usuário desconhecido

3

C, 94 83 80 173 caracteres

EDIT: Adicionado muito código, implementa toda a funcionalidade solicitada agora. A constante 1e8pode ser ajustada para controlar a velocidade. Na minha máquina, é bastante rápido.
Alguns personagens certamente podem ser salvos aqui. lpode ser estático (salva a inicialização), cpode se tornar um ponteiro (substituindo b+c).

char b[99],c=1;
main(a,t,w,i,l)char**t;{
    for(l=0;b[l++]=*t[1]++;b[l++]=32);
    for(w=80;i--||
        printf("\033[F\033[K%*.*s\n",w-=l<a,a++,b,i=1e8)>l+6||
        b[++c]&&memmove(b+c-1,b+c,l););
}

Versão antiga (80 caracteres), com funcionalidade parcial:
Salva alguns caracteres substituindo char**tpor int*t. Funciona bem em 32 bits ( int**tsuportaria 64 bits).

main(i,t,w)
    int*t;
{
    for(w=80;i--||printf("\033[F\033[K%*s\n",w,t[1],i=1e8)*--w;);
}

2

K&R C - 431 416 caracteres

Respeita o padrão a um alto grau. Usa ncurses, portanto deve ser amplamente independente do terminal. Há uma leve gagueira quando o texto atinge o lado devido a alguns truques executados para preservar o espaço em branco pretendido na string.

A string a ser usada deve ser passada como o primeiro argumento na linha de comando (e deve ser escapada se contiver espaços, mais ainda se contiver a !como minha string de teste ( Hello, World!)).

#include <ncurses.h>
#include <unistd.h>
#define T usleep(1e5),S(l)
#define U mvprintw(23,0,"%s",l),refresh()
char l[63],*p,*q,r;
S(char*s){r=0;if(*s==32)q=s++;else{for(;*s-32||*(s+1)-32;s++); 
for(q=s;*s==32;s++);(s-q)&1?s--:usleep(1e5);}
for(r=0;*s;*q++=*s++){*s-32?r=1:0;}return r;}
main(int c,char**v){initscr();curs_set(0);for(c=0;c<62;l[c++]=32);
for(p=*++v;*p;){l[52]=*p++;U;T;U;T;U;T;}for(;T;U);getch();endwin();}

De uma forma mais legível e comentada:

#include <ncurses.h>
#include <unistd.h>

char l[63] /* take advantage of 0 initialization */,
  *p,*q, r;

/* Remove the first unwanted space. Unwanted means at the begining of
 * the line, all of even length blocks between non-spaces, and
 * all-bu-one of odd length blocks between non-spaces.
 *
 * Return true if the removed space occurs before a non-space character.
 */
S/*lide marquee*/(char*s){
  r=0; /* initialize the return value */
  if(*s==' '){
    q=s++;
  } else {
    /* Find the start of first block of contiguous spaces */
    for(;*s-' '||*(s+1)-' ';s++); 
    for(q=s;*s==' ';s++); /* q holds the start, s finds it's end */
    /* if this block is even length remove all, if odd, all but one */
    if( (s-q)%2 )s--; else usleep(1e5);
  }
  /* copy from s to q all the way to the end */
  for(r=0;*s;*q++=*s++){ 
    if(*s-' ')r=1; /* note if we pass a non-space */
  } 
  return r;
}

main(int c,char**v){
  initscr();curs_set(0); /* setup ncurses with invisible cursor */
  for(c=0;c<62;l[c++]=' '); /* initialize l */
  for(p=*++v;*p;){ /* load the message into the marque, skipping space */
    l[52]=*p++;
    mvprintw(23,0,"%s",l),
    refresh();
    usleep(1e5),
    S(l);
    usleep(1e5),
    S(l);
    usleep(1e5),
    S(l);
  }
  for(;usleep(1e5),S(l);mvprintw(23,0,"%s",l),refresh()); /* keeping sliding until we're done. */
  getch();
  endwin();
}

Há muito potencial para encurtar, principalmente substituindo ifpor operadores. Por exemplo - if((s-q)%2)s--;else usleep(1e5);-> s-q&1?s--:usleep(1e5);(ou s-=s-q&1||usleep(1e5);)
— ugoren 28/03

@ugoren: Sim, e eu tinha me esquecido de substituir os ' 's por equivalentes numéricos.
— dmckee --- ex-moderador gatinho

Mais alguns truques: Substitua x==32por x-32(inverte o significado, então inverta o if-else) ou por x<33(assumindo que 0..31 nunca foi usado). Inicialize com os valores que você tem ( for(curs_set(c=0);...). *(s+1)-> s[1]. Remova os aparelhos desnecessários (substituir ;por ,ajudará).
— Ugoren

2

Perl 5.13.2, 96

$_=join$;x4,$;x46,split//,pop;print substr(s/$;/ /gr,0,50)." \r"while$|=s/$;//+select'','','',.1

Roubando muito da resposta de @ Kevin Reid , especialmente o /rtruque disponível nos Perls mais recentes.

Perl, 115

Como a resposta de @ Joel Berger , isso ficaria muito mais curto se eu pudesse usar sleep 1e ser lento, ou passar -MTime::HiRes=sleepna linha de comando para ativar sleep.1. Caso contrário, a única maneira incorporada de dormir pouco select'','','',.1é a bastante longa.

$|=@_=(($")x45,map{($")x4,$_}split//,pop);for(0..$#_){print@_," \r";splice@_,($_-=45)<0?0:$_/4,1;select'','','',.1}

Perl, 128

$_=$"x9 .pop;s/./    $&/g;$.=-46;$\=" \r";while($|=/./g){print substr($_,0,50);pos=++$.<0?0:$./4;s/\G.//;select'','','',.1}print

Perl, 133

$|=@_=split//,pop;for$i(reverse-$#_..50){for(@_){print$"x($j||$i),$_;($i+=$j=($i++>0)*4)>50&&last}print"    \r";$j=select'','','',.1}

sim, eu me mordi com minha própria regra nessa! Eu não sabia que outros langs teriam um sono embutido. Oh, bem.
— Joel Berger

algumas sugestões, você pode remover o espaço após cada uma delas xe a forma de bloco mapeconomizará algumas.
— Joel Berger

1

Javascript 180 218 caracteres

Versão de produção:

function f(){i--&&(i>50?h=h.substr(1):h=h.replace(" ",i==16?"&nbsp;":""),document.body.innerHTML="<pre>"+h.substr(0,50)+"</pre>",setTimeout(f,99))}h=(new Array(50)).join(" ")+"HelloWorld".split("").join("   "),i=80,f()

Versão Ungolfed:

h=new Array(50).join(" ")+("HelloWorld".split("").join("   "));
i=80;

function f(){
        if(i--){
            if(i>50){
                h=h.substr(1);
            }else{
                h=h.replace(" ",(i==16)?"&nbsp;":"");
            }
            document.body.innerHTML="<pre>"+h.substr(0,50)+"</pre>";
            setTimeout(f,99);
        }
}
f();​

Aqui está uma demonstração do jsFiddle

Nota: se você tentar reproduzi-lo, verifique se o código está abaixo do corpo


Não posso dizer pela demo, ela "se empilha" no lado esquerdo ou simplesmente faz para a esquerda e mostra a sequência final? O Howard definitivamente funciona se você não tiver certeza.
— Joel Berger

@JoelBerger, o hello world tem 4 espaços entre cada letra; quando h é o primeiro caractere, esses espaços são removidos. Esta demo é mais lenta jsfiddle.net/fYvg7/1
— ajax333221

Isso está próximo, mas você deve remover cada espaço individualmente.
— Joel Berger

@JoelBerger Fixed
— ajax333221

Bem, eu odeio ser um problema, mas um outro problema: o seu começa com todas as letras exibidas, em vez de digitar uma a uma à direita.
— Joel Berger

1

Perl 5.13.2, 115 caracteres

$_=$"x9 .pop=~y/ /\0/r;s/./    $&/g;print(y/\0/ /r=~/(.{50})/,"\r"),select$.,$.,$.,.02while$|=s/ (\S)/$1 /g;print$/
  • Aviso de limpeza.
  • Pode ser espremido um pouco, reduzindo o espaço entre os caracteres ou o espaço em branco inicial.
  • Requer Perl 5.13.2 ou mais recente devido ao uso de /r.
  • A substituição para NUL para preservar espaços é inequívoca, pois o POSIX argv não é limpo por NUL. No entanto, a substituição do loop transformará qualquer outro espaço em branco em nada (eventualmente).

Créditos:


Eu amo a rbandeira, melhor além da língua desdestate
— Joel Berger

1

festança 234

w=$1
p(){
i=$1
s=$2
p=$((50+s*3-i))
((p<s+1)) && p=$((s+1));
((p<50)) && echo -en "[20;"${p}H$3"  ";
}
clear
for i in {0..99}
do
for s in $(seq 0 ${#w})
do
p $i $s ${w:s:1} 
done
sleep .1
echo -en "[20;1H  "
done
echo -en "\b\b$w\n"

Uso:

./marquee.sh "Hello, fine marquee world"

ungolfed:

#!/bin/bash
w=$1
p(){
    #si String index
    it=$1
    #it=iteration
    si=$2
    pos=$((50+(si*3)-it))
    ((pos<si+1 )) && pos=$((si+1));
    ((pos<50)) && echo -en "[20;"${pos}H$3"  ";
}
clear
for it in {0..99}
do
    for si in $(seq 0 ${#w})
    do
        p $it $si ${w:si:1} 
    done
    sleep .1
    echo -en "[20;1H   "
done
echo -en "[22;1H"

1

R, 319 caracteres

Seguindo a filosofia do exemplo do @Blazer (d é o atraso em segundos):

f=function(x,n=50,d=0.2){
    s=strsplit(x,"")[[1]];i=1;l=length
    while (i<(n+l(s)-1)){
        if(i<=l(s))cat(rep(" ", n-i),s[1:i])
        else if((i<=n)&&(i>l(s)))cat(rep(" ", n-i),s[1:l(s)])
        else cat(paste(s[1:(i-n+1)],collapse=""),s[(i-n+2):l(s)])
        Sys.sleep(d);system("clear");i=i+1
    }
    cat(paste(s[1:l(s)],collapse=""))
}

Uso:

f("Hello World",n=20,d=0.2)

1

Perl : 144 133

$|=@s=(($")x50,map{$_,($")x4}@i=split//,pop);{$n=0;$s[$n]ne$_?last:$n++for@i;splice@s,$n,1;print"\r",@s[0..50];sleep.1;$n!=@i&&redo}

Para obter o sono <1s, você precisa executar o seguinte:

perl -MTime::HiRes=sleep scriptname 'string to print'

Como não vou me declarar vencedor, não discutirei sobre o que conta lá ou não (mas realmente não posso fazer com que Ruby ganhe isso ;-))


4 mais e ele se encaixa em um tweet: D
— ajax333221 31/03

4 caracteres aqui: s/' '/$"/ges/shift/pop/
— ephemient 29/03

Sim, eu os incluí, além de remover a pushdeclaração. Eu ainda não tinha postado ainda.
— Joel Berger

0

Q, 145

Não atende exatamente aos requisitos porque a linha final remove todos os espaços que estavam na cadeia de entrada original.

{c:2_'((!)(#)a)_'a:((l:3*(#)x)#" "),\(1_(,/)b,'x,'b:" ");{(-1 x;);system"sleep ",($)y}'[-1_c,(l-1)$d(!:)[d]except\(&)(^)d:((!)(#)q)!q:last c;y];}

São necessários dois argumentos: string de entrada e velocidade de rolagem

q){c:2_'((!)(#)a)_'a:((l:3*(#)x)#" "),\(1_(,/)b,'x,'b:" ");{(-1 x;);system"sleep ",($)y}'[-1_c,(l-1)$d(!:)[d]except\(&)(^)d:((!)(#)q)!q:last c;y];}["hello";0.05]
             h
            h
           h
          h  e
         h  e
        h  e
       h  e  l
      h  e  l
     h  e  l
    h  e  l  l
   h  e  l  l
  h  e  l  l
 h  e  l  l  o
h  e  l  l  o
h e  l  l  o
he  l  l  o
he l  l  o
hel  l  o
hel l  o
hell  o
hell o
hello

infelizmente esse é um ponto importante. Eu sei que os scripts Perl podem ficar muito pequenos sem ele.
— Joel Berger

0

PowerShell, 135

Não sou muito golfista e provavelmente uma abordagem horrível, mas estou doente e não consigo pensar ...

for($x="`r"+' '*50;$y-ne$x){$y=$x
write-host($x=$x-replace' ([^ ])','$1 ')-n
if(!($t++%5)){$x=$x-replace'.$',"$args"[$i++]}sleep -m 99}

0

J (116)

s(echo@((50#LF)&,)@([[i.@]&2e7)@(50&{.)@;@:(([,~#&' '@])&.>))"1([-=&0@/:@\:@:~:&0)^:(i.>:+/k)k=.50,3#~<:#s=.>2{ARGV

Toma a string de entrada na linha de comando, ou seja jconsole marquee.ijs 'Hello, world!'

Se não precisar limpar a tela, ou seja, faça a seguinte saída:

H  e  l  l  o
H e  l  l  o
He  l  l  o
He l  l  o
...

é permitido, seriam 12 caracteres mais curtos.

Explicação:

  • s.=>2{ARGV: obtém a string na linha de comando
  • k.=50,3#~<:#s: a quantidade inicial de espaço em branco adicionada antes de cada caractere, 50 antes do primeiro e 3 antes de todos os outros. (fornece uma matriz, '50 3 3 3 ... ')
  • ([-=&0@/:@\:@~:&0): dado um array, diminui o primeiro item diferente de zero no array
  • ^:(i.>:+/k): esta função aplicada N vezes, em que N é 0 até a soma da quantidade de espaço em branco adicionado. (dá uma matriz: 50 3 3 3; 49 3 3 3; 48 3 3 3; ... 0 0 0 1; 0 0 0 0).
  • "1: execute a seguinte função em cada linha da matriz
  • ;@:(([,~#&' '@])@.>): adicione a quantidade especificada de espaços antes de cada caractere na sequência
  • (50&{.): pega os primeiros 50 caracteres da sequência
  • ([[i.@]&2e7): uma função que gera a lista de 0 a 2 * 10 ^ 7 e a joga fora. Isso leva cerca de um terço de segundo na minha máquina, isso causa o atraso.
  • ((50#LF)&,): adicione 50 novas linhas antes da sequência, para limpar a tela
  • echo: gera a string
  • s (...): fornece a string como argumento esquerdo para a função

0

APL (70)

{⎕SM∘←1,⍨1,⍨,/D{⍺,⍨⍵⍴⍕⍬}¨P←⍵-{⍵×~×⍺}\×⍵⊣⎕DL÷8⋄0∨.≠P:∇P}1↓⎕SD,1↓3⍴⍨⍴D←⍞

Pega a entrada do teclado, a saída está na ⎕SMjanela (que seria o terminal se você tivesse um APL baseado em texto, eu acho). O tamanho da janela é detectado automaticamente, se você realmente quiser 50, mude 1↓⎕SDpara 50.

Explicação:

  • 1↓⎕SD,1↓3⍴⍨⍴D←⍞: leia a string e armazene D. Gere um vetor descrevendo quanto espaço em branco será adicionado antes de cada caractere, que é a largura da tela antes do primeiro caractere ( 1↓⎕SD) e 3 antes dos outros ( 1↓3⍴⍨⍴D).

  • ⎕DL÷8: aguarde 1/8 de segundo

  • P←⍵-{⍵×~×⍺}\×⍵: no vetor no argumento certo, subtraia 1 do item diferente de zero à esquerda e armazene o novo vetor em P.
  • ,/D{⍺,⍨⍵⍴⍕⍬}¨P: para cada caractere em D, prefixe a quantidade de espaço em branco fornecida em P.
  • ⎕SM∘←1,⍨1,⍨: exibido na tela, na coluna mais à esquerda da linha superior
  • 0∨.≠P:∇P: se houver um elemento diferente de zero em P, repita com P.

0

PowerShell , 129 bytes

for($x=' '*52+(($args|% t*y)-join' '*4);$x-match'  '){write-host "`r$(-join($x=$x-replace'(?<!  .*)  ')[0..50])  "-n
sleep -m 99}

Experimente online!

Este script não remove espaços dos argumentos em contraste com o script de Joey .

TIOnão exibe a saída corretamente. Com o console do Powershell, você obtém a marca de rolagem.


0

05AB1E , 42 bytes

ð¶:S3úJ46ú[D50£¶ð:D?IQ#ðõ.;“…¢('\r')“.eт.W

Experimente online (sem dormir). NOTA: Não tenho o 05AB1E instalado localmente, por isso não tenho 100% de certeza se o \rtruque funciona (em teoria, ele deve funcionar). No TIO, eles \rsão interpretados como novas linhas. Além disso, o TIO usa a versão herdada, porque .eestá desativado na nova versão do TIO (o programa é o mesmo na versão herdada e na nova versão do 05AB1E).

Explicação:

ð¶:            # Replace all spaces in the (implicit) input-string with newlines
   S           # Split the string to a list of characters
    3ú         # Pad each character with 3 leading spaces
      J        # Join the characters together again
       46ú     # And pad the entire string with an additional 46 leading spaces
[              # Now start an infinite loop:
 D             #  Duplicate the string
  50£          #  And leave only the first 50 characters of this copy as substring
     ¶ð:       #  Replace the newlines back to spaces
        D?     #  Duplicate the string, and print it without trailing newline
 IQ            #  If the current string is equal to the input:
   #           #   Stop the infinite loop
 ðõ.;          #  Replace the first space with an empty string to remove it
 “…¢('\r')“    #  Push dictionary string "print('\r')"
           .e  #  Evaluate it as Python code
 т.W           #  Sleep for 100 ms

Veja esta dica 05AB1E meu (seção Como usar o dicionário? ) Para entender por que “…¢('\r')“é "print('\r')".


0

Python, 139 bytes

import os;P='\n'
def f(x,w):
 v=k=P*w+P.join(x);o=str.replace
 while v!=x:os.system('sleep 1;clear');k=o(k,P,'',1);v=o(k,P,' ');print v[:w]

Tem que ligar f('Hello World', 50)para começar.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.