实施秒表


23

实现一个简单的数字秒表,它将以秒和分钟为单位显示经过的时间,如下所述。

重要

请阅读“ 显示”和“ 控件”部分!

显示

经过的时间应以MM:SS格式显示,方法是替换以前显示的时间字符串“就地”(也可以清除整个屏幕或部分屏幕)。

秒表必须至少每秒更新一次。

例子:

0分0秒

00:00

0分33秒

00:33

1分50秒

01:50

最初,您可以从“ 00:00”开始,也可以从[00:00-59:59]范围内的任何其他值开始。

秒表到达时59:59,它应重置为00:00并重新开始。

只要您遵循常规格式,就可以使用其他基数(而不是十进制),甚至可以使用其他数字系统。

例如13:03可以显示为:

小数

13:03

十六进制

0D:03

Base64

N:D

虚构基数

10101:3

罗马数字

XIII:III

请注意,如果您使用非十进制数字系统/基数,则必须使用可打印的ASCII(或Unicode)字符对它进行编码,例如,不允许使用两个二进制(不可打印的)字节分别表示分钟和秒。

如果数值系统允许的话,还必须在输出上用零填充左键。

:用任何其他可打印字符(包括数字)替换分隔符也是可以的。

控制项

秒表应开始暂停,并保持此状态,直到用户通过按“控制”键(见下文)明确启动它为止。

如果,当秒表计数,用户按下“控制”再次键,秒表应该暂停,直到(保持当前的时间),“控制”键被按下一次。

“对照”键可以是单个键击,例如s,或键,例如任何组合Ctrl+Shift+X,但它必须是“原子”,按压在序列多个按键,例如s然后Enter,被不允许

必须使用相同的“控制”键(或组合键)来暂停恢复秒表。

您必须使用特定的“控制”键,即不允许使用“任何键”。

另外,您也可以单击一次或双击,而不用按下“控制”键。


规则

  • 这是,以字节为单位的最短答案为胜;
  • 适用标准代码高尔夫球漏洞;
  • 您的程序必须(理论上)能够永远运行。

可以输入“控制”键吗?
Loovjo

@Loovjo是的,任何单个键或键组合都可以使用,包括Enter键(只要可以暂停然后使用同一键恢复即可)。
Zeppelin


1
我们是否需要亚秒级的粒度?也就是说,如果用户在00:05打印后暂停了大约7000毫秒,然后又重新开始,是否必须在00:06按下恢复键后出现3000毫秒,还是可以在按下恢复键后打印整整一秒钟?
smls

@smls恢复后可以等待一秒钟。
Zeppelin

Answers:


8

SmileBASIC,86 77 71字节

@L
N=N!=DIALOG(FORMAT$("%02D:%02D",F/60MOD 60,F MOD 60),,,N)F=F+1GOTO@L

DIALOG在触摸屏上显示一个文本框。N是文本框消失前在屏幕上停留的秒数。如果N0,则它将一直保留到用户按下触摸屏上的按钮为止。

DIALOG返回1用户是否按下了按钮,并且按钮0是否自动关闭。因此,当用户按下暂停按钮时,它将返回1,并且显示时间设置为0,从而使秒表暂停。用户再次按下按钮后,我们将显示时间重新设置为1,恢复计时器。基本上,每次DIALOG返回时1,显示时间就在10使用之间切换!=,只要两个输入均为1或0,就等于逻辑XOR。


看起来很棒!如果您还可以提供有关其工作原理的动画“截屏视频”,将不胜感激!
齐柏林飞艇

好吧,我会尽快做的
2007年

也可以在此模拟器上进行测试:citra-emu.org/game/smilebasic
roblogic

9

Python 2中,167个 129字节

