Чувствительное ко времени эхо


39

Задний план

echoПрограмма настолько аккуратно. Вы можете сказать что-нибудь, и это повторяет ваши слова идеально, каждый раз! Как это круто! Неутешительно, это повторяет ввод все сразу, независимо от вашей скорости печати, которая не очень реалистична. Мы должны это исправить.

Задание

Ваша программа должна получать свои данные из STDIN или ближайшего аналога. Он должен читать строки от пользователя одну за другой, возможно, отображая какое-то приглашение, пока они не введут пустую строку. После этого он выводит строки в STDOUT или ближайший эквивалент в том порядке, в котором они были заданы. Последняя (пустая) строка не печатается, а последняя напечатанная строка не нуждается в конце новой строки.

Кроме того, программа должна сохранять временные интервалы между каждой строкой: если пользователю потребовалось xнесколько секунд, чтобы ввести строку, программе потребуется xнесколько секунд, чтобы ее распечатать. Это относится и к первой и последней строкам; пустая строка не печатается, но программа все равно ждет, прежде чем завершить работу.

пример

Вот пример сеанса с программой. Все действия, которые не производят текст, описаны в скобках, и (необязательно) приглашение отображается как >.

[begin program]
> fhtagn[enter; 1.48s passed since starting program]
> yum yum[enter; 3.33s passed since previous enter]
> so cool![enter; 2.24s passed since previous enter]
> [enter; 0.23s passed since previous enter]
[wait 1.48s]fhtagn
[wait 3.33s]yum yum
[wait 2.24s]so cool!
[wait 0.23s, then end program]

Без действий сессия выглядит так:

> fhtagn
> yum yum
> so cool!
> 
fhtagn
yum yum
so cool!

Правила и оценки

Время ожидания должно быть с точностью до 0,01 секунды (на практике, если обычный человек не может определить разницу, у вас все в порядке). Побеждает меньшее количество байтов, и стандартные лазейки запрещены. Если ваш язык имеет встроенную функцию именно для этой задачи, вы не можете ее использовать.


9
Следующий шаг: игра в гольф, играющая в основную ритмическую игру: P
Sp3000

Можем ли мы игнорировать время, которое программа тратит на вывод символов? Я имею в виду, если я могу измерить, что мой язык занимает 0,1 секунды для вывода символа, я должен принять это во внимание? Полное раскрытие, я планирую использовать> <> время тиков переводчиков для реализации задержки; в этом случае я могу иметь цикл, истекающий время ввода, а затем игнорировать время, истекшее моим циклом отображения?
Аарон

1
@AaronGOUZIT Я позволю это, если вы последовательны: либо интервалы времени между моментами, когда ваша программа начинает печатать строку, все взяты у пользователя, ИЛИ время ожидания между завершением печати строки и началом печати Следующие все взяты от пользователя.
Згарб

1
@TessellatingHeckler Последний; см. пример сеанса.
Згарб

1
@KritixiLithos Я использовал только правую руку yum yum, что было довольно громоздко.
Згарб

Ответы:


16

CJam, 45 41 39 36 34 байта

{eslN1$}g;es](es-fm3/{){_es>}g;o}/

Конечно, в онлайн-интерпретаторе это не имеет смысла, но работает в интерпретаторе Java.

Это не отображает подсказку.

объяснение

{        e# Do while... (popping the condition from the stack)
  es     e#   Get the current timestamp.
  l      e#   Wait for a line to be entered and read it.
  N      e#   Push a linefeed.
  1$     e#   Copy the line we read - this terminates if the line is empty, because
         e#   empty strings/arrays are falsy.
}g
;        e# Discard the last linefeed (the one after the empty input).
es       e# Push the current timestamp (corresponding to the last, empty, input).
]        e# Wrap everything in an array. This is now a flat array containing:
         e#   - The initial timestamp.
         e#   - Three elements for each line: the line, a linefeed, the timestamp.
         e#   - Two elements for the last line: the empty string and the timestamp.
