Прокрутка Marquee


13

Після мого вступу в Замкнутий Привіт Світ я подумав, що може бути цікавим поділитися базовим кодом. Але чому просто показати код, давайте зробити його і для гольфу!

Виклик

Напишіть сценарій, який прокручує рядок через термінал, справа наліво, розташовуючись з лівого боку.

Вхідні дані

Приймає рядок як аргумент.

Результат

Друкує прокручувальну схему до STDOUT. Максимальна ширина ~ 50 символів. Починається з 0 або 1 показ символів. Деякий пробіл між літерами під час прокрутки. Зупиняється при влаштуванні (не маючи зайвого місця між символами слова). Повільне прокручування, але не надто повільне (<1 секунди за ітерацію).

Приклад

Запуск сценарію з arg 'Hello World'

                                                   H

пізніше

                H    e    l    l    o         W    o

пізніше

H    e    l    l    o          W    o    r    l    d

пізніше

Hell    o         W    o    r    l    d

нарешті

Hello World

Для прикладу роботи спробуйте мій код із виклику "Hello World". Врешті-решт я пошлю свою. В даний час це 202 символи в Perl. Тепер, коли є деякі конкуренти, я розмістив свої відповіді.

Переможець

Я не хочу, щоб обмеження були абсолютними, тому я залишив їх трохи розпливчастими. Виграє найкоротший сценарій, який відповідає духу мого оригіналу.

Примітки

Ця гра передбачає xtermоточення. Якщо інше середовище виявиться корисним, порівнюватимуться лише подібні середовища, і для кожного може бути оголошено окремий переможець.

Додаток (25 квітня 2012 р.)

Щоб вирішити деякі проблеми з початком, я приймаю рішення. Кількість персонажів повинна містити код, необхідний для:

  1. Flush STDOUT (дивлячись на тебе Ruby)
  2. Реалізація sleepіз затримкою в часі <1s (дивлячись на вас Perl)

Це може бути зроблено, коли командний рядок переходить до інтерпретатора, але ці символи рахуються в загальній кількості (без навколишнього пробілу).


Я трохи стурбований клемне поведінку для такого роду речі ... xterm, vt102, ...?
dmckee --- колишнє кошеня модератора

Я припускаю xterm, але не думаю, що це має велике значення. Можливо, я не розумію вашої турботи?
Джоель Бергер

Ці трюки зазвичай виробляються, спираючись на те, як різні термінали обробляють деякі символи, що не друкуються, і термінали відрізнялися тим, що вони могли зробити, і які послідовності викликали ефекти. Для відтворюваності може бути добре мати визначене кінцеве середовище.
dmckee --- кошеня колишнього модератора

1
Це допоможе вам правильно, якщо хтось опублікує дійсно коротку відповідь, яка залежить від неясного терміналу, для якого у вас немає емулятора, але гаразд.
dmckee --- кошеня колишнього модератора

ок, я думаю, це зараз у мене є. Дякую за думки :-)
Джоель Бергер

Відповіді:


5

пітон 2 - 146 символів

edit: зробив це функцією замість введення через stdin. перший аргумент - рядок, а другий аргумент - довжина, яку ви хочете. тож виклик був би f('Hello World', 50). Я також зробив це набагато гладше; коли кожен персонаж "приземлився", була незручна пауза

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)

старий, 158 символів:

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)

Використовуючи bash (принаймні, в недавній установці MacOSX і CentOS), команда оболонки, яка використовується для очищення екрана терміналу, повинна бути "clear", а не "cls".
Паоло

'cls' для Windows, 'clear' для OSX / Linux, будується, я думаю
Blazer

Порада, як запускати програму для тих, хто не займається python щодня, буде корисним. Запустіть пітон. вставити код, дзвінок f("Hello World, 40)працював для мене.
користувач невідомий

@user Я гм. Я поклав виклик туди?
Блейзер

4

Рубі, 93 91 89 чол

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

Текст, який відображається, повинен бути вказаний як аргумент командного рядка, наприклад

ruby marquee.rb "Hello World"

для наведеного вище прикладу. На жаль, я не можу показати анімацію тут, тому вам доведеться спробувати код самостійно.

Попередня версія:

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

Вражаючі розміри. Хоча це не дуже гладко, це те, що я (я зараз на досить малопотужній машині) чи так працює код?
Джоель Бергер

Зрозумівши це, я повинен був налаштувати STDOUT.sync=true;так, щоб він автоматично розмивався. Перлівський еквівалент є $|++. Thats додаткові 17 chars, але все ще значно нижче мого. Ну, я не можу Рубі бити Перла! Зробимо хафту. Хороший.
Джоель Бергер

Якщо я зателефоную, ruby1.8 "Hello World"я отримаю, не зовсім здивований, помилку про те, що:ruby1.8: No such file or directory -- Hello World (LoadError)
користувач невідомий

@userunknown, можливо, ви також повинні там покласти шлях до вихідного файлу: ruby foo.rb args;-)
Patrick Oscity