-36个字节主要来自*使用Maltysen的ctrl-c使用异常捕获的想法 - 值得称赞
-4个字节归功于DLosc(初始值nb0而不是f()
-1个字节归功于FlipTack(使用p^=1而不是p=1-p
-2个字节归功于Felipe Nardi Batista(删除精度说明符)

import time
f=time.time
n=b=p=0
while 1:
 try:n=[n,f()][p];t=n-b;print'\r%02d:%02d'%(t/60%60,t%60),
 except:b=[b-n+f(),b][p];p^=1

与下面的原始图片相同,但控制键序列为ctrl+c
(由我在Windows 7 64bit上使用Python 2.7.8进行
测试; 由Brian Minton在Linux 64bit上使用Python 2.7.13进行测试)

*还折叠if了对列表查找的语句,以使它try成为单行。

我的原件:

import time,msvcrt as m
f=time.time
n=b=p=0
while 1:
 if m.kbhit()and m.getch()==b'p':b=[b-n+f(),b][p];p^=1
 if p:n=f()
 t=n-b;print'\r%0.2d:%0.2d'%(t/60%60,t%60),

(由我在Windows 7(64位)上使用Python 2.7.8进行了测试-但是,由于使用了该msvcrt库,因此此代码特定于Windows )

控制键为“ p”。

nb在启动时初始化为相同的值,“偏移”为0;p被初始化为0,表示暂停状态。

每当按下控制键时,的值p就会切换。当从暂停状态切换到活动状态时,b将更新为新值,并使用保持与前一个活动状态的任何当前偏移b-n

在活动状态期间,n通过调用反复将其更新为当前时间time.time()

之间的差nbt激活状态(或多个)期间,然后是秒的总数(包括小数部分)经过。

然后经过t/60的分钟数将以分钟60的分钟和秒数显示(t/60%60,t%60)。对于每个前导零,使用整数部分的字符串格式(以开头)'...%0.2d...',在第一个项的前导回车符()处打印元组(尾随)\r会导致先前打印的文本被覆盖。


嗯,不错,我原本确实有,^=但是在制定过程中的某个时候切换了。
乔纳森·艾伦

@DLosc的确如此,谢谢...
Jonathan Allan

它不是Windows特定的。我刚刚使用Python 2.7.13在Linux 64位上对此进行了测试,并且可以正常工作。(使用Ctrl-C的控制键)
Brian Minton

@BrianMinton谢谢您让我知道!
乔纳森·艾伦

.in 的需求是%0.2d什么?它的工作原理就像%02d
Felipe Nardi Batista

6

蟒- 160个 159 143字节

感谢@JonathanAllan为我节省了18个字节!

仅使用内置库,因此控制键为ctrl-c,以捕获它except keyboardInterrupt

import time
Z=0
print'00:00'
while 1:exec"try:\n while 1:\n  %s\nexcept:1\n"*2%(1,"print'\033c%02d:%02d'%divmod(Z%3600,60);Z+=1;time.sleep(1)")

不错哦。我认为也许仅仅用它就可以缩短except:?我有我的工作版本...
Jonathan Allan

@JonathanAllan哦,很酷,不知道您能做到。
Maltysen

5

bash + Unix实用程序,90或93字节

90字节版本:

trap d=\$[!d] 2;for((n=0;;)){((d|!n))&&dc<<<DP60dod*d$n\r%+n|colrm 1 4&&: $[n++];sleep 1;}

93字节版本:

trap d=\$[!d] 2;for((n=0;;)){((d|!n))&&dc<<<DP60dod*$n+n|colrm 1 4&&n=$[(n+1)%3600];sleep 1;}

Ctrl-C是恢复/暂停字符。空格是分钟和秒之间的分隔符。

两种版本之间的区别在于90字节的程序将运行2 ^ 63秒(此时,bash将给我整数溢出)。

93字节的版本将永远有效。

最初的问题包括以下要求:“您的程序必须(理论上)能够永远运行。”

如果运行2 ^ 63秒足以满足该要求,则可以使用90字节的解决方案。持续时间是宇宙年龄的20倍以上!

如果程序需要能够运行更长的时间,我将不得不使用93字节的解决方案。


我可能应该指出,这种解决方案以及至少其他一些解决方案,将非常缓慢地落后于实际经过的时间。这种滑移的原因是,在每次执行循环主体之间,程序都会休眠一秒钟,但是循环主体确实需要花费很少的时间来执行。实际上这是无关紧要的。


除非您“取消暂停”,否则它似乎不会在屏幕上显示初始值。
Zeppelin

“秒表应该开始暂停,并保持这种状态,直到用户通过按下'control'键(见下文)明确启动它为止。” 有没有我错过的规格?
米切尔·史派克

是的,这是正确的,但它仍应显示一个初始值Initially, you can start with '00:00' or with any other value in range [00:00-59:59],该值将一直保留在屏幕上,直到您首次按下“ control”。对不起,如果我还不能把这个表述得足够清楚!
齐柏林飞艇

好的,这很有道理-我将对其进行修改。
米切尔·史佩克特

1
现在看起来一切都很好!
Zeppelin

5

QBasic,213211字节

控制键是选项卡。保持运行状态可能会导致笔记本电脑起火。你被警告了。

DO
WHILE k$<>CHR$(9)
k$=INKEY$
LOCATE 1
?CHR$(48+m\10);CHR$(48+(m MOD 10));":";CHR$(48+(d MOD 60)\10);CHR$(48+(d MOD 10))
IF r THEN
n=TIMER
d=v+n-b+86400
m=d\60MOD 60
END IF
WEND
k$=""
v=v+n-b
r=1-r
b=TIMER
LOOP

它在起作用,在10、15和20秒暂停:

秒表运行

取消评论

' Outer loop runs forever
DO
  ' The WHILE-WEND loop runs until tab is pressed
  WHILE key$ <> CHR$(9)
    key$ = INKEY$
    ' Output the stopwatch value at top left of screen
    LOCATE 1
    ' Unfortunately, QBasic's PRINT USING doesn't have a format for printing
    ' with leading zeros, so we have to do it manually by printing the
    ' 10s digit and the 1s digit
    PRINT CHR$(48 + minute \ 10); CHR$(48 + (minute MOD 10));
    PRINT ":";
    PRINT CHR$(48 + second \ 10); CHR$(48 + (second MOD 10))
    ' Update the current time if the running flag is set
    IF running THEN now = TIMER
    ' Take the difference between now and the last time we started the
    ' stopwatch, plus the amount of saved time from previous runs,
    ' plus 86400 to account for the possibility of running over midnight
    ' (since TIMER is the number of seconds since midnight, and QBasic's
    ' MOD doesn't handle negative values like we would need it to)
    diff = saved + now - lastStarted + 86400
    second = diff MOD 60
    minute = diff \ 60 MOD 60
  WEND
  ' If we're outside the WHILE loop, the user pressed tab
  key$ = ""
  ' Add the previous run's time to the saved amount
  saved = saved + now - lastStarted
  ' Toggle running between 0 and 1
  running = 1 - running
  ' If we're starting, we want to put the current time in lastStarted;
  ' if we're stopping, it doesn't matter
  lastStarted = TIMER
LOOP

请注意,的值为TIMER浮点数。这并不影响输出,因为MOD\截断为整数。但这确实增加了所节省时间的准确性:如果您在滴答滴答之前暂停计时器,则当再次启动计时器时,您会看到该数字在不到一秒钟的时间内变化。


4

批处理,132字节

set/ar=0,m=s=100
:l
cls
@choice/t 1 /d y /m %m:~1%:%s:~1% /n
set/as+=r,m+=c=s/160,s-=c*60,m-=m/160*60,r^^=%errorlevel%-1
goto l

按下n将(取消)暂停计时器。可以减少三(或四个)字节的输出闪烁。


4

纯bash,141个字节

set -m
while ! read -t 1;do printf '\r%02i:%02i' $[s=s>3598?0:s+1,s/60] $[s%60];done&trap 'fg>/dev/null' TSTP
printf '00:00'
kill -STOP $!
read

它只使用Bash内置函数(不使用外部工具)。控制字符是Ctrl-Z,因此标准SIGTSTP处理会使秒表暂停。

如果Ctrl-Z在子外壳程序处于前台状态时按,则它将暂停执行并将外部脚本返回到前台,在此它将静默等待。如果外部脚本位于前台,则陷阱处理程序将恢复子Shell的执行,并将再次计数。


3

Chrome控制台中的Javascript,143字节

f=document,m=s=g=i=0;setInterval(()=>{if(g%2){m=(i/60|0)%60;s=i++%60}f.write((m>9?m:'0'+m)+':'+(s>9?s:'0'+s));f.close();f.onclick=()=>g++},1e3)

当在控制台中输入时,它将计数器初始化为00:00,然后启用对文档进行按键控制。

没有太多的魔术,尤其是(i/60)|0楼层数

在Chrome控制台中完成并经过测试


好答案。您可以通过对不带参数的函数使用伪参数来删除一些字节,并可以用包含代码的字符串替换setInterval中的第一个参数。
路加福音

1
132 B:m=s=g=i=0;(f=document).onclick=_=>g++;setInterval("g%2&&f.close(f.write(`${(m=i/60%60|0)>9?m:'0'+m}:`+((s=i++%60)>9?s:'0'+s)))",1e3)
路加福音

哦,太好了:)在这里学到了一些东西。间隔中的字符串和_ => g ++。谢谢:)
gzbz

