Typing training with GUI in Python This script allows you to practice your typing skills, as soon as you finish typing a new word appears for a non-stop typing experience. The code has in memory the top 100 words as per the Pareto Principle and Zipf's Law, of these, the top 10 are more common than the rest.

To start, type start.

Tested in Linux, Python 3.4 but should work in any version in any OS. 

try:
    import tkinter as tk
except ImportError:
    import Tkinter as tk
import random

FONT = (None, 50)
WORDS = ['the', 'be', 'to', 'of', 'and', 'a', 'in', 'that', 'have', 'I', 'it', 'for', 'not', 'on', 'with', 'he', 'as', 'you', 'do', 'at', 'this', 'but', 'his', 'by', 'from', 'they', 'we', 'say', 'her', 'she', 'or', 'an', 'will', 'my', 'one', 'all', 'would', 'there', 'their', 'what', 'so', 'up', 'out', 'if', 'about', 'who', 'get', 'which', 'go', 'me', 'when', 'make', 'can', 'like', 'time', 'no', 'just', 'him', 'know', 'take', 'people', 'into', 'year', 'your', 'good', 'some', 'could', 'them', 'see', 'other', 'than', 'then', 'now', 'look', 'only', 'come', 'its', 'over', 'think', 'also', 'back', 'after', 'use', 'two', 'how', 'our', 'work', 'first', 'well', 'way', 'even', 'new', 'want', 'because', 'any', 'these', 'give', 'day', 'most', 'us']

new_word = lambda: random.choice(random.choice((WORDS[0:len(WORDS)//10], WORDS)))

root = tk.Tk()
root.title("Typing trainer")

text_to_copy = tk.Label(root, text = "start", font=FONT)
text_to_copy.pack()

typing_ground = tk.Entry(root, font=FONT)
typing_ground.pack()

points = tk.Label(root, text = "Score: 0", font=FONT)
points.pack()

def if_equal_delete_and_take_other_phrase(ev):
    if text_to_copy.cget("text") == typing_ground.get():
        typing_ground.delete(0, 'end')
        text_to_copy['text'] = new_word()
        points['text'] = "Score: " + str(int(points['text'].split(': ')[-1]) + 1)

root.bind('&lt;Key&gt;', if_equal_delete_and_take_other_phrase)

root.mainloop()
I love seeing functionality like this packed so concisely. Really nice job.

UX

When I ran your code, it ran fine, but a usability problem is that the text entry box does not have focus, you have to click on it to make it have the active focus/cursor. You should add this to your script:

typing_ground.focus_set()


I ran it with python and python3, both worked fine.

Another thing that came up is that it occasionally happens that the next word is the same as the previous word. You should add a re-selection of a new word until it is different, otherwise the experience is "odd" (the word stays the same but your entry widget clears... and when you're typing you are not really looking at the entry box, just the target word.... and since it does not change, you think you've made a mistake.

Variables

Your code uses text entry and display components as variables. This code makes me cringe:


points['text'] = "Score: " + str(int(points['text'].split(': ')[-1]) + 1)



Instead of having a score variable, you store the score in the partial text value of the score displaying widget. Really? You do the same thing with the text to copy. Currently your code is:


def if_equal_delete_and_take_other_phrase(ev):
    if text_to_copy.cget("text") == typing_ground.get():
        typing_ground.delete(0, 'end')
        text_to_copy['text'] = new_word()
        points['text'] = "Score: " + str(int(points['text'].split(': ')[-1]) + 1)



Would it really be so hard to do:

target = "start"
score = 0
def if_equal_delete_and_take_other_phrase(ev):
    global target
    global score
    if target == typing_ground.get():
        score = score + 1
        target = new_word()
        typing_ground.delete(0, 'end')
        text_to_copy['text'] = target
        points['text'] = "Score: " + str(score)


Lambda

The lambda here is simply gratuitous:


new_word = lambda: random.choice(random.choice((WORDS[0:len(WORDS)//10], WORDS)))



It is never used in an anonymous way, and really there's no use for this format at all. It makes the reader expect something "funny", and there's confusion when the only funny thing is the declaration above.

Talk about confusing.... why is the first 10% of the WORDS list more important than the next 10%? The first 10% of the words appear with significantly more frequency because you not only choose the random word from the array, but you choose to use either the first 10% only, or the whole thing. In other words, half of the choices only ever come from the first 10% of the words.

I cannot think of any reason for that, and it makes the code complicated, and it is a head scratcher, and as a consequence, the code maintainer (me) would be cursing your name and hexing your bytestrings. For all things sweet and dainty, at least leave a comment, please. As for me, I'll just rewrite that crap as:

def new_word():
    return random.choice(WORDS)


Hmmm.... let me add in the non-repeating word function too:

def new_word():
    while True:
        nword = random.choice(WORDS)
        if nword != target:
            return nword


Conclusion

I added a #!/usr/bin/python3 line too. It's nice to not have to type these things in linux at least.

The code I ended up with is:

#!/usr/bin/python3
try:
    import tkinter as tk
except ImportError:
    import Tkinter as tk
import random

FONT = (None, 50)
WORDS = ['the', 'be', 'to', 'of', 'and', 'a', 'in', 'that', 'have',
         'I', 'it', 'for', 'not', 'on', 'with', 'he', 'as', 'you',
         'do', 'at', 'this', 'but', 'his', 'by', 'from', 'they',
         'we', 'say', 'her', 'she', 'or', 'an', 'will', 'my', 'one',
         'all', 'would', 'there', 'their', 'what', 'so', 'up', 'out',
         'if', 'about', 'who', 'get', 'which', 'go', 'me', 'when',
         'make', 'can', 'like', 'time', 'no', 'just', 'him', 'know',
         'take', 'people', 'into', 'year', 'your', 'good', 'some',
         'could', 'them', 'see', 'other', 'than', 'then', 'now',
         'look', 'only', 'come', 'its', 'over', 'think', 'also',
         'back', 'after', 'use', 'two', 'how', 'our', 'work',
         'first', 'well', 'way', 'even', 'new', 'want', 'because',
         'any', 'these', 'give', 'day', 'most', 'us']


target = "start"
score = 0

root = tk.Tk()
root.title("Typing trainer")

text_to_copy = tk.Label(root, text = target, font=FONT)
text_to_copy.pack()

typing_ground = tk.Entry(root, font=FONT)
typing_ground.pack()

points = tk.Label(root, text = "Score: " + str(score), font=FONT)
points.pack()

def new_word():
    while True:
        nword = random.choice(WORDS)
        if nword != target:
            return nword

def if_equal_delete_and_take_other_phrase(ev):
    global target
    global score
    if target == typing_ground.get():
        score = score + 1
        target = new_word()
        typing_ground.delete(0, 'end')
        text_to_copy['text'] = target
        points['text'] = "Score: " + str(score)

root.bind('&lt;Key&gt;', if_equal_delete_and_take_other_phrase)

typing_ground.focus_set()

root.mainloop()