Your task is to make a program that measures how fast you can type the letters of the English alphabet.
- The program shall only accept lowercase letters
atozin alphabetical order. - Each letter is echoed as typed on the same line (without new line or any other separators between letters).
- If you type an invalid character the program shall output
Failon a new line and exit. - If you type all 26 letters the program shall, on a new line, output the time in milliseconds it took from the first to the last letter and exit.
- The timer starts when you type the first letter,
a.
Example outputs:
b
Fail
abcdefgg
Fail
abcdefghijklmnopqrstuvwxyz
6440
This is code-golf, so shortest answer in bytes wins.
23 Answers 23
HTML (JavaScript (ES6)), (削除) 129 (削除ここまで) (削除) 126 (削除ここまで) 117 bytes
<input id=i onfocus=l=0,n=Date.now onkeypress=event.which-97-l?i.outerHTML='Fail':24<l?i.outerHTML=n()-t:t=l++?t:n()>
Click in the input and start typing! Also, my typing sucks; I take about 5 seconds even with practice. Edit: Saved 2 bytes thanks to @HermanLauenstein by switching language. Saved 3 bytes thanks to @qw3n. Saved 9 bytes thanks to @tsh.
-
1\$\begingroup\$ -2 bytes by using html with a script tag:
<input id=i><script>l=0;n=Date.now;i.onkeypress=e=>e.charCode-97-l?i.outerHTML='Fail':l>24?i.outerHTML=n()-t:t=l++?t:n()</script>, -11 bytes if the closing tag isn't needed \$\endgroup\$Endenite– Endenite2017年10月29日 11:02:08 +00:00Commented Oct 29, 2017 at 11:02 -
\$\begingroup\$ @HermanLauenstein The closing tag seems to be necessary for a snippet, at least, so I'll leave it in. \$\endgroup\$Neil– Neil2017年10月29日 11:35:33 +00:00Commented Oct 29, 2017 at 11:35
-
2\$\begingroup\$ This is too infuriating and fun at the same time. \$\endgroup\$Zenon– Zenon2017年10月29日 23:26:32 +00:00Commented Oct 29, 2017 at 23:26
-
1\$\begingroup\$ What about put event on input?
<input id=i onkeypress=event.which-97-l?i.outerHTML='Fail':24<l?i.outerHTML=n()-t:t=l++?t:n() onfocus=l=0,n=Date.now>\$\endgroup\$tsh– tsh2017年10月30日 02:27:25 +00:00Commented Oct 30, 2017 at 2:27 -
1\$\begingroup\$ Doesn't echo the text on a new line \$\endgroup\$anna328p– anna328p2017年10月30日 19:40:18 +00:00Commented Oct 30, 2017 at 19:40
6502 machine code (C64 PAL), (削除) 189 (削除ここまで) 165 bytes
00 C0 A9 17 8D 18 D0 A9 40 85 FE E6 FE 20 E4 FF F0 FB 20 D2 FF C5 FE 38 D0 38
C9 5A 18 F0 33 C9 41 D0 E8 A9 00 85 FC 85 FD A9 18 85 FB A9 7F 8D 0D DD A9 7F
8D 18 03 A9 C0 8D 19 03 A9 D8 8D 04 DD A9 03 8D 05 DD A9 01 8D 0E DD A9 81 8D
0D DD D0 B9 A9 7F 8D 0D DD A9 47 8D 18 03 A9 FE AD 19 03 CE 0E DD B0 14 A9 0D
20 D2 FF A4 FC A5 FD 20 91 B3 20 DD BD A9 01 A8 D0 04 A9 9D A0 C0 4C 1E AB 48
AD 0D DD 29 01 F0 14 E6 FC D0 02 E6 FD C6 FB D0 0A A9 18 85 FB CE 0E DD EE 0E
DD 68 40 0D C6 41 49 4C 00
- -24 bytes by inlining functions and not caring for other CIA2 interrupts
Online demo (Usage: sys49152)
Explanation:
This would be a tiny program if it wasn't for the problem of an exact measurement of milliseconds on the C64. The system interrupt occurs roughly 60 times per second, which isn't even close. So we have to use a hardware timer here that gets its input ticks from the system clock.
On a PAL machine, the system clock is exactly 985248 Hz. Initializing the timer to 985 therefore gives something close to millisecond ticks, but it's a bit too fast, we'd have to count 986 cycles for every fourth tick, or hold the timer for a single cycle. This isn't possible, but we can hold the timer for 6 cycles with the sequence DEC $DD0E, INC $DD0E: $DD0E is the timer control register with bit 0 switching it on and off, and both instructions take 6 cycles, so the exact writes that stop and start the timer are exactly 6 cycles apart. Therefore we have to execute this sequence every 6*4 = 24th tick. This still isn't absolutely exact, the timer will lag 1 millisecond behind after 8 minutes and 12 seconds, but it's probably good enough -- compensating for that one would take a lot of code.
edit: The start value for the timer must be 984, not 985, because these timers fire "on underflow", so a value of 0 will count one more cycle before firing. Code fixed, byte count unchanged.
Here's the commented disassembly listing:
00 C0 .WORD $C000 ; load address
.C:c000 A9 17 LDA #17ドル ; mode for upper/lower text
.C:c002 8D 18 D0 STA $D018 ; set in graphics chip
.C:c005 A9 40 LDA #40ドル ; initialize expected character
.C:c007 85 FE STA $FE ; to 'a' - 1
.C:c009 .mainloop:
.C:c009 E6 FE INC $FE ; increment expected character
.C:c00b .getchar:
.C:c00b 20 E4 FF JSR $FFE4 ; read character from keyboard
.C:c00e F0 FB BEQ .getchar ; until actual character entered
.C:c010 20 D2 FF JSR $FFD2 ; output this character
.C:c013 C5 FE CMP $FE ; compare with expected
.C:c015 38 SEC ; set carry as marker for error
.C:c016 D0 38 BNE .result ; wrong character -> output result
.C:c018 C9 5A CMP #5ドルA ; compare with 'z'
.C:c01a 18 CLC ; clear carry (no error)
.C:c01b F0 33 BEQ .result ; if 'z' entered, output result
.C:c01d C9 41 CMP #41ドル ; compare with 'a'
.C:c01f D0 E8 BNE .mainloop ; if not equal repeat main loop
.C:c021 A9 00 LDA #00ドル ; initialize timer ticks to 0
.C:c023 85 FC STA $FC
.C:c025 85 FD STA $FD
.C:c027 A9 18 LDA #18ドル ; counter for adjusting the timer
.C:c029 85 FB STA $FB
.C:c02b A9 7F LDA #7ドルF ; disable all CIA2 interrupts
.C:c02d 8D 0D DD STA $DD0D
.C:c030 A9 7F LDA #<.timertick ; set NMI interrupt vector ...
.C:c032 8D 18 03 STA 0318ドル
.C:c035 A9 C0 LDA #>.timertick
.C:c037 8D 19 03 STA 0319ドル ; ... to our own timer tick routine
.C:c03a A9 D9 LDA #$D8 ; load timer with ...
.C:c03c 8D 04 DD STA $DD04
.C:c03f A9 03 LDA #03ドル
.C:c041 8D 05 DD STA $DD05 ; ... 985 (-1) ticks (see description)
.C:c044 A9 01 LDA #01ドル ; enable timer
.C:c046 8D 0E DD STA $DD0E
.C:c049 A9 81 LDA #81ドル ; enable timer interrupt
.C:c04b 8D 0D DD STA $DD0D
.C:c04e D0 B9 BNE .mainloop ; repeat main loop
.C:c050 .result:
.C:c050 A9 7F LDA #7ドルF ; disable all CIA2 interrupts
.C:c052 8D 0D DD STA $DD0D
.C:c055 A9 47 LDA #47ドル ; set NMI interrupt vector ...
.C:c057 8D 18 03 STA 0318ドル
.C:c05a A9 FE LDA #$FE
.C:c05c AD 19 03 LDA 0319ドル ; ... back to system default
.C:c05f CE 0E DD DEC $DD0E ; disable timer
.C:c062 B0 14 BCS .fail ; if carry set, output fail
.C:c064 A9 0D LDA #0ドルD ; load newline
.C:c066 20 D2 FF JSR $FFD2 ; and output
.C:c069 A4 FC LDY $FC ; load timer value in
.C:c06b A5 FD LDA $FD ; A and Y
.C:c06d 20 91 B3 JSR $B391 ; convert to float
.C:c070 20 DD BD JSR $BDDD ; convert float to string
.C:c073 A9 01 LDA #01ドル ; load address of
.C:c075 A8 TAY ; string buffer
.C:c076 D0 04 BNE .out ; and to output
.C:c078 .fail:
.C:c078 A9 9D LDA #<.failstr ; load address of "Fail" string
.C:c07a A0 C0 LDY #>.failstr ; in A and Y
.C:c07c .out:
.C:c07c 4C 1E AB JMP $AB1E ; done; OS routine for string output
.C:c07f .timertick:
.C:c07f 48 PHA ; save accu
.C:c080 AD 0D DD LDA $DD0D ; load interrupt control register
.C:c083 29 01 AND #01ドル ; to know whether it was a timer NMI
.C:c085 F0 14 BEQ .tickdone ; if not -> done
.C:c087 E6 FC INC $FC ; increment timer ticks ...
.C:c089 D0 02 BNE .adjusttick
.C:c08b E6 FD INC $FD ; high byte only on overflow
.C:c08d .adjusttick:
.C:c08d C6 FB DEC $FB ; decrement counter for adjusting
.C:c08f D0 0A BNE .tickdone ; not 0 yet -> nothing to do
.C:c091 A9 18 LDA #18ドル ; restore counter for adjusting
.C:c093 85 FB STA $FB
.C:c095 CE 0E DD DEC $DD0E ; halt timer for exactly
.C:c098 EE 0E DD INC $DD0E ; 6 cycles
.C:c09b .tickdone:
.C:c09b 68 PLA ; restore accu
.C:c09c 40 RTI
.C:c09d .failstr:
.C:c09d 0D C6 41 .BYTE 0ドルD,"Fa"
.C:c0a0 49 4C 00 .BYTE "il",00ドル
-
6\$\begingroup\$ Well, now I have a somewhat decent millisecond timer in my toolbox ;) might be useful some day. \$\endgroup\$Felix Palmen– Felix Palmen2017年10月30日 16:53:11 +00:00Commented Oct 30, 2017 at 16:53
-
11\$\begingroup\$ Pay attention, script kiddies. This is real golf. \$\endgroup\$J...– J...2017年10月31日 17:23:47 +00:00Commented Oct 31, 2017 at 17:23
-
1\$\begingroup\$ @J... I could golf it further by inlining
.starttimer-- will do soon :) (and even further by using the systemTIlike this BASIC answer, but I'm not sure this is valid, because you can do better in machine code) \$\endgroup\$Felix Palmen– Felix Palmen2017年10月31日 22:26:34 +00:00Commented Oct 31, 2017 at 22:26 -
\$\begingroup\$ Wow, I missed a factor of 985 when calculating the error in my time measurement first -- it's actually pretty good the way it is (if I made another error in my calculations, please point out!) :) \$\endgroup\$Felix Palmen– Felix Palmen2017年11月01日 10:54:39 +00:00Commented Nov 1, 2017 at 10:54
-
\$\begingroup\$ And do you see what this guy have in the GITHUB?: android boot recovery.... he is completely insane! favorited his profile. \$\endgroup\$Luciano Andress Martini– Luciano Andress Martini2019年01月09日 11:58:59 +00:00Commented Jan 9, 2019 at 11:58
Bash + coreutils, (削除) 103 (削除ここまで) (削除) 99 (削除ここまで) 98 bytes
for((;c==p%26;r=`date +%s%3N`-(s=s?s:r),c=62#$c-9,p++))
{
read -N1 c
}
((c==p))||r=Fail
echo "
$r"
Must be run in a terminal.
Test run
$ bash type.sh
abcdefghijklmnopqrstuvwxyz
3479
$ bash type.sh
abcz
Fail
$ bash type.sh 2>&- # typing '@' would print to STDERR
ab@
Fail
$ bash type.sh
A
Fail
-
4\$\begingroup\$
3479is pretty fast! well done :) \$\endgroup\$Rob Audenaerde– Rob Audenaerde2017年10月30日 07:51:12 +00:00Commented Oct 30, 2017 at 7:51 -
\$\begingroup\$ Is there a specific version of bash required or something? On 4.4.12, typing
aimmediately gives meline 1: ((: r=15094100773N: value too great for base (error token is "15094100773N")and exits. \$\endgroup\$numbermaniac– numbermaniac2017年10月31日 00:35:38 +00:00Commented Oct 31, 2017 at 0:35 -
\$\begingroup\$ @numbermaniac The version of Bash shouldn't matter, but the one of
datemight. Mine is from GNU coreutils 8.23. What doesdate +%s%3Nprint on your system? \$\endgroup\$Dennis– Dennis2017年10月31日 00:38:58 +00:00Commented Oct 31, 2017 at 0:38 -
\$\begingroup\$ @Dennis it outputs
15094104833N- this is the built-indateutility on macOS, if that makes a difference. \$\endgroup\$numbermaniac– numbermaniac2017年10月31日 00:42:23 +00:00Commented Oct 31, 2017 at 0:42 -
1\$\begingroup\$ @numbermaniac BSD's
dateseems to be using strftime, which doesn't recognize%N. \$\endgroup\$Dennis– Dennis2017年10月31日 00:52:18 +00:00Commented Oct 31, 2017 at 0:52
Python 2 + getch, 116 bytes
import time,getch
t=[i+97-ord(getch.getche())and exit("Fail")or time.time()for i in range(26)]
print(t[-1]-t[0])*1e3
Thanks to ovs and ElPedro for fixing the code and saving 57 bytes.
Pascal (FPC), 176 bytes
Uses CRT,SysUtils;Var c:char;a:Real;Begin
for c:='a'to'z'do
if c=ReadKey then
begin Write(c);if c='a'then a:=Now;end
else
begin
Write('Fail');Halt;end;Write((Now-a)*864e5)
End.
Some tricks used in code for golfing:
- Use
Realas a shorter alternative toTDateTime, because as defined here,TDateTime=Double, which is floating-point type. - Instead of using
MilliSecondsBetweenfor calculating time gap, this code multiply the difference between two floating-point values by864e5, which works because of the way Free Pascal encodeTDateTimedescribed here.
Note:
ReadKeyfunction doesn't actually print the key on the console, so manual writing to console withWrite(c)is necessary.- TIO get a score near
0for typing the alphabet for obvious reason. - The program prints time in floating-point notation, I guess that's allowed.
-
\$\begingroup\$ Welcome to the site! \$\endgroup\$2017年10月30日 07:52:36 +00:00Commented Oct 30, 2017 at 7:52
-
\$\begingroup\$ You can save 1 byte by moving the
for c:='a'to'z'doto the same line asa:=Time;. \$\endgroup\$Ismael Miguel– Ismael Miguel2017年10月30日 21:05:04 +00:00Commented Oct 30, 2017 at 21:05 -
-
\$\begingroup\$ Why
86398338?? I can understand if you multiple 864e5 since there are 864e5 milliseconds in a day. but how does this magic number come? \$\endgroup\$tsh– tsh2017年10月31日 02:28:49 +00:00Commented Oct 31, 2017 at 2:28 -
\$\begingroup\$ @tsh I don't know either. By manual testing I happens to find that "magic" number, and I don't know how Pascal store
TDateTimeasDouble.864e5sounds more correct, I will fix the issues. \$\endgroup\$user75648– user756482017年10月31日 09:49:51 +00:00Commented Oct 31, 2017 at 9:49
SOGL V0.12, 35 bytes
"ζ¦F‘→I
]I!}Su[I:lzm≠?■しかくFail←z=?Suκ←
Try it Here! - click run, and enter the alphabet in the input box. Note that it may be a little laggy because SOGL only pauses for input every 100 executed tokens (and SOGL is quite slow). If that bothers you, run sleepBI=true in the console.
note: don't run this in the compatibility mode - it'll just loop forever.
Explanation:
"ζ¦F‘ push "inputs.value" (yes, that is a word in SOGLs english dictionary)
→ execute as JS, pushing the inputs contents
I named function I
] } do while POP is truthy
I execute I
! negate it - check if it's empty
Su push the current milliseconds since start
[ loop
I execute I
: duplicate the result
l let its length
zm mold the alphabet to that size
≠? if that isn't equal to one of the result copies
■しかくFail push "Fail"
← and exit, implicitly outputting that
z=? if the other copy is equal to the alphabet
Su push the milliseconds since start
κ subtract the starting milliseconds from that
← and exit, implicitly outputting the result
-
\$\begingroup\$ @HyperNeutrino I knew it would come in handy :p \$\endgroup\$dzaima– dzaima2017年10月29日 15:22:23 +00:00Commented Oct 29, 2017 at 15:22
-
\$\begingroup\$ Who would expect SOGL to be able to do that...by the way isn't "Fail" a word in the dictionary? \$\endgroup\$Erik the Outgolfer– Erik the Outgolfer2017年10月29日 15:42:19 +00:00Commented Oct 29, 2017 at 15:42
-
\$\begingroup\$ @EriktheOutgolfer well, SOGL was supposed to be an all-purpose language, but that didn't work out :p \$\endgroup\$dzaima– dzaima2017年10月29日 15:44:19 +00:00Commented Oct 29, 2017 at 15:44
-
\$\begingroup\$ BTW I don't know if this is completely valid, but then again I think that might be an issue with the interface and not the interpreter behind... \$\endgroup\$Erik the Outgolfer– Erik the Outgolfer2017年10月29日 15:48:01 +00:00Commented Oct 29, 2017 at 15:48
-
\$\begingroup\$ @EriktheOutgolfer yeah, I don't know how valid that is, I guess I'm waiting for the OP. At first I thought that this is something like the HTML answer, but it's quite different now that I look at it \$\endgroup\$dzaima– dzaima2017年10月29日 15:53:29 +00:00Commented Oct 29, 2017 at 15:53
Java, (削除) 404 (削除ここまで) (削除) 388 (削除ここまで) (削除) 354 (削除ここまで) (削除) 348 (削除ここまで) (削除) 320 (削除ここまで) 318 bytes
import java.awt.*;import java.awt.event.*;interface M{static void main(String[]a){new Frame(){{add(new TextArea(){{addKeyListener(new KeyAdapter(){long t,i=64;public void keyPressed(KeyEvent e){t=t>0?t:e.getWhen();if(e.getKeyChar()!=++i|i>89){System.out.print(i>89?e.getWhen()-t:"Fail");dispose();}}});}});show();}};}}
And here I thought Java Console was already verbose..
Since Java has no way to raw listen for key-presses in the Console a.f.a.i.k., I use a GUI with java.awt.
-78 bytes thanks to @OlivierGrégoire.
Explanation:
import java.awt.*; // Required import for Frame and TextField
import java.awt.event.*; // Required import for KeyAdapter and KeyEvent
interface M{ // Class
static void main(String[]a){ // Mandatory main-method
new Frame(){ // Create the GUI-Frame
{ // With an initialization-block
add(new TextArea(){ // Add an input-field
{ // With it's own initialization-block
addKeyListener(new KeyAdapter(){
// Add a KeyAdapter to the input-field
long t, // Long to save the time
i=64; // Previous character, starting at code of 'a' -1
public void keyPressed(KeyEvent e){
// Override the keyPressed-method:
t=t>0? // If `t` is already set:
t // Leave it the same
: // Else:
e.getWhen(); // Save the current time (== start the timer)
if(e.getKeyCode()!=++i
// As soon as an incorrect character is pressed,
|i>89){ // or we've reached 'z':
System.out.print(i>89?
// If we're at 'z':
e.getWhen()-t // Print the end-time in ms to the Console
: // Else (an incorrect character was pressed)
"Fail"); // Print "Fail" to the Console
dispose();} // And exit the application
} // End of keyPressed-method
}); // End of KeyAdapter
} // End of input-field initialization-block
}); // End of input-field
show(); // Initially show the Frame
} // End of Frame initialization-block
}; // End of Frame
} // End of main-method
} // End of class
Example gif of success: (Yes, I type the alphabet pretty slowly here..)
Note: This is an old gif. Current version no longer prints key-presses to Console. And it no longer prints the time with digits after the decimal point.
enter image description here
Example gif of fail:
Note: This is an old gif. Current version no longer prints key-presses to Console.
-
2\$\begingroup\$ impressive answer considering it has a gui! \$\endgroup\$AncientSwordRage– AncientSwordRage2017年10月30日 10:46:10 +00:00Commented Oct 30, 2017 at 10:46
-
1\$\begingroup\$ 388 bytes. I took the liberty to fix your code in addition to golfing because you used
setVisible(false)instead of exiting. \$\endgroup\$Olivier Grégoire– Olivier Grégoire2017年10月30日 12:04:13 +00:00Commented Oct 30, 2017 at 12:04 -
\$\begingroup\$ @OlivierGrégoire Thanks. Forgot about
showanddispose, which is even shorter thansetVisible. I almost never use Java's GUI.. And smart to use class-initialization instead of putting it in the main-method. I should remember that. \$\endgroup\$Kevin Cruijssen– Kevin Cruijssen2017年10月30日 12:23:57 +00:00Commented Oct 30, 2017 at 12:23 -
1\$\begingroup\$ @KevinCruijssen Thanks, and no problem ;-) Though some more general comments: you don't need to output the letters twice. Echoing is already provided by
TextField. Also, you could useTextAreainstead ofTextFieldto gain two bytes. Finally,KeyEventhas agetWhenmethod that gives the time between epoch and the event in milliseconds. Just need to use those instead ofSystem.nanoTime()to gain even more bytes. \$\endgroup\$Olivier Grégoire– Olivier Grégoire2017年10月30日 13:33:36 +00:00Commented Oct 30, 2017 at 13:33 -
1\$\begingroup\$ You're welcome! But I got it down further to 320 bytes. ;-) \$\endgroup\$Olivier Grégoire– Olivier Grégoire2017年10月30日 19:56:23 +00:00Commented Oct 30, 2017 at 19:56
C# (.NET Core), (削除) 245 + 13 (削除ここまで) (削除) 183 + 41 (削除ここまで) 177 + 41 bytes
+41 bytes for using System;using static System.Console.
Untested since I am on mobile and this does not run on TIO.
n=>{int c=ReadKey().KeyChar,x=0;try{if(c!=97)x/=x;var s=DateTime.Now;while(c<149)if(ReadKey().KeyChar!=c++)x/=x;Write((DateTime.Now-s).TotalMilliseconds);}catch{Write("Fail");}}
-
1\$\begingroup\$ +1 for creating a functioning program without being able to test it. Golfing: 1) One shorter way I've found to produce the exception:
int x=0;and then dox=1/x;. This should save 14 bytes. Unfortunately you needx. If you try to do1/0you get a Division by constant zero compiler error. 2) -5 bytes for combining the declaration ofcwith the firstReadKey. 3) Change the condition in the inneriftoReadKey!=++cand remove thec++;elsefor another -9 bytes. \$\endgroup\$raznagul– raznagul2017年10月30日 10:10:10 +00:00Commented Oct 30, 2017 at 10:10 -
\$\begingroup\$ @raznagul Thanks!
x=1/xcan be reduced tox/=x. And i addedusing static System.Console;to save some more bytes :) \$\endgroup\$Ian H.– Ian H.2017年10月30日 10:30:23 +00:00Commented Oct 30, 2017 at 10:30 -
\$\begingroup\$ Some more bytes can be saved by removing
iand usingcin the loop condition instead. \$\endgroup\$raznagul– raznagul2017年10月30日 10:53:50 +00:00Commented Oct 30, 2017 at 10:53
C# (.NET Core), (削除) 184+13=197 (削除ここまで) 173+13=186 bytes
()=>{var s=DateTime.Now;var i=97;while(i<123&&Console.ReadKey().KeyChar==i)if(i++<98)s=DateTime.Now;Console.Write(i>122?$"\n{(DateTime.Now-s).TotalMilliseconds}":"\nFail");}
Unfortunately TIO can't run this, but it's handy for getting byte count.
+13 for using System;
-1 by changing i==123 to i>122. I was tempted to make this i>'z'.
Acknowledgements
-10 bytes thanks to @raznagul
Ungolfed
()=>{
var s=DateTime.Now;
var i=97;
while(i<123&&Console.ReadKey().KeyChar==i)
if(i++<98)
s=DateTime.Now;
Console.Write(i>122?
$"\n{(DateTime.Now-s).TotalMilliseconds}":
"\nFail"
);
}
-
1\$\begingroup\$ You can save some bytes by moving the
ReadKeyto the loop condition so you can remove the firstifand thebreak. \$\endgroup\$raznagul– raznagul2017年10月30日 10:50:23 +00:00Commented Oct 30, 2017 at 10:50
Node.js, (削除) 240 (削除ここまで) 213 bytes
require('readline',{stdin:i,stdout:o,exit:e}=process).emitKeypressEvents(i)
w=s=>o.write(s)
n=0
i.on('keypress',c=>w(c)&&c.charCodeAt()-97-n?e(w(`
Fail`)):!n++?s=d():n>25&&e(w(`
`+(d()-s)))).setRawMode(d=Date.now)
EDIT: Saved 27 bytes thanks to Jordan
Ungolfed version:
const readline = require('readline')
let index = 0
let start
readline.emitKeypressEvents(process.stdin)
process.stdin.setRawMode(true)
process.stdin.on('keypress', character => {
process.stdout.write(character )
// Lookup character in ASCII table
if (character !== String.fromCharCode(97 + index) {
process.stdout.write('\nFail')
process.exit()
}
index++
if (index === 1) {
start = Date.now()
}
if (index === 26) {
process.stdout.write('\n' + (Date.now() - start))
process.exit()
}
})
C (gcc), 303 bytes
Works on *nix systems. Standalone code removing the current terminal's canonical mode to allow reading characters without waiting for newlines:
/!\ Running this program will make the terminal almost unusable.
#import <stdlib.h>
#import <termios.h>
#define x gettimeofday(&t,0)
#define r t.tv_sec*1000+t.tv_usec/1000
c,i=97;main(){long s=0;struct termios n;struct timeval t;cfmakeraw(&n);n.c_lflag|=ECHO;tcsetattr(0,0,&n);for(;i<'d';){c=getchar();if(c!=i++)puts("\nFail"),exit(0);x;s=s?:r;}x;printf("\n%ld",r-s);}
Ungolfed and commented:
// needed in order to make gcc aware of struct termios
// and struct timeval sizes
#import <stdlib.h>
#import <termios.h>
// gets the time in a timeval structure, containing
// the number of seconds since the epoch, and the number
// of μsecs elapsed in that second
// (shorter than clock_gettime)
#define x gettimeofday(&t,0)
// convert a timeval structure to Epoch-millis
#define r t.tv_sec*1000+t.tv_usec/1000
// both integers
// c will contain the chars read on stdin
// 97 is 'a' in ASCII
c,i=97;
main(){
long s=0; // will contain the timestamp of the 1st char entered
struct timeval t; // will contain the timestamp read from gettimeofday
// setting up the terminal
struct termios n;
cfmakeraw(&n);//create a raw terminal configuration
n.c_lflag|=ECHO;//makes the terminal echo each character typed
tcsetattr(0,0,&n);//applies the new settings
// from 'a' to 'z'...
for(;i<'{';){
// read 1 char on stdin
c=getchar();
// if int value of the input char != expected one => fail&exit
if(c!=i++)puts("\nFail"),exit(0);
// macro x: get current timestamp
x;
// if not already set: set starting timestamp
s=s?:r;
}
// get end of sequence timestamp
x;
// prints the end-start timestamps difference
printf("\n%ld",r-s);
}
Alternative solution (218 bytes):
If configuring the terminal beforehand is allowed, then we can get rid of the portion of code handling that part.
Here is the same code without terminal manipulation:
#import <stdlib.h>
#define x gettimeofday(&t,0)
#define r t.tv_sec*1000+t.tv_usec/1000
c,i=97;main(){long s=0;struct timeval t;for(;i<'{';){c=getchar();if(c!=i++)puts("\nFail"),exit(0);x;s=s?:r;}x;printf("\n%ld",r-s);}
To make it work:
$ gcc golf.c
$ stty -icanon
$ a.out
runtime example: enter image description here
Commodore BASIC v2 - 113 bytes
Capital letters must be shifted.
Thanks to Felix Palmen for pointing out some typos, specs
try it
0d=64
1on-(f=26)gO5:gEa$:ifa$=""tH1
2iff=0tHt=ti
3f=f+1:ifa$<>cH(d+f)tH6
4?cH(14)a$;:gO1
5?:?(ti-t)/60*1000:eN
6?"Fail"
-
\$\begingroup\$ Click edit to see the corrected markdown code. \$\endgroup\$Maya– Maya2017年10月31日 14:26:25 +00:00Commented Oct 31, 2017 at 14:26
-
\$\begingroup\$ Welcome to the site! Could you add a link to an interpreter (if one exists), so that others can test your code? \$\endgroup\$2017年10月31日 14:37:34 +00:00Commented Oct 31, 2017 at 14:37
-
\$\begingroup\$ Well, this uses the system IRQ (
TIis incremented in it) I deemed unsuitable for its lack of precision, but I guess it's fair game here because there's just no way to do better in BASIC :) Still, pasting this in vice, I get a syntax error in1-- any help? \$\endgroup\$Felix Palmen– Felix Palmen2017年10月31日 15:51:34 +00:00Commented Oct 31, 2017 at 15:51 -
\$\begingroup\$ Figured it out myself, you have a typo in line one, should be
1on-(f=26)gO4:gEa$:ifa$=""tH1Nitpicks: 1.) output is on the same line, 2.) output is all-caps -- I think you should fix those, won't take many bytes anyways :) \$\endgroup\$Felix Palmen– Felix Palmen2017年10月31日 15:56:42 +00:00Commented Oct 31, 2017 at 15:56 -
\$\begingroup\$ Adressed the issues, any typos left? \$\endgroup\$user75079– user750792017年10月31日 17:19:46 +00:00Commented Oct 31, 2017 at 17:19
Mathematica (notebook expression), 248 bytes
DynamicModule[{x={},s=0,t=0},EventHandler[Framed@Dynamic[If[x=={"a"}&&s<1,s=SessionTime[]];Which[x==a,If[t==0,t=SessionTime[]-s];1000t,x==a~Take~Length@x,""<>x,1>0,"Fail"]],Table[{"KeyDown",c}:>x~AppendTo~CurrentValue@"EventKey",{c,a=Alphabet[]}]]]
How it works
DynamicModule[{x={},s=0,t=0},
EventHandler[
Framed@Dynamic[
If[x=={"a"} && s<1,s=SessionTime[]];
Which[
x==a,If[t==0,t=SessionTime[]-s];1000t,
x==a~Take~Length@x,""<>x,
1>0,"Fail"]],
Table[{"KeyDown",c}:>x~AppendTo~CurrentValue@"EventKey",
{c,a=Alphabet[]}]]]
A DynamicModule with an EventHandler that responds to lowercase letter keypresses. The variables x, s, and t hold the letters pressed so far, the start time, and the end time, respectively. As soon as we notice x being equal to {"a"}, we start the time; we display either the total time spent, or the string built so far, or "Fail" depending on which condition is met.
We could save another byte with t<1 rather than t==0 if we can assume that nobody is fast enough to type the alphabet in less than one second :)
If you're trying this out in a Mathematica notebook, keep in mind that you have to click inside the frame before your keypresses will be registered. (This is the reason that we need the frame to begin with; if Framed is not there, then the entire object selected changes when a key is pressed, so it stops being selected and you'd have to click again.)
MSX-BASIC, 126 characters
1C=97:GOSUB3:TIME=0
2IFASC(C$)<>CTHEN?"Fail":ENDELSEIFC=122THEN?TIME*20:ENDELSEC=C+1:GOSUB3:GOTO2
3C$=INKEY$:IFC$=""GOTO3
4RETURN
TIME is an internal MSX-BASIC variable that increases by one every 20 milliseconds.
Perl 5, (削除) 79 (削除ここまで) 93 +31 (-MTerm::ReadKey -MTime::HiRes=time) bytes
$|=1;map{ReadKey eq$_||exit print"
Fail";$s||=time}a..z;print$/,0|1e3*(time-$s)
$|=1 is not sufficient to set terminal in raw mode, stty -icanon should be run before or
ReadMode 3;map{ReadKey eq$_||exit print"
Fail";print;$s||=time}a..z;print$/,0|1e3*(time-$s)
to see characters in the terminal after running command : stty echo or stty echo icanon
-
\$\begingroup\$ Good old
ReadKey! You can save a few bytes here and there,1e3for1000,$s||=timeand if you set$sfirst and then callReadKey, you can swap out themapto a postfixfor. I'd like to saydieinstead ofexit print, but I think you're right there... I tinkered withprintf"\n%i"but that ended up larger, and I thought about using$-instead of$s, but that was stupid! :) \$\endgroup\$Dom Hastings– Dom Hastings2017年10月30日 16:33:50 +00:00Commented Oct 30, 2017 at 16:33 -
\$\begingroup\$ @DomHastings, thank you for your help, I could save 4 bytes, but i added 5 bytes to set unbuffered input
$|=1;, also $s||=time can't be swap out the map because timer must start after first key pressed, anddiewould echoFailon stderr instead of stdout. \$\endgroup\$Nahuel Fouilleul– Nahuel Fouilleul2017年10月31日 07:50:42 +00:00Commented Oct 31, 2017 at 7:50 -
\$\begingroup\$ Happy to help, hope you don't mind me offering ideas! Yeah, it's s shame,
exit printis so long! Sorry, I don't think I explained my thought for theforproperly:$s||=time,ReadKey eq$_||exit print" Fail"for a..zshould work I think... Maybe even$|=$s||=...or$|=map...if you prefer that approach! Think you pretty much nailed it though! \$\endgroup\$Dom Hastings– Dom Hastings2017年10月31日 08:31:38 +00:00Commented Oct 31, 2017 at 8:31 -
\$\begingroup\$
$|=map..doesn't set unbuffered input in new terminal (I had the error when removing, ReadMode 3, because I was testing in the same session), and$s||=timebefore first ReadKey would start timer too early \$\endgroup\$Nahuel Fouilleul– Nahuel Fouilleul2017年10月31日 09:42:22 +00:00Commented Oct 31, 2017 at 9:42 -
\$\begingroup\$ Ahh, I misunderstood, I get it now, didn't wait long enough after starting to script to check that... :) Shame about
$|, but again, it's storing after the loop which is too late! You're one step ahead! \$\endgroup\$Dom Hastings– Dom Hastings2017年10月31日 09:46:53 +00:00Commented Oct 31, 2017 at 9:46
APL (Dyalog), SBCS, 114 (削除) 153 (削除ここまで) bytes
Using a GUI form to handle keypress events:
t←⍬
a←819⌶⎕A
f←{⍬≡t:f ⍵⊣t⊢←⎕AI⋄⊃a≠⍞←3⊃⍵:⎕EX⎕A⊣⎕←'Fail'⋄'z'=a~←⊃a:⎕←3⊃⎕AI-t}
⎕DQ⎕A⎕WC'Form'('Event' 'KeyPress' 'f')
(Golfed by Adám; I think it would be odd for him to be awarding a bounty for an answer which is now mostly his golf rewrite, so that's here, and my original is below. This version handles the "exit on failure" part of the spec, too.]
t←⍬
a←(819⌶)⎕A
∇w
'W'⎕WC'Form'('Event' 'KeyPress' 'f')
⎕DQ'W'
∇
∇f e
{26=≢a:t⊢←⎕TS}⍬
{e[3]=1↑a:{⍞←1↑a⋄a⊢←1↓a}⍬⋄⎕←'Fail'}⍬
{0=≢a:⎕←60 60 1e3⊥4↓⎕TS-t}⍬
∇
w
Image of it (the first posted version) in use, Dyalog APL 17.1:
Animated screen capture of this code working in Dyalog APL 17.1
Explanation.
It's a function w which loads a GUI form and adds an event handler to it, and starts listening for events, and the call back which handles the alphabet.
Lambda functions are used to get guard pattern matching, instead of longer :If ⋄ cond ⋄ code ⋄ :Else ⋄ code ⋄ :EndIF syntax. Guards are {cond: code} pattern, and the {}⍬ pattern is calling a function on an empty numeric vector just to make it run
t←⍬ ⍝ Variable for the time of starting typing
a←(819⌶)⎕A ⍝ Variable for lowercase alphabet,
cast from uppercase with I-beam 819
⍝ Function "w" makes window of type 'Form', called 'W', with event handler.
⍝ Callback function "f", and starts event loop.
∇w
'W'⎕WC'Form'('Event' 'KeyPress' 'f')
⎕DQ'W'
∇
⍝ event handler function "f" takes event "e"
∇f e
{26=≢a:t⊢←⎕TS}⍬ ⍝ lambda function (dfn)
⍝ checks if there are 26 letters,
⍝ (i.e. started typing) starts the timer.
⍝ "t" is initialised first, for global scoping.
{e[3]=1↑a:{⍞←1↑a⋄a⊢←1↓a}⍬⋄⎕←'Fail'}⍬ ⍝ guard, if event[3] (key pressed)
⍝ is the next alphabet letter (first of "a")
⍝ print 1 from "a", drop 1 from "a"
⍝ else print "Fail".
{0=≢a:⎕←60 60 1e3⊥4↓⎕TS-t}⍬ ⍝ guard, if all the letters are gone,
⍝ subtract current timestamp from stored,
⍝ drop 4 elements (year, month, day, hour)
⍝ base-convert min, sec, ms to pure ms
⍝ and print.
∇
⍝ run it by calling function "w"
w
C#, (削除) 154 (削除ここまで) 152 + 13 = 165 bytes
Saved 2 bytes thanks to Ayb4btu's comments
x=>{
long t=0,c=97;
for(;Console.ReadKey().KeyChar==c++&&c<123;t=t<1?DateTime.Now.Ticks:t);
Console.Write(c>122?"\n"+(DateTime.Now.Ticks-t)/1e4:"\nFail");
}
The code above has whitespace to make it fit in SE without a scrollbar. Whitespace isn't part of the byte count
and 13 bytes for using System;
It's similar to Ayb4btu's version but with the following differences:
Storing datetime as a long, allows us to make
ca long also, and short cut the declarationLoop doesn't need a separate break
It's not actually shorter to use
$"interpreted strings"versus adding a needed "\n" onto the milliseconds to make it a string for the inline ifUsing a
forloop sometimes allows us to save chars over a while, though I think this one wouldn't save over the equivalentwhile
From Ayb4btu:
s=s==0can becomes=s<1, andc==123can becomec>122
Ungolfed
long t=0,c=97;
for (; //no loop vars declared
Console.ReadKey().KeyChar == c++ && c < 123; //loop test
t = t < 1 ? DateTime.Now.Ticks : t //post-loop assigns
) ; //empty loop body!
//now just need to turn ticks into millis, 10,000 ticks per millis
Console.Write(c>122?"\n"+(DateTime.Now.Ticks-t)/1e4:"\nFail");
-
\$\begingroup\$ Nice solution with how you used
DateTime. You can save a couple more bytes by changings=s==0tos=s<1(counting on the fact that s will not be negative), and changingi==123toi>122. \$\endgroup\$Ayb4btu– Ayb4btu2017年10月31日 00:20:40 +00:00Commented Oct 31, 2017 at 0:20 -
\$\begingroup\$ Also, has this been tested? As I found that
i<123had to go before theReadKey(), otherwise it waits for another character after z before displaying the time. \$\endgroup\$Ayb4btu– Ayb4btu2017年10月31日 00:41:46 +00:00Commented Oct 31, 2017 at 0:41 -
\$\begingroup\$ Odd, because at the end of the alphabet,
zshould mean readkey.keychar returns 122 when the user types z, c is also 122, hence'z' == 122succeeds, c is then incremented, then c (now 123) is tested againstc<123and fails, stopping the loop .. ? \$\endgroup\$Caius Jard– Caius Jard2017年10月31日 10:10:42 +00:00Commented Oct 31, 2017 at 10:10 -
\$\begingroup\$ You're right, I missed the
c++increment when I was looking at it. However, I just tried it and when I type inabcdefghijklmnopqrstuvwxysit gives me a time instead of failing. I believe it is becausecstill increments even though theKeyCharcheck fails, therefore passing thec>122check. \$\endgroup\$Ayb4btu– Ayb4btu2017年10月31日 19:25:30 +00:00Commented Oct 31, 2017 at 19:25 -
\$\begingroup\$ Good point - maybe moving the ++ to the c<123 check will keep the bytecount the same and prevent the c from incrementing if the last char is wrong - no time to debug right now, but I'll take a look at it! cheers :) \$\endgroup\$Caius Jard– Caius Jard2017年11月01日 18:31:51 +00:00Commented Nov 1, 2017 at 18:31
Aceto, 70 bytes
d'|d 't9
$z=p zp1
!= >#v
d, 1 +
cTpaXpn3
Io$'p"*F
|'!=ilnu
@ad,aF"
I start by setting a catch mark and mirroring horizontally(@|), if the value on the stack is truthy. It isn't initially, and later always will be. We will jump back here later if a wrong key is entered.
Next, we push an a on the stack ('a), then we duplicate it and read a single character from the user (d,). If the two characters are not equal (=!), we "crash" ($) and jump back to the catch mark.
Otherwise, we push another "a" and print it, then we set the current time ('apT).
Then we enter our "main loop": We "increment" the current character and "increment" the character ('apToIc), then we duplicate it, read a new character, compare it, and "crash" if it the characters aren't identical (d,=!$).
If we didn't crash, we compare the current character to "z" (d'z=|), if it isn't equal, we print the character, then we push a 1 and jump "conditionally" (in this case: always) to the only o in the code (the begin of our main loop).
If it was equal to z, we mirrored horizontally to some empty space on top. We print "z", then push the current time (minus the starting time; t) and then multiply the number 1000 (gotten by raising 10 to the third power; 91+3F) by it (because we get seconds, not milliseconds). Then we print a newline, the time, and exit (pX).
If we ever crash (bad input by the user), we jump all the way to the beginning. Since we will now have some truthy value on the stack, we will mirror horizontally onto the u, which reverses the direction we're moving in. n prints a newline character, then we push "Fail" on the stack, print it, and exit (pX).
Processing.org (削除) 133 (削除ここまで) 142
first code didn't exit
char k=97;int m;void draw(){if(key==k){m=m<1?millis():m;print(key=k++,k>122?"\n"+(millis()-m):"");}if(m>0&&key!=k-1){print("\nFail");exit();}}
GCC, windows, 98 bytes
t;main(i){for(;i++<27;t=t?:clock())if(95+i-getche())return puts("\nFail");printf("\n%d",clock()-t);}
Requires no instantly input for the first key
Ruby: 194 bytes
require 'io/console'
a=[*"a".."z"]
c=0
s=
loop do
i=STDIN.getch
if i==a[c]
print i
s=Time.now if i=='a'
else
puts "\nFail"
exit
end
if i=='z'
puts "\n"+((Time.now-s)*1000).to_s
exit
end
c+=1
end
Python 3, 107 bytes
from time import*;x=time();a=input();print((time()-x)*1000 if a=="abcdefghijklmnopqrstuvwxyz" else "Fail");
Outputs a floating point number. Relies on lowercase alphabet.
Java (Android), 709 bytes
And here I thought Java Console was already verbose.
Imagine complaining about AWT :omegalul:
package a;import android.widget.*;import android.text.*;public class Z extends android.app.Activity{long g;long f(){return System.currentTimeMillis();}public void onCreate(android.os.Bundle b){super.onCreate(b);EditText t=new EditText(this);t.setSingleLine();t.setInputType(144);t.addTextChangedListener(new TextWatcher(){public void beforeTextChanged(CharSequence s,int a,int b,int c){if(g<1)g=f();}public void onTextChanged(CharSequence s,int a,int b,int c){}public void afterTextChanged(Editable s){}});t.setOnEditorActionListener((x,y,z)->{t.setError((""+t.getText()).equals("abcdefghijklmnopqrstuvwxyz")?f()-g+"":"Fail");return true;});addContentView(t,new android.view.ViewGroup.LayoutParams(-1,-2));}}
Commented version:
// Android requires all Activities to be in a package.
package a;
// EditText
import android.widget.*;
// TextWatcher, Editable
import android.text.*;
// just use full package names for the rest
// yes, we need this entire signature.
public class Z extends android.app.Activity {
// timer
long g;
// Wrapper because it is shorter than calling this behemoth
// Gets the current time
long f() {
return System.currentTimeMillis();
}
// Activity entry point
public void onCreate(android.os.Bundle b) {
super.onCreate(b);
// Android Studio doesn't have var. They abandoned Java 10 in favor of Kotlin.
// geeeeeeeeee I wonder why ANYone would abandon programming for Android in Java... :P
EditText t = new EditText(this);
// This sets the enter key to a submit key, allowing us to catch OnEditorAction
t.setSingleLine();
// no autocomplete 4 u
// InputType.VISIBLE_PASSWORD
t.setInputType(144);
// The main reason this is so verbose is because the requirement needs us to start
// timing on the first character TYPED. It would be much easier to add an onClick or onFocus
// listener instead, but nooooo. :(
t.addTextChangedListener(new TextWatcher() {
// why
public void beforeTextChanged(CharSequence s, int a, int b, int c) {
// Start our timer the first time the user types something.
if (g < 1) g = f();
}
// three
public void onTextChanged(CharSequence s, int a, int b, int c) {
}
// methods?
public void afterTextChanged(Editable s) {
}
});
// When they hit submit, verify using the obvious way.
// I _may_ be able to verify in TextWatcher, but TextWatcher is not char by char. IDK, I haven't experimented with it yet.
t.setOnEditorActionListener((x, y, z) -> {
// Show the result via setError, which is on a new line. :)
t.setError(("" + t.getText()).equals("abcdefghijklmnopqrstuvwxyz") ? f() - g + "" : "Fail");
return true;
});
// Append to the root view.
// -1 == LayoutParams.MATCH_PARENT
// -2 == LayoutParams.WRAP_CONTENT
addContentView(t, new android.view.ViewGroup.LayoutParams(-1, -2));
}
}
Edit: I have gotten very good at this by the way, look at my mad skills.
Explore related questions
See similar questions with these tags.
Failwithout a heading newline? (e.g.abdFail\norabd Fail\n)) \$\endgroup\$Failor milliseconds) must be on a new line, like in the example. Most answers already assume this. \$\endgroup\$