3

HTML +的JavaScript(ES6),191个192 187 183 174字节

<b onclick='b=b?clearInterval(b):setInterval("a.innerHTML=`${(d=(((c=a.innerHTML.split`:`)[1]>58)+c[0])%60)>9?d:`0`+d}:${(e=++c[1]%60)>9?e:`0`+e}",1e3)'onload='b=0'id=a>00:00

说明

单击计时器以启动或暂停秒表。这样,单击就是控制键。两个值之间的分隔符是冒号。

每当用户单击该点击时,b都会检查的值。将其初始化为0,结果为false,因此每1000毫秒对一串代码进行评估。这会将变量设置为间隔的id,因此可以稍后将其停止。如果b包含数字,则结果为true,因此间隔停止。这将返回值undefined,因此循环继续。

代码字符串更改具有id a(秒表)的元素的html 。首先,通过获取前一个秒表值,将其解析为分钟,然后将其除以冒号,然后获取分钟值,如果秒值不是59(大于58),则将其增加0;否则将其取模16,否则为1然后填充此值。然后是冒号,最后是秒。代码只是获取旧值,将其增加1,取模60,并可选地填充它。


这似乎根本不起作用。我刚收到ReferenceError:d尚未定义
Alexis Tyler's

您可能还可以通过删除href =#来节省一些字节,因为使用onclick实际上并不需要它。
亚历克西斯·泰勒