(        e# Pull off the initial time.
es-      e# Subtract the current time, which gives (minus) the difference between
         e# when a line was entered and when it should be printed back.
fm       e# This maps "minus that value" onto each element in the array. Now the lines
         e# and linefeeds are strings (arrays) - so minus is set difference, but they
         e# only contain characters, not any integers (like the difference value), so
         e# none of the strings will be affected.
         e# The timestamps on the other hand will be incremented by the time difference
         e# between reading and printing, giving the time at which each line should be
         e# printed back.
3/       e# Split the array into chunks of 3 (where the remaining two elements are
         e# just grouped as a pair).
{        e# For each of those chunks...
  )      e#   Pull off the timestamp.
  {      e#   Do while... (popping the condition from the stack)
    _    e#     Duplicate the target time.
    es>  e#     Check if it's still greater than the current time.
  }g
  ;o     e# Discard the target time and print the rest of the current chunk, which will
         e# automatically be flattened/concatenated into a single string.
}/

9

JavaScript, 119 112 байт

k=(d=Date.now)(i=j=[]);do{i[++j]=[prompt(),d()-k]}while(i[j][0]);i.map(a=>setTimeout(b=>console.log(a[0]),a[1]))

Надеюсь найти еще пару байтов для вырезания.


1
Вы также можете сэкономить пару байтов с помощью j=i=[]( ++все еще будет работать!), Вам whileне нужно, так !=''как это ложно! Так разочарован, я пропустил map! +1
Дом Гастингс

1
Хорошая заметка о !=''. Был обеспокоен, если вход был 0, но, кажется, справиться с этим хорошо. Я уже заметил []возможность увеличения, но я был глуп и пытался делать j++с этим. Делать ++jработает, так []++как, по-видимому, 0 XD Спасибо!
Mwr247

1
Отметьте этот день, когда я узнал, что do...whileв JS были петли
Конор О'Брайен

6

JavaScript, 120 байт

Нет шансов приблизиться к CJam с таким подходом, но простой сценарий.

a=[];t=+new Date;while(s=prompt()){a.push({s:s,t:+new Date})}while(v=a.pop()){setTimeout(`console.log('${v.s}')`,v.t-t)}

1
Кажется, мы оба пошли на JS в одно и то же время, ха-ха, хотя ты получил немного раньше моего. Все-таки разные подходы.
Mwr247

@ Mwr247 Действительно, ваш более элегантный, хотя!
Дом Гастингс

6

Pyth, 68 байт

M&p+Gb$__import__('time').sleep(H)$J].dZWeaYwaJ.dZ)aJ.dZp&gVPY-VtJJk

Потеряно много байтов на вызове sleep, так как Pyth не имеет sleepфункции.


3
Может быть, вы должны предложить это как дополнение к Pyth.
mbomb007

Я полагаю, у вас есть ошибка в ожидании. Попробуйте запустить программу, подождать, затем набрать что-нибудь и быстро нажать клавишу ввода. Он сразу напечатает первую строку, затем подождет некоторое время, прежде чем завершится.
FryAmTheEggman

6

Руби, 74

t,*a=Time.now
a<<[$_,t-t=Time.now]while$/<gets
a.map{|l,i|sleep -i;puts l}

Трюки: *aв первой строке инициализируется пустой массив. Я мог бы использовать $*вместо этого, но это слегка схематично, так как он заполнен некоторыми вызовами и только экономит мне байт. $/является новой $_строкой и является последней строкой, полученной с помощью gets.

Редактировать: сон в конце стоит еще 20 байтов, вероятно, способ проиграть

t,*a=Time.now
a<<[$_,t-t=Time.now]while$/<gets
t-=Time.now
a.map{|l,i|sleep -i;puts l}
sleep -t

Я думаю, что вам нужно спать на последней строке, в зависимости от того, сколько времени потребовалось пользователю, чтобы предоставить пустую строку.
Конрад Боровски

Для того, чтобы спать в конце (решение 2), вы вызываете Time.nowдостаточно раз, чтобы использовать def n;Time.now;end, сохраняя целые 2 байта
Value Ink

6

Питон 3, 124

Работает только на платформах Windows

