Skip to Content
Course content

432: Building a Typing Speed Test

Click on the "Edit" button in the top corner of the screen to edit your slide content.

When you first decide to build a typing speed test, the impulse is to keep it as simple as possible: show a sentence, start a timer, wait for the user to hit Enter, and stop the timer. It feels like a complete solution, but if you've ever used a professional typing tool, you know that "speed" is a surprisingly nuanced metric. If we just measure the time between the prompt appearing and the Enter key being pressed, we aren't measuring typing speed—we're measuring the user's reaction time plus their typing speed.

The "Input-and-Pray" Approach

In a naive implementation, you'd probably do something like this. I've seen a lot of juniors start here because it's intuitive.

import time

target_text = "The quick brown fox jumps over the lazy dog"
print(f"Type this: {target_text}")

start_time = time.time()
user_input = input("> ")
end_time = time.time()

duration = end_time - start_time
words = len(user_input) / 5
wpm = words / (duration / 60)
print(f"Your speed: {wpm:.2f} WPM")

This works, technically, but it's fragile. First, it uses time.time(), which is "wall-clock time." If the system clock updates via NTP while your user is typing, your duration could actually be negative or wildly inaccurate. More importantly, this approach treats every single keystroke as a success. If the user mashes their keyboard for ten seconds and happens to hit Enter, the program reports a massive WPM because it only cares about the length of the string and the time elapsed.

Why Precision and Validation Matter

To make this professional, we need to move from time.time() to time.perf_counter(). I always use perf_counter for benchmarking because it's a monotonic clock—it never goes backward and has much higher resolution. It's designed specifically for measuring durations.

But the real upgrade is in how we calculate the WPM. In the industry, "Gross WPM" is just raw speed, but "Net WPM" is what actually matters. Net WPM subtracts errors. If you type 100 words per minute but 20 of them are misspelled, you aren't actually typing at 100 WPM; you're typing at 80 WPM with a lot of mistakes. We need to iterate through the strings and count only the characters that match the target text at the correct position.

Building a Robust Measurement Loop

Instead of just trusting the length of the input, we should compare the user's attempt against the target character-by-character. This allows us to calculate accuracy and "Net WPM" separately. Here is how I would structure this to be more resilient.

import time

def calculate_speed(target, user_attempt):
    # Use perf_counter for high-resolution timing
    start = time.perf_counter()
    
    # We assume the user is typing now
    # In a real GUI this would be an event, but for CLI, we capture the input
    input("> ") 
    end = time.perf_counter()
    
    duration_minutes = (end - start) / 60
    
    # Calculate correct characters
    correct_chars = 0
    for t_char, u_char in zip(target, user_attempt):
        if t_char == u_char:
            correct_chars += 1
            
    # Standard WPM definition: (correct characters / 5) / time in minutes
    net_wpm = (correct_chars / 5) / duration_minutes
    accuracy = (correct_chars / len(target)) * 100 if target else 0
    
    return net_wpm, accuracy

# Example usage
text = "The quick brown fox jumps over the lazy dog"
print(f"Type this:\n{text}")
# In a real scenario, we'd pass the actual input captured
# For this logic demo, let's assume the user typed 'The quick brown fox'
# and spent 5 seconds doing it.

Notice the use of zip(). It's the cleanest way to pair the target characters with the user's input. By stopping at the length of the shortest string, we avoid IndexError if the user stops halfway or types too much. This approach gives us a real metric: if the user types gibberish, their correct_chars will be zero, and their Net WPM will be zero, regardless of how fast they hit the keys. That's the difference between a toy and a tool.




📋 Practical Task

Exercise: Implementing a Penalty-Based Accuracy Tracker

Build a Python script that implements a typing test with a "penalty" system. Your program should:

  • Define a target sentence of at least 10 words.
  • Use time.perf_counter() to measure the time it takes for the user to type the sentence.
  • Calculate Gross WPM (total characters typed / 5 / time) and Net WPM (correct characters / 5 / time).
  • Implement a "Penalty" feature: For every character that is incorrect, subtract an additional 2 seconds from the user's "effective time" (or simply deduct from the final WPM score) to simulate the time it would take to go back and fix the error.
  • Print a final report showing: Total Time, Gross WPM, Net WPM, and Accuracy Percentage.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.