我刚刚解决了。我也删除了href,因为您是对的。谢谢!
路加福音

您不能将onclick放在b标签上并在答案中指定吗?

我想那行得通。它节省了9B。非常感谢!
路加福音

3

C 309179字节

f(){m=0,s=0;A: while(getchar()^'\n'){if(s++==59){if(m++==59)m=0;s=0;}printf("\r%02d:%02d",m,s);sleep(1);system("clear");if(getchar()=='\n'){break;}}while(getchar()^'\n'){}goto A;}

非高尔夫版本:

void f()
{
   int m=0,s=0;

   A: while(getchar()^'\n')
      {           
       if(s++==59)
       {
         if(m++==59)
           m=0;

         s=0;
       }
       printf("\r%02d:%02d",m,s);
       sleep(1);  
       system("clear");

        if(getchar()=='\n')
        {
          break;
        }
      }

       while(getchar()^'\n')
       {}
       goto A ;
}

使用方法:按此Enter按钮可以暂停恢复秒表。

说明:

  • 等待Enter按键,break第一个while循环,直到下一个循环Enter
  • 下次Enter按键时,goto首先while循环并恢复计数。

现在,我知道gotoC语言中的一种不好的编码习惯,但是我想不出另一种方法。


该代码无法编译。此外,getchar()阻塞直到按下某个字符。
G. Sliepen

在Linux机器上编译和运行
Abel Tom,

可能是非高尔夫版本,而高尔夫版本则没有。m=0,s=0;它已经失败了,因为您没有在任何地方声明这些变量。
G. Sliepen

3

Javascript,124个字节

