1

I am still a newbie when it comes to python coding so please be kind! I have been suggested to use threading to run both the 'timer' and the for/while loop together, but I am not sure if it's necessary or how to implement it at all.

Being a beginner it looks as though threading is still a bit far from my reach at least for now. My goal here is to have an extensive list of random words that the user must input and at the end I'll calculate their WPM and accuracy (I'll expand the list later).

What I don't understand is why the while loop doesn't stop even though the program seems to reach the ''time's up'' part.. how can I fix this code?

import datetime

sentence_to_match = ['hello', 'darkness', 'my', 'old', 'friend', 'fox']
instructions = 'You have 1 minute to type all the words you can'
print(instructions)
start_test = input('Press y to start or n to exit the test : ').lower()

wrong = []
correct = []
total = []

if start_test == 'y':
    x = 60
    currenttime = datetime.datetime.now()
    endtime = currenttime + datetime.timedelta(seconds=x)
    print(currenttime)
    print(endtime)

    while currenttime < endtime:
        now_time = datetime.datetime.now()
        print(now_time)
        if now_time >= endtime:
            print('Time is up!')
            break
        for word in sentence_to_match:
            print(word)
            matching_text = input()

            total.append(word)

            if matching_text == word:
                correct.append(word)
            elif matching_text != word:
                wrong.append(word)

print(f'You typed a grand total of {len(total)} words!')
print(f'These are all the words you have spelled correctly : {correct}')
print(f'These are all the words you have spelled wrong : {wrong}')
print(f'This is your WPM {len(total) / 5 / 60} !')

  • What have you tried already? There is some very good [documentation](https://docs.python.org/3/library/threading.html) that is recommended to read. StackOverflow is not a code writing service. – Xiddoc Dec 25 '22 at 15:28
  • from the description of the problem, a solution would not require threading. In fact the best approach would be to use the `time` module. – D.L Dec 25 '22 at 17:57
  • My apologies I think the wording of my title sounds very weird, English is not my first language. I have only tried watching some videos about threading on Youtube and by the looks of it , I thought it was outside of my 'league' , with this post I only meant to understand why my loop was not behaving the way I wanted. I understand StackOverflow is not a code writing service, I guess I'll learn how to use this website at some point too. Thank you for the link to the documentation though, I'll not give up on threading just yet! – TwinkleTwinkle Dec 25 '22 at 19:02

1 Answers1

0

The reason your loop doesn't stop is that you check if the time is elapsed outside of the sentence loop. The following code should work:

import datetime

sentence_to_match = ['hello', 'darkness', 'my', 'old', 'friend', 'fox']
instructions = 'You have 1 minute to type all the words you can'
print(instructions)
start_test = input('Press y to start or n to exit the test : ').lower()

wrong = []
correct = []
total = []

if start_test == 'y':
    x = 10
    game_active = True
    currenttime = datetime.datetime.now()
    endtime = currenttime + datetime.timedelta(seconds=x)
    
    while game_active:
        for word in sentence_to_match:
            print(word)
            matching_text = input()
            now_time = datetime.datetime.now()
            if now_time >= endtime:
                print('Time is up!')
                game_active = False
                break
            else:
                total.append(word)
                if matching_text == word:
                    correct.append(word)
                elif matching_text != word:
                    wrong.append(word)

print(f'You typed a grand total of {len(total)} words!')
print(f'These are all the words you have spelled correctly : {correct}')
print(f'These are all the words you have spelled wrong : {wrong}')
print(f'This is your WPM {60 * len(correct) / x} !') # convert wps to wpm

Moreover, this code will not count the last word typed when the time is up.

Edit: I've just written a version of the program using the pynput library to make the program terminate even if the user is typing a word. This avoids interrupting the input function by force. I think this is what you need rather than the threading library. Here is the code:

import time
from itertools import cycle
from pynput import keyboard

sentence_to_match = ['hello', 'darkness', 'my', 'old', 'friend', 'fox']

sentence_loop = cycle(sentence_to_match)

instructions = 'You have 1 minute to type all the words you can'
print(instructions)
start_test = input('Press y to start or n to exit the test : ').lower()

user_input = []
user_words = []
wrong = []
correct = []
total = []

def on_press(key):
    global user_input
    
    if key == keyboard.Key.backspace: 
        # remove last letter from user_input and from printed text
        if user_input != []:
            user_input.pop()
            print('\b', end='')
        return
    elif key == keyboard.Key.space:
        # if user pressed space bar
        char = ' '
    else:
        try:
            # if user typed a letter
            char = key.char
        except AttributeError:
            # if user typed something else, don't do anything
            return
    
    user_input.append(char)
    print(char, end='')

listener = keyboard.Listener(on_press=on_press)

if start_test == 'y':
    x = 10
    start_time = time.time()
    end_time = start_time + x
    
    listener.start()
    
    # print the first word
    word = next(sentence_loop)
    print('\r' + 15*' ', end='')
    print('\r' + word, end=' ')
    
    while time.time() < end_time:
        if user_input != [] and user_input[-1] == ' ': # if user typed space
            print()
            last_user_word = ''.join(user_input[:-1]) # remove the last space
            user_words.append(last_user_word)
            if last_user_word == word:
                correct.append(last_user_word)
            else:
                wrong.append(last_user_word)
            user_input = []
            
            # print the next word and repeat
            word = next(sentence_loop)
            print('\r' + 15*' ', end='')
            print('\r' + word, end='')
            
        time.sleep(0.1)
    
    print('\ndone!\n')
    listener.stop()

print(f'You typed a grand total of {len(user_words)} words!')
print(f'These are all the words you have spelled correctly : {correct}')
print(f'These are all the words you have spelled wrong : {wrong}')
print(f'This is your WPM {60 * len(correct) / x} !')

I hope this helps!

Nonlinear
  • 684
  • 1
  • 12
  • I didn't expect such a quick answer during Christmas , I understand my mistake now though, thank you a lot sir! I honestly didn't know about Pynput but it looks very interesting, I'll try looking a bit into it. Your version works a lot better, It's definitely more comprehensive, thank you once again. – TwinkleTwinkle Dec 25 '22 at 18:52