@padde: Так, я повинен. На жаль, Говард редагував своє повідомлення, не повідомляючи мене про свою зміну. Погляньте на історію, щоб зрозуміти моє запитання.
користувачеві невідомо

3

C, 94 83 80 173 символів

EDIT: Додано багато коду, реалізовано всі потрібні функції зараз. Константу 1e8можна налаштувати для управління швидкістю. На моїй машині це досить швидко, як є.
Тут напевно можна зберегти деяких персонажів. lможе бути статичним (зберігає ініціалізацію), cможе стати вказівником (заміною 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););
}

Стара версія (80 символів), з частковою функціональністю:
збережено пару символів заміною char**tна int*t. Відмінно працює в 32-розрядному ( int**tпідтримує 64-бітну).

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 символів

Поважає стандарт у високій мірі. Використовує ncurses, тому він повинен бути значною мірою незалежним від терміналу. Виникає незначне заїкання, коли текст потрапляє в бік через деяку хитрість, яку відіграє для збереження призначеного пробілу в рядку.

Рядок, який слід використовувати, повинен бути переданий як перший аргумент у командному рядку (і його слід уникнути, якщо він містить пробіли, тим більше, якщо він містить !як мій тестовий рядок ( 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();}

У більш читаному та коментованому вигляді:

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

Існує великий потенціал для скорочення, особливо заміною ifоператорів. Наприклад - if((s-q)%2)s--;else usleep(1e5);-> s-q&1?s--:usleep(1e5);(або s-=s-q&1||usleep(1e5);)
ugoren

@ugoren: Так, і я забув замінити ' 's на числові еквіваленти.
dmckee --- кошеня колишнього модератора

Ще кілька хитрощів: Замініть x==32на x-32(повертає значення, тому переверніть значення if-else), або на x<33(якщо 0..31 ніколи не використовується). Ініціалізуйте зі значеннями, які у вас є ( for(curs_set(c=0);...). *(s+1)-> s[1]. Видаліть непотрібні дужки (замінюють ;з ,Допоможуть).
угорен

2

Perl 5.13.2, 96

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

Вкрасти багато з відповіді Кевіна Рейда , особливо /rхитрість, доступна в нових Perls.

Перл, 115

Як і у відповіді Джоела Бергера , це стало б набагато коротшим, якби я міг використовувати sleep 1і бути повільним, або перейти -MTime::HiRes=sleepна командний рядок, щоб увімкнути sleep.1. Інакше єдиний вбудований спосіб короткого сну - select'','','',.1це досить довгий.

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

Перл, 128

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

Перл, 133

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

так, я кусаю себе своїм правилом щодо цього! Я не розумів, що в інших мовців буде вбудований сон. О, добре.
Джоель Бергер

кілька пропозицій, ви можете видалити пробіл після кожного, xі блок-формат mapзбереже кілька.
Джоель Бергер

1

JavaScript 180 218 символів

Версія виробництва:

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()

Версія без заготівлі:

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();​

Ось демонстрація jsFiddle

Примітка. Якщо ви намагаєтесь відтворити його, переконайтеся, що код знаходиться нижче корпусу


Я не можу сказати з демонстрації, чи він "складений" з лівого боку, чи просто зробити його ліворуч, а потім показати остаточний рядок? Говард безумовно працює, якщо ви не впевнені.
Джоель Бергер

@JoelBerger у привітному світі є 4 пробіли між кожною буквою, коли h - перший символ, ці пробіли видаляються. Ця демонстрація повільніше jsfiddle.net/fYvg7/1
ajax333221

Це близько, але ви повинні видалити кожен простір окремо.
Джоель Бергер

@JoelBerger Виправлено
ajax333221

Ну, я ненавиджу бути нагі, але ще одна проблема: ваша починається з усіх букв, а не введення один за одним справа.
Джоель Бергер

1

Perl 5.13.2, 115 символів

$_=$"x9 .pop=~y/ /\0/r;s/./    $&/g;print(y/\0/ /r=~/(.{50})/,"\r"),select$.,$.,$.,.02while$|=s/ (\S)/$1 /g;print$/
  • Попередження-чисте.
  • Можна трохи стиснути, зменшивши пробіл між символами або початковим пробілом.
  • Потрібен Perl 5.13.2 або новіший через використання /r.
  • Заміна NUL для збереження пробілів є однозначною, оскільки POSIX argv не є NUL-чистим. Однак заміна циклу перетворить будь-який інший пробіл у ніщо (зрештою).

Кредити:

  • $"як джерело, " "взяте з відповіді ефедія , зменшення на 1 символ.

Я люблю rпрапор, найкраще доповнення до мови з тих пірstate
Джоел Бергер

1

баш 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"

Використання:

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

неозорений:

#!/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 символів

Дотримуючись філософії прикладу @Blazer (d - затримка в сек):

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=""))
}