s=i=1,setInterval("s&&(d=document).close(d.write(`0${i/60%60|0}:`.slice(-3)+`0${i++%60}`.slice(-2))),d.onclick=_=>s=!s",1e3)

单击“控制键”即可在文档上单击。要对此进行测试,请将代码粘贴到控制台或<script>标记内的html文件中。

说明:

let s = 1
let i = 1
setInterval(() => {
    //If s = true then check after the "&&" operator else false
    s && (d = document).close( //put the document variable inside the d variable, so now i don't need to use anymore the long word 'document, then i close the document
            d.write( //Write into the document the next string
                `0${i/60%60|0}:`.slice(-3) + `0${i++%60}`.slice(-2) //Here is the magic, here I update the 'i' variable and convert the 'i' value to minutes and seconds
            ) 
        ),
        d.onclick = _ => s = !s //Add onclick event to the document, if s = true then s = false, if s = false then s = true
}, 1e3) //1e3 = 1000

在Chrome中测试


1
欢迎光临本站!是否可以在指向在线测试站点的链接中进行编辑,例如“ 在线尝试”!,以便其他用户可以验证您的答案?
caird coinheringaahing

感谢@cairdcoinheringaahing,它与jsfiddle一起使用:jsfiddle.net/xjw7o0ps
TheCopyright

2

PHP,94 91字节

我假设32是空格键的关键代码(可能不是)。
我目前无法测试ncurses。但是其余的代码可以正常工作。

for($s=[STDIN];;)echo date("\ri:s",$t+=$r^=stream_select($s,$n,$n,1)&&32==ncurses_getch());

从开始于00:00,但在暂停结束后立即增加

如果您(像我一样)没有ncurses,则可以通过用或替换第二个date参数来进行测试。(总是返回。)$t+=$r^=!rand(sleep(1),19);$t+=$r^=++$x%20<1+sleep(1);sleep0

分解

for($s=[STDIN];                     // set pointer for stream_select
    ;                               // infinite loop:
)
    echo date("\ri:s",                  // 5. print CR + time
        $t+=                            // 4. increment $t if watch is running
        $r^=                            // 3. then toggle pause
            stream_select($s,$n,$n,1)   // 1. wait 1 second for a keystroke
            &&32==ncurses_getch()       // 2. if keystroke, and key==space bar
    ;

2

C#220字节

using static System.Console;
using static System.DateTime;
class P
{
    static void Main()
    {
        var l = Now;
        var d = l-l;
        for( var r = 1<0;;Write($"\r{d:mm\\:ss}"))
        {
            if (KeyAvailable&&ReadKey(1<2).KeyChar == 's')
            {
                l = Now;
                r = !r;
            }
            if (r)
                d -= l - (l = Now);
        }

    }
}

打高尔夫球

using static System.Console;using static System.DateTime;class P{static void Main(){var l=Now;var d=l-l;for(var r=1<0;;Write($"\r{d:mm\\:ss}")){(KeyAvailable&&ReadKey(1<2).KeyChar=='s'){l=Now;r=!r;}if(r)d-=l-(l=Now);}}}

使用s键开始/停止。整个程序通过记住使用DateTime.Now

这里的大多数C#-Magic都来自C#7.0功能using static


2

Bash,65个字节

trap d=\$[!d] 2;for((;;)){ printf "\r%(%M:%S)T" $[n+=d];sleep 1;}

请注意,必须将其写入文件脚本才能正常工作,否则,请尝试:

bash -c 'trap d=\$[!d] 2;for((;;)){ printf "\r%(%M:%S)T" $[n+=d];sleep 1;}'

扩展版解释一下:

trap d=\$[!d] 2                     # flip d for each INT (ctrl-c) signal.
for((n=0;;)){                       # repeat forever the code inside the {...}
                                    # The n=0 is not strictly needed.
    printf "\r%(%M:%S)T" "$[n+=d]"  # Print Minute:Second string calculated from 
                                    # the n value, increment by the value of d.
                                    # If IFS is not numeric (0-9), then, the
                                    # quotes around "$[n+=d]" could be removed.
    sleep 1                         # wait for 1 second.
}

%(...)Tprintf 的格式在bash 5+中有效。


不起作用 00:00按下时,仅打印并增加计数器Ctrl-C。没有计时器的动画。(在bash 5.0.7上测试)
roblogic

1
您是否将代码编写到脚本中?否则,请尝试:bash -c 'trap d=\$[!d] 2;for((;;)){ printf "\r%(%M:%S)T" $[n+=d];sleep 1;}'。@roblogic
艾萨克

啊,行得通!该脚本必须与运行bash -c:)
roblogic

