Reflex
Reflex is a simple reaction time tester.
Only the Return key is used in interaction with
the program. When pressing Return for the first time,
the user is instructed to Wait...; after a few seconds,
the program says Go! and the user must
strike Return again as fast as possible. The elapsed
time is displayed and the test can be repeated.
Here is the program:
module Reflex where
import POSIX
import RandomGenerator
data State = Idle | Waiting Msg | Counting
format t = show (secOf t) ++ '.' : fracs ++ " secs"
where n = microsecOf t `div` 10000
fracs = if n<10 then '0':show n else show n
reflex env = class
print str = env.stdout.write (str ++ "\n")
tmr = new timer
gen = new baseGen (microsecOf env.startTime)
state := Idle
enter _ = action
case state of
Idle -> r <- gen.next
waitingTime = sec 2 + millisec (r `mod` 2000)
msg <- after waitingTime action
tmr.reset
print "Go!"
state := Counting
print "Wait..."
state := Waiting msg
Waiting msg -> abort msg
print "Cheat!!!"
state := Idle
Counting -> t <- tmr.sample
print (format t)
state := Idle
result action
env.stdin.installR enter
print "Press return to start"
root = newRoot reflex
Comments to the code:
- The program uses a timer object tmr, which is
an instance of the primitive class timer. A timer
can be can be reset and sampled; in
the latter case it returns the Time elapsed since it was
last reset.
- It also makes use of a random number generator to
produce a random waitingTime between two and four seconds
for the Waiting state.
- The program is a simple State machine, where
state changes are triggered in two ways:
- The user strikes Return; the case statement in enter
describes the corresponding actions and state changes. Note that
a strike in the Waiting state is a user error;
hence the user is accused of cheating.
- The Waiting time has elapsed and
the action that was scheduled at the previous keystroke is
invoked.
- The Waiting state carries one more piece of information in the
form of a Msg tag, created when the Go message was scheduled.
If the user cheats, that scheduled action must be aborted;
the message tag is needed as argument to the abort function.
- The time displayed is formatted with two decimals, using
auxiliary function format.
- This program should preferrably be executed in some simpler
environment with only a display, one or two buttons and perhaps some
sound-making device. The program would have to be modified
accordingly to import the proper environment module instead of POSIX
and to call the methods of that environment.