from time import*
s=[(1,clock())]
while s[-1][0]:s+=[(input(),clock()-s[-1][1])]
[sleep(y)or x and print(x)for x,y in s[1:]]

Хранение ввода и времени в отдельных списках стоило мне еще 3 байта . Вероятно, не лучший подход.

129-байтовая версия для Unix с благодарностью Mego :

from time import*
t=time
s=[(1,t())]
while s[-1][0]:s+=[(input(),t(),t()-s[-1][1])]
[sleep(y)or x and print(x)for x,z,y in s[1:]]

Вы не можете использовать time()вместо того, clock()чтобы сохранить 2 байта?
kirbyfan64sos

4

SWI-Пролог, 185 байт

a:-b([],S),reverse(S,T),c(T),!.
b(R,S):-get_time(X),read_string(user_input,"\n","",_,A),get_time(Y),Z is Y-X,(A="",S=[A:Z|R];b([A:Z|R],S)).
c([A:Z|T]):-sleep(Z),T=[];(write(A),nl,c(T)).

Здесь, вероятно, есть много для игры в гольф, но пока это подойдет ...


4

PowerShell, 261 190 121 95 байт

$(do{Measure-Command{$l=read-host};$l}while($l))|%{($_,(sleep -m($_.Ticks/1e4)))[($b=!$b+!$_)]}

Реквизиты TessellatngHeckler и Tomkandy для помощи в гольф и вдохновения

Это очень похоже на концепцию 121-байтовой версии ниже, мы просто динамически создаем и строим список объектов, вместо того, чтобы проходить через цикл while для сохранения их в явном массиве $a. В обоих случаях этот список объектов передается по конвейеру в один и тот же цикл foreach |%{...}. Индексирование в селектор массива результата на ($b=!$b+!$_)этот раз сформулировано для исключения следующих if($_){$_}итераций, что позволяет сэкономить еще несколько байтов.


Предыдущий, 121 байт

$l,$a=1,@();while($l){$t=Measure-Command{$l=read-host};$a+=$t,$l}$a|%{($(if($_){$_}),(sleep -m($_.Ticks/1e4)))[($b=!$b)]}

Расширено и объяснено:

$l,$a=1,@()                        # Set variable $l and create array $a
while($l){                         # So long as we don't have a blank line
  $t=Measure-Command{$l=read-host} # Read the input and measure time to input
  $a+=$t,$l                        # Add those values into the array
}
$a|%{                              # For each item in $a, do
  ($(if($_){$_}),(sleep -m($_.Ticks/1e4)))[($b=!$b)]
  # Magic happens here ... first, we set $b to the NOT of it's uninitialized
  # value, so $b is initially set to truthy
  # This value in [...] selects which of the two elements ( , ) get selected
  # Truthy to start means the second command, sleep, gets chosen first, and
  # then it alternates every next item, so it sleeps, then prints, then
  # sleeps, then prints, etc., until we run out of $a
}

Предыдущий, 190 байт

function f {param($m)sleep -m $a[$m].totalmilliseconds}$a=1,1;while($a[-1]-ne""){$a+=Measure-Command{$b=read-host};$a+=$b}if(!($a[3])){f 2;exit}$i=2;while($i-lt$a.length){f($i++);$a[($i++)]}

function f {                        # Define a new function
  param($m)                         # with $m as input
  sleep -m $a[$m].totalmilliseconds # sleep for $a[$m] milliseconds
}
$a=1,1                              # Create new array with two elements
while($a[-1]-ne""){                 # While the last element isn't empty
  $a+=Measure-Command{$b=read-host} # Read into $b and measure how long that took,
                                    # and add the time into $a
  $a+=$b                            # Then add the input into $a
}
if(!($a[3])){                       # If the third element is empty, the user entered
                                    # a blank as the only input, so...
  f 2                               # sleep for $a[2] ms (how long it took them to hit enter)...
  exit                              # and exit the script
}                                   # Else ...
$i=2                                # Set a counter variable
while($i-lt$a.length){              # While we haven't reached the end of $a
  f($i++)                           # Sleep
  $a[($i++)]                        # Write the output
}

Предыдущий, 261 байт