Використання:

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}

Для того щоб заснути <1, хоча вам потрібно запустити як:

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

Оскільки я не оголошу себе переможцем, я не буду сперечатися над тим, що там рахується чи ні (але я справді не можу, щоб Рубі перемогла це ;-))


Ще 4, і це підходить до твіту: D
ajax333221

4 символи тут: s/' '/$"/gіs/shift/pop/
ефемія

так, я включив їх разом із видаленням pushзаяви. Я просто ще не опублікував його.
Джоель Бергер

0

Q, 145

Не відповідає точно вимогам, оскільки підсумковий рядок видаляє всі пробіли, що були у вихідному рядку введення.

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

Це займає два аргументи, рядок введення та швидкість прокрутки

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

на жаль, це важливий момент. Я знаю, що без цього сценарії Perl могли бути дуже маленькими.
Джоель Бергер

0

PowerShell, 135

Не дуже гольф і, мабуть, жахливий підхід, але я хворий і не можу по-справжньому думати ...

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

Бере вхідний рядок у командному рядку, тобто jconsole marquee.ijs 'Hello, world!'

Якщо не потрібно очищати екран, тобто виводити так:

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

дозволено, це було б на 12 символів коротше.

Пояснення:

  • s.=>2{ARGV: отримати рядок з командного рядка
  • k.=50,3#~<:#s: початкова кількість пробілів, доданих перед кожним символом, 50 перед першим та 3 перед усіма іншими. (дає масив, '50 3 3 3 ... ')
  • ([-=&0@/:@\:@~:&0): заданий масив, декрементує перший ненульовий елемент у масиві
  • ^:(i.>:+/k): ця функція застосовується N разів, де N дорівнює сумі кількості доданого пробілу. (Дає матрицю: 50 3 3 3; 49 3 3 3; 48 3 3 3; ... 0 0 0 1; 0 0 0 0).
  • "1: запустіть наступну функцію в кожному рядку матриці
  • ;@:(([,~#&' '@])@.>): додайте задану кількість пробілів перед кожним символом у рядку
  • (50&{.): візьміть перші 50 символів рядка
  • ([[i.@]&2e7): функція, яка генерує список від 0 до 2 * 10 ^ 7, а потім викидає його. Це займає приблизно третину секунди на моїй машині, це спричиняє затримку.
  • ((50#LF)&,): додайте 50 рядків перед рядком, щоб очистити екран
  • echo: вивести рядок
  • s (...): дайте рядок як лівий аргумент функції

0

APL (70)

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

Вводиться з клавіатури, вихід - у ⎕SMвікні (який би термінал, якби у вас був текстовий APL, я думаю). Розмір вікна визначається автоматично, якщо ви дійсно хочете, щоб це було 50, змініть 1↓⎕SDна 50.

Пояснення:

  • 1↓⎕SD,1↓3⍴⍨⍴D←⍞: читати рядок і зберігати в D. Створіть вектор, що описує, скільки пробілів потрібно додати перед кожним символом, яка ширина екрана перед першим символом ( 1↓⎕SD) та 3 перед іншими ( 1↓3⍴⍨⍴D).

  • ⎕DL÷8: зачекайте 1/8 секунди

  • P←⍵-{⍵×~×⍺}\×⍵: у векторі правого аргументу відніміть 1 від крайнього лівого ненульового елемента та збережіть новий вектор у P.
  • ,/D{⍺,⍨⍵⍴⍕⍬}¨P: для кожного символу в D, префікс кількість пробілів, задана в P.
  • ⎕SM∘←1,⍨1,⍨: відображення на екрані в крайньому лівому стовпчику верхнього ряду
  • 0∨.≠P:∇P: якщо в P є ненульовий елемент, повторіть із P.

0

PowerShell , 129 байт

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

Спробуйте в Інтернеті!

Цей скрипт не вилучає пробілів з аргументів на відміну від сценарію Джої .

TIOне відображає коректно вихід. Використовуючи консоль Powershell, ви отримуєте прокрутки.


0

05AB1E , 42 байти

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

Спробуйте в Інтернеті (без сну). ПРИМІТКА. У мене не встановлено 05AB1E локально, тому я не впевнений на 100%, чи \rпрацює цей трюк (проте теоретично він повинен працювати). У TIO \rнатомість інтерпретуються як нові рядки. Крім того, TIO використовує застарілу версію, оскільки .eвін відключений у новій версії TIO (програма однакова і в застарілій, і в новій версії 05AB1E, однак).

Пояснення:

ð¶:            # 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

Дивіться цей 05AB1E наконечник шахти (розділ Як користуватися словником? ) , Щоб зрозуміти , чому “…¢('\r')“це "print('\r')".


0

Пітон, 139 байт

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]

Доводиться телефонувати, f('Hello World', 50)щоб почати.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.