1

C(gcc)121115字节

p,r;g(){r^=1;}main(t,b){for(b=time(signal(2,g));;r?p=t:(b+=t!=p))t=time(0)-b,printf("\r%02d:%02d  ",t/60%60,t%60);}

在线尝试!

设置SIGINT的信号处理程序,可通过按Control-C触发该信号处理程序。我们在中保留一个时间偏移b,并显示挂钟时间减去时间偏移。如果我们停顿了,每次壁钟滴答滴答地增加时基以冻结显示的时间。

感谢@ceilingcat削减了6个字节!


0

Zsh + Gnu日期,242个字节

具有1/100秒的功能!它需要一个交互式终端,但是无论如何这是一个TIO链接
点击Enter以启动/停止计时器;Ctrl-C退出。

u(){p=`gdate +%s`;q=`gdate +%N`;}
f(){read -t0.01&&{read;break};unset REPLY}
g(){while :;{u;t=$[p-a];s=$[t%60];m=$[(t%3600-s)/60]
echo "\r`printf %02d:%02d $m $s`.$q[1,2]\c";f;}}
<<<ready;read;u;a=$p
while :;{f;echo "\r\e[2A\c";u;a=$[p-t];g;}

评论(有点过时):

u()echo $[`gdate +%s%N`/1000]       # fn:unix timestamp extended to µs
v()gdate +%s                        # fn:unix time, in s
f(){read -t0.01 -r&&{read -r;break;} # fn:listens for "Enter"
                      ;unset REPLY;}

g(){while :;                        # fn:rolling stopwatch
    {q=`u`;t=$[`v`-a]               #    t=time diff from baseline (s)
    ;echo "\r`printf %02d:%02d      #    format output
    $[(t%3600-s)/60] $s`            #    minutes:seconds
    .${q:10:2}\c";                  #    .xx = partial seconds
    f;}}                            #    listen for "Enter"

                                    # Execution starts here!
<<<ready;read;u;a=$p                # Wait for "Enter"; get baseline $a

while :;{                           # Main program loop
         f;                         # listen for an "Enter"
           echo "\r\e[2A\c"         # go up 1 line of the console
a=$[`v`-t]                          # reset the baseline
                ;g;}                # begin the stopwatch

@Isaac,我无法击败您的简洁和优雅答案,所以我想我应该添加功能……
roblogic

1
这是一个很棒的目标@roblogic :-) .... ....仍然了解您的代码....
Isaac

0

Commodore BASIC(C64 / TheC64 Mini,VIC-20,PET,C16 / + 4)-147个标记化和BASIC字节

 0?"{clear}":geta$:ifa$<>" "thengoto
 1ti$="000000"
 2fori=.to1:?"{home}"mid$(ti$,3,2)":"mid$(ti$,5,2):geta$:b$=ti$:i=-(a$=" "):nE:pO198,.
 3geta$:ifa$<>" "then3
 4ti$=b$:goto2

{clear}清单中的SHIFT+CLR/HOME哪一个是在跟随引号时输出为一个PETSCII字符,而是在跟随引号的相同条件下没有移位{home}CLR/HOME键。

使用空格键作为控制键。

要在BASIC 7中使用Commodore 128,请在以下几行中更改清单:

 0?"{clear}":geta$:ifa$<>" "thengoto0
 2fori=.to1:?"{home}"mid$(ti$,3,2)":"mid$(ti$,5,2):geta$:b$=ti$:i=-(a$=" "):nE:poK198,.

在计数中添加额外的七个令牌(因为所有数字都作为7个字节存储在BASIC中,所以goto108个标记字节goto也只有1个)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.