$a=$d=@();$d+=,@(date);$x=Read-Host
while($x){$a+=,@($x);$d+=,@(date);$x=Read-Host}
if($x){0..($a.Length-1)|%{sleep -m((($d[$_+1]).ticks-($d[$_]).ticks)/1e4);$a[$_]};sleep -m((($d[-1]).ticks-($d[-2]).ticks)/1e4)}
else{sleep -m(((date).Ticks-($d[0]).Ticks)/1e4)}

Святое многословие, Бэтмен! Давайте разберемся с этим:

$a=$d=@()                  # Create two empty arrays
$d+=,@(date)               # Add the current time into $d
$x=Read-Host               # Read the first line
while($x){                 # So long as it's not empty
  $a+=,@($x)               # Add it into our output array
  $d+=,@(date)             # Add the current time into $d
  $x=Read-Host             # Get the next line
}
if($a){                    # So long as $a exists (i.e., the first input wasn't blank)
  0..($a.Length-1)|%{      # For-loop over the length
                           # Sleep for how long it took to do input
    sleep -m((($d[$_+1]).ticks-($d[$_]).ticks)/1e4)
    $a[$_]                 # Print out the input
  }
                           # Sleep the length it took for the final blank
  sleep -m((($d[-1]).ticks-($d[-2]).ticks)/1e4)
}
else{
                           # If we're here, the initial input was blank, so just sleep
  sleep -m(((date).Ticks-($d[0]).Ticks)/1e4)
}

144$a=1,1;while($a[-1]-ne""){$a+=Measure-Command{$b=read-host};$a+=$b};$i=2;while($i-lt$a.length){sleep -m $a[($i++)].totalmilliseconds;$a[($i++)]}
Томканди

@tomkandy Спасибо! Обновлено с улучшениями.
AdmBorkBork

@ TessellatingHeckler Отлично! Я боролся со способом эффективного управления чередованием, и индексация в массив, подобный этому, является очевидным выбором, когда я его вижу. Кстати, я добавил еще один байт, удалив @из этого массива, так как он не нужен в этом контексте, поэтому до 121 .
AdmBorkBork

@TimmyD вчера я пытался поместить ($ t, $ l) пар в $ a для создания вложенного массива. Я не мог заставить это работать, но сегодня я мог, и это немного помогает, потому что нет необходимости переключаться, просто прочитайте каждую пару и используйте их. Тогда я понял - у нас есть очень хороший конвейер, который может ставить в очередь вещи, зачем вообще хранить массив? $($l=1;while($l){Measure-Command{$l=read-host};$l})|%{($_,(sleep -m($_.Ticks/1e4)))[($b=!$b+!$_)]}- и с переключением на тумблер, так что когда строка пуста, она не переключается, а вместо этого спит - 98
TessellatingHeckler

(Сделайте это do{...}while($l)петлей и бросьте, $l=1;чтобы получить 95 )
TessellatingHeckler

3

Perl 6, 70 символов

repeat {$/=now;.push($!=get,now -$/)}while $!;.map:{sleep $^b;say $^a}

Интерпретатор Perl 6 определяет только три символические переменные (в отличие от сумасшествия Perl 5). Чтобы быть точным, то $/, $!и $_. Эта программа использует их все, чтобы избежать затрат на объявление переменных my.

getчитает строку из STDIN. Он не содержит перевода строки, в отличие от Perl 5.

nowВстроенный возвращает текущее время. При вычитании это дает интервал, который может быть передан в строку.

Метод, в котором ничего не осталось (как .pushи .mapв этом коде), работает $_.

Используя repeat whileцикл (известный как do whileв других языках программирования), Perl 6 записывает текущую временную метку $/и помещает полученную строку (которую он также сохраняет $!), а также разницу между текущим временем и временной меткой $/. Из-за порядка параметров nowне рассчитывается до получения строки.

В whileпроверяет состояние , если строка не пуста (в Perl 6, "0"это истинное значение, в отличие от Perl 5).

После того, как я получаю все метки времени и линии, я просто предоставляю те для mapобратного вызова, который немного спит и говорит, что было сказано.


2

Groovy, 202 байта

def b={System.currentTimeMillis()};def h=[];for(;;){def t=b();def s=System.console().readLine();h.add(s+" "+(b()-t));if(s=="")break};for(def s:h){Thread.sleep((s=s.split(" "))[1].toLong());println s[0]}

Radical.

Безголовая версия:

def b = {System.currentTimeMillis()}; // Creates a closure (short function) b that returns the current time since the epoch in milliseconds.
def h = []; // Makes an empty list
for(;;) { // Infinite loop
  def t = b(); // Get the time
  def s = System.console().readLine(); // Read a line
  h.add(s + " " + b()-t); // Add the string plus the amount of time elapsed to the list
  if(s=="") // If the string is blank
    break; // Exit loop
}
for(def s : h) { // Iterate through array
  Thread.sleep((s=s.split(" "))[1].toLong()); // Splits s into an array and puts the value in s, then takes the second element (the time), converts into a long and sleeps for that time.
  println s[0] // Print the first element (text)
}

2

JavaScript (ES6) 102

Объединение усилий Mwr247 и Dom Hastings (CW)

/* for TEST */ console.log=x=>O.innerHTML+=x+'\n'

for(k=new Date,i=[];p=prompt();i.push([p,new Date]));i.map(a=>setTimeout(b=>console.log(a[0]),a[1]-k))
<pre id=O></pre>


2

MATLAB, 107 99

tic;a={};i=1;while nnz(i);i=input('','s');a=[a;{i,toc}];tic;end;for b=a';pause(b{2});disp(b{1});end

И безглым

tic; %Start timer
a={};
i=1; %Make us enter the while loop
while nnz(i); %While i has some non-zero elements (this is used to detect a zero length input where we end)
    i=input('','s'); %Get an input string
    a=[a;{i,toc}]; %Append the string and current time as a new cell in a
    tic; %Restart timer
end
for b=a' %For each input
    pause(b{2}); %Wait for the required time
    disp(b{1}); %Then print the string
end

Это не будет на 100% точным по времени, так как не учитывает время, затрачиваемое на отображение каждой строки, но это должно быть довольно быстрым, поэтому по времени это должно быть довольно близко.


После быстрого пересмотра я сохранил несколько байтов, удалив двухслойный массив глубоких ячеек. Оказывается, все, что мне было нужно, - ;это правильно разделить его при упаковке.


1
Может быть, вы могли бы сделать версию, которая играется в гольф в MATL.
ckjbgames

1

Java, используя версию 1.04 этой библиотеки , 385 байт

import sj224.lib.util.*;import java.util.*;class E{static long t(){return System.currentTimeMillis();}public static void main(String[]a) throws Exception{List<Pair<?,Long>>l=new ArrayList();Scanner i=new Scanner(System.in);while(true){long t=t();String s=i.nextLine();if(s.isEmpty())break;l.add(new Pair(s,t()-t));}for(Pair<?,Long>p:l){Thread.sleep(p.two);System.out.println(p.one);}}}

1

Cache ObjectScript, 123 байта

w() q $P($ZTS,",",2)
r f  s i=i+1,t=$$w() r x,! q:x=""  s g(i,x)=$$w()-t
    f i=1:1 s s=$O(g(i,"")) q:s=""  w s,! h g(i,s)
    q

Как обычно, это предполагает чистую таблицу символов перед запуском d r.

Эта проблема не может быть решена в ANSI MUMPS, поскольку стандарт ANSI требует только разрешения второго уровня для встроенного времени $H[OROLOG]. К счастью, Intersystems Caché, которая в настоящее время в отрасли платформу для свинка, обеспечивает в реализации определенных $ZT[IME]S[TAMP]сущностных , которая обеспечивает разрешение микросекунд-уровня.

(Оценка была раньше 105 байтов, но была ошибка.)


1

C ++ 11, 343 338 байт

Хотел посмотреть, сколько байт потребуется для кода в c ++. Гораздо больше, чем я ожидал. Может быть, я слишком сложное решение.

#include<iostream>
#include<vector>
#include<chrono>
int i;using namespace std;int main(){auto n=chrono::system_clock::now;auto t=n();string s{1};vector<string>r;vector<decltype(t-t)>w;while(s.size())getline(cin,s),r.push_back(s),w.push_back(n()-t),t=n();while(i<r.size()){while((n()-t)<w[i]);t=n();cout<<r[i++]<<(i<r.size()-1?"\n":0);}}  

Посмотрим, смогу ли я как-нибудь уменьшить это.


Вы можете удалить пробелы в #includes и объявление типа для main. Это 7 байтов - не много, но начало. Вы также можете использовать, autoа не stringдля s.
Алекс А.

Спасибо за ответ. Я буду сохранять тип возврата для основного. Если я правильно помню, только для cэтого нам не нужно указывать это. Я пытался изначально использовать auto s... но похоже, что он преобразован в const char *и нет std::string. Интересно, смогу ли я создать псевдоним для while.
Вендельбсильва

Удаление возвращаемого типа работает для C ++, даже если оно «не должно» в соответствии со стандартом. Вы можете попробовать создать псевдоним для whileиспользования #defineможет быть.
Алекс А.

1

Баш, 91 90 байт

while r=`\time -fsleep\ %e head -1`
[[ $r ]]
do printf{,\ %%b\ %q\;} "$r
"
done>t 2>&1
. t

Это создает временный файл t. Он перезапишет существующий файл с тем же именем.

Сама идея довольно короткая, но работа со специальными символами на входе добавляет около 15 байт ...


1

VBA, 233 228 байт

Я уверен, что это может быть много в гольфе. они не указали, сколько входных данных, поэтому я жестко запрограммировал длину моего массива, потому что тогда он короче Redim preserve.

Вход через всплывающее окно, выход debug.print потому что msgboxсоздает MODAL и останавливает код.

Я не знаю, как проверить, если это с точностью до 0,01 с. Может быть, кто-то может проверить, но я даю команде wait номер таким образом, что она ДОЛЖНА использовать миллисекунды, но VBA не известна тем, что она должна делать.

If gotoМожет быть в состоянии быть замещен хорошо golfed Do Loop While.

Sub a()
Dim k(99) As String
Dim h(99) As Date
b:
t=Now()
i=i+1
k(i)=InputBox("")
h(i)=Now()-t
If k(i)<>"" Then GoTo b
For u=1 To i
Application.Wait (Now()+(Format(h(u),"s")&Format(h(u),"ms"))/10^8)
Debug.Print k(u)
Next
End Sub

Не будет работать в Access VBA, потому что у доступа нет команды ожидания, потому что Microsoft ненавидит согласованность


0

SmileBASIC, 122 байта

DIM A$[0],T[0]@L
C=MAINCNT
LINPUT S$PUSH A$,S$PUSH T,MAINCNT-C
IF""<S$GOTO@L@P
WAIT SHIFT(T)IF""<A$[0]THEN?SHIFT(A$)GOTO@P

Я думаю, что это можно сделать немного короче.


0

C UNIX, 272 байта

#include <stdio.h>
#include <unistd.h>
#define P printf
i;r;c;main(){char*L[99]={0};size_t s;long T[99]={0};while(1){P(">  ");T[c]=time(0);r=getline(&L[c],&s,stdin);T[c]=time(0)-T[c];if(r==-1|!(*L[c]-10))break;c++;}while(i<c){P("> ");usleep(T[i]*1000);P("%s", L[i]);i++;}}

Детальнее

#include <stdio.h>
#include <unistd.h>

int main(void)
{
    int i = 0, c = 0, r;
    char * L[99] = {0};
    size_t size;
    long T[99] = {0L};

    while(1)
    {
        printf("> ");
        T[c] = time(0);
        r = getline(&L[c], &size, stdin);
        T[c] = time(0) - T[c];
        if(r == (-1)) break;
        if(*L[c]=='\0' || *L[c]=='\n') break;
        c = c + 1;
    }

    while(i < c)
    {
        printf(" %ld > ",T[i]);
        usleep(T[i]*1000);
        printf("%s", L[i]);
        i = i + 1;
    }

    return 0;
}

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.