10
\$\begingroup\$

I have made a game (I like to code when in my spare time) where words are taken at random from a list and displayed on a label. If they type it correctly, their wordcount goes up by 1 and the word is removed from the list. If they get it wrong, the word remains. If they enter nothing in an attempt to skip the long words, they get a skip. After their wordcount has reached 12 and their time is less than 60 seconds, they get the new high score.

try:
    from tkinter import *

except ImportError:
    from Tkinter import *

import time
import random

time_score = 0
high_score = 60.00
name = "A really slow typer"
words = ["Games",
         "Development",
         "Keyboard",
         "Speed",
         "Typer",
         "Anything",
         "Alpha",
         "Zealous",
         "Accurate",
         "Basics",
         "Shortcut",
         "Purpose",
         "Window",
         "Counter",
         "Fortress",
         "Modification",
         "Computer",
         "Science",
         "History",
         "Football",
         "Basketball",
         "Solid",
         "Phantom",
         "Battlefield",
         "Advanced",
         "Warfare",
         "Download",
         "Upload",
         "Antidisestablishmentarianism",
         "Supercalifragilisticexpialidocious",
         "Discombobulation",
         "Liberated",
         "Assassin",
         "Brotherhood",
         "Revelation",
         "Unity",
         "Syndicate",
         "Victory"]

wordcount = 0
skips = 0

start_time = time.time()

def restart(event):
    global wordcount, skips, time_score
    start_time = time.time()
    wordcount = 0
    skips = 0
    time_score = 0
    label.config(text="")
    time_scoreLabel.config(text="Time: " + str(time_score) + "s")
    wordcounter.config(text="Words: " + str(wordcount))
    skipcounter.config(text="Skips: " + str(skips))
    wronglabel.config(text="")
    hilab.pack_forget()
    enter.pack_forget()
    time_scoreLabel.pack_forget()
    wordcounter.pack_forget()
    skipcounter.pack_forget()
    wronglabel.pack_forget()
    entry.pack_forget()
    time_scoreLabel.pack()
    wordcounter.pack()
    skipcounter.pack()
    wronglabel.pack()
    entry.pack()
    entry.focus_set()
    root.bind("<Return>", check)
    shuffle()

def shuffle():
    global word, time_score, start_time
    go.pack_forget()
    while wordcount < 12:
        time_score = time.time() - start_time
        time_score = round(time_score,2)
        word = random.choice(words)
        label.config(text=str(word))
        time_scoreLabel.config(text="Time: " + str(time_score) + "s")      
        return

    if wordcount == 12:
        end()


def no(event):
    pass 

def end():
    global time_score, start_time, high_score, name
    time_score = time.time() - start_time
    time_score = round(time_score,2)
    entry.delete(0, tkinter.END)
    time_scoreLabel.pack_forget()
    label.config(text="Finished")
    wordcounter.config(text="Well done you did it in " + str(time_score) +
                       "s"
                       )
    if float(start_time) < float(high_score):
        hilab.pack()
        high_score = time_score
        enter.pack()       
    root.bind("<Return>", no)

def update():
    global time_score, start_time, high_score, name
    name = entry.get()
    ThirdLine.config(text="The current world record is: " + str(high_score)
                     + "s, by: " + name
                     )
    entry.delete(0, tkinter.END)

def check(event):
    global time_score, high_score, name, wordcount, skips, word, start_time
    now = time.time()
    time_score = time.time() - start_time
    time_score = round(time_score,2)
    if entry.get().lower() == word.lower():
        time_scoreLabel.config(text="Time: " + str(time_score) + "s")
        wordcount += 1
        wordcounter.config(text="Words: " + str(wordcount))
        wronglabel.config(text="")
        words.remove(word) 
        shuffle()

    elif entry.get().lower() != word.lower():
        wronglabel.config(text="WRONG!", fg='red')
        time_scoreLabel.config(text="Time: " + str(time_score) + "s")
        shuffle()

    entry.delete(0, tkinter.END)

root = Tk()          
root.title("SpeedTypr")
root.geometry = ("750x600")

Header = Label(root, text="SpeedTypr", font=('Titilium Web', 32)
                       , bg='Red')
Header.pack(fill=X)

seperator1 = Frame(root, height=2, width=2, bg='black')
seperator1.pack(fill=X)

FirstLine = Label(root, text="The aim of the game is to type"
                          "whatever you"
                          "see on the screen as quickly as possible"
                          )
FirstLine.pack()

SecondLine = Label(root, text="You will be shown 12 words at"
                           "random and you have to type them all"
                           "correctly as shown"
                           )
SecondLine.pack()

ThirdLine = Label(root, text="The current world record is: " +
                          str(high_score) + "s, by: " + name
                          )
ThirdLine.pack()

SeventhLine = Label(root, text="When you are ready, press go"
                            "to begin!"
                            )
SeventhLine.pack()

label = Label(root, font=("Helvetica", 60))
label.pack()

time_scoreLabel = Label(root, text="Time: " + str(time_score) +
                                "s", font=('Helvetica', 14)
                                )
time_scoreLabel.pack()

wordcounter = Label(root, text="Words: " + str(wordcount),
                            font =("Helvetica", 14)
                            )
wordcounter.pack()

skipcounter = Label(root, text="Skips: " + str(skips),
                            font =("Helvetica", 14)
                            )
skipcounter.pack()

wronglabel = Label(root, text="", font =("Helvetica, 14"))
wronglabel.pack()                                       

go = Button(root, text="GO!", command=shuffle)
go.pack()

hilab = Label(root, text="Well done, you got the high score!"
                      "Enter your name below"
                      "Press [TAB] to restart!"
                      )

enter = Button(root, text="Enter", command=update)
entry = Entry(root)

root.bind("<Return>", check)
root.bind("<Tab>", restart)

entry.pack()

entry.focus_set()

root.mainloop()

I wanted to share my code with you guys to find out if there is anything that can be improved in terms of code shortening or even bugs that I could've missed out when writing the program. Also, I made this in Python 3 and used the try and except to try and help it work in Python 2. I do not have Python 2 so could you please also try and see if it works on there.

\$\endgroup\$
0

3 Answers 3

6
\$\begingroup\$

Bug

You imported tkinter as a wildcard (*) so you should remove tkinter. from your program for proper operation.

Minor imprecision

The information text lacks spaces, some words stick to each other, giving a feeling of lack of professionality.

Lack of focus on the important

The most important part of the program is the entry when the user types its text, yet it is tiny. Parts of the program should have sizes proportional to their importance.

Lack of separation of code and data

You have a wordlist right inside your code. This makes it pretty annoying to change it and a non-programmer might actually be scared to change something inside a code-file. I suggest reading the words from a file, it is very easy:

with open(WORDS_FILE) as f:
   WORDS = list(f.readlines())

Constants are uppercase by convention

A constant is a value that never changes, as a convention they are uppercase, for example WORDS.

Multiline widgets

There is no need to make a new widget for each line, you can use the same widget for many lines.

\$\endgroup\$
1
  • \$\begingroup\$ I have put the words as a text file and read them into a list. Now when I run the program and retype the word, it is always wrong. In the text file it's one word per line and when it's displayed on the label it appears squashed at the top of the label \$\endgroup\$
    – Inkblot
    Dec 15, 2015 at 16:15
4
\$\begingroup\$

Use if __name__ == "__main__":

This is important for proper execution when running a program with multiple files.

Code Duplication

if entry.get().lower() == word.lower():
    time_scoreLabel.config(text="Time: " + str(time_score) + "s")
    wordcount += 1
    wordcounter.config(text="Words: " + str(wordcount))
    wronglabel.config(text="")
    words.remove(word) 
    shuffle()

elif entry.get().lower() != word.lower():
    wronglabel.config(text="WRONG!", fg='red')
    time_scoreLabel.config(text="Time: " + str(time_score) + "s")
    shuffle()

shuffle() is the last line of code in both blocks, and can be moved to immediately after the block. It does not appear that the duplication of time_scoreLabel can be removed without reformatting the output, so that is OK.

Use more functions

As already mentioned by TheCoffeeCup, you have huge, poorly formatted methods. You may be able to split these up into smaller methods controlling a smaller section of the program. For example, in the above mentioned code block, you could split that into a method for the win condition and a method for the lose condition, making your methods smaller and responsible for less. That block comes from a function named check(event), but it gives status updates as well as checking.

Naming

I don't remember ever seeing snake_camelCase used before, as in time_scoreLabel. You should probably name that with just snake_case, as in time_score_label, instead.

\$\endgroup\$
3
\$\begingroup\$

In restart(event), all I see is a mess of code. What I want to see, or what I should see, is a properly formatted code:

def restart(event):
    global wordcount, skips, time_score

    start_time = time.time()

    wordcount = 0
    skips = 0
    time_score = 0

    label.config(text = "")
    time_scoreLabel.config(text = "Time: " + str(time_score) + "s")
    wordcounter.config(text = "Words: " + str(wordcount))
    skipcounter.config(text = "Skips: " + str(skips))
    wronglabel.config(text = "")

    hilab.pack_forget()
    enter.pack_forget()
    time_scoreLabel.pack_forget()
    wordcounter.pack_forget()
    skipcounter.pack_forget()
    wronglabel.pack_forget()
    entry.pack_forget()

    time_scoreLabel.pack()
    wordcounter.pack()
    skipcounter.pack()
    wronglabel.pack()
    entry.pack()

    entry.focus_set()
    root.bind("<Return>", check)
    shuffle()

In end(), you have this line:

wordcounter.config(text="Well done you did it in " + str(time_score) +
                   "s"
                   )

The ) is in a weird spot. It should be on the same line as "s":

wordcounter.config(text="Well done you did it in " + str(time_score) +
                   "s")

There is a similar line in restart(), and a lot of lines after the function declarations.

Let's go format the rest of the code:

try:
    from tkinter import *
except ImportError:
    from Tkinter import *

import time
import random

time_score = 0
high_score = 60.00

name = "A really slow typer"
words = ["Games",
         "Development",
         "Keyboard",
         "Speed",
         "Typer",
         "Anything",
         "Alpha",
         "Zealous",
         "Accurate",
         "Basics",
         "Shortcut",
         "Purpose",
         "Window",
         "Counter",
         "Fortress",
         "Modification",
         "Computer",
         "Science",
         "History",
         "Football",
         "Basketball",
         "Solid",
         "Phantom",
         "Battlefield",
         "Advanced",
         "Warfare",
         "Download",
         "Upload",
         "Antidisestablishmentarianism",
         "Supercalifragilisticexpialidocious",
         "Discombobulation",
         "Liberated",
         "Assassin",
         "Brotherhood",
         "Revelation",
         "Unity",
         "Syndicate",
         "Victory"]

wordcount = 0
skips = 0

start_time = time.time()

def restart(event):
    global wordcount, skips, time_score
    start_time = time.time()

    wordcount = 0
    skips = 0
    time_score = 0

    label.config(text="")
    time_scoreLabel.config(text="Time: " + str(time_score) + "s")
    wordcounter.config(text="Words: " + str(wordcount))
    skipcounter.config(text="Skips: " + str(skips))
    wronglabel.config(text="")

    hilab.pack_forget()
    enter.pack_forget()
    time_scoreLabel.pack_forget()
    wordcounter.pack_forget()
    skipcounter.pack_forget()
    wronglabel.pack_forget()
    entry.pack_forget()

    time_scoreLabel.pack()
    wordcounter.pack()
    skipcounter.pack()
    wronglabel.pack()
    entry.pack()

    entry.focus_set()
    root.bind("<Return>", check)
    shuffle()

def shuffle():
    global word, time_score, start_time
    go.pack_forget()

    while wordcount < 12:
        time_score = time.time() - start_time
        time_score = round(time_score,2)
        word = random.choice(words)
        label.config(text=str(word))
        time_scoreLabel.config(text="Time: " + str(time_score) + "s")      
        return

    if wordcount == 12:
        end()


def no(event):
    pass 

def end():
    global time_score, start_time, high_score, name
    time_score = time.time() - start_time
    time_score = round(time_score,2)

    entry.delete(0, tkinter.END)
    time_scoreLabel.pack_forget()
    label.config(text="Finished")
    wordcounter.config(text="Well done you did it in " + str(time_score) +
                       "s")

    if float(start_time) < float(high_score):
        hilab.pack()
        high_score = time_score
        enter.pack()       

    root.bind("<Return>", no)

def update():
    global time_score, start_time, high_score, name
    name = entry.get()
    ThirdLine.config(text="The current world record is: " + str(high_score)
                     + "s, by: " + name)
    entry.delete(0, tkinter.END)

def check(event):
    global time_score, high_score, name, wordcount, skips, word, start_time
    now = time.time()
    time_score = time.time() - start_time
    time_score = round(time_score,2)

    if entry.get().lower() == word.lower():
        time_scoreLabel.config(text="Time: " + str(time_score) + "s")
        wordcount += 1
        wordcounter.config(text="Words: " + str(wordcount))
        wronglabel.config(text="")
        words.remove(word) 
        shuffle()

    elif entry.get().lower() != word.lower():
        wronglabel.config(text="WRONG!", fg='red')
        time_scoreLabel.config(text="Time: " + str(time_score) + "s")
        shuffle()

    entry.delete(0, tkinter.END)

root = Tk()          
root.title("SpeedTypr")
root.geometry = ("750x600")

Header = Label(root, text="SpeedTypr", font=('Titilium Web', 32)
                       , bg='Red')
Header.pack(fill=X)

seperator1 = Frame(root, height=2, width=2, bg='black')
seperator1.pack(fill=X)

FirstLine = Label(root, text="The aim of the game is to type"
                          "whatever you"
                          "see on the screen as quickly as possible")
FirstLine.pack()

SecondLine = Label(root, text="You will be shown 12 words at"
                           "random and you have to type them all"
                           "correctly as shown")
SecondLine.pack()

ThirdLine = Label(root, text="The current world record is: " +
                          str(high_score) + "s, by: " + name)
ThirdLine.pack()

SeventhLine = Label(root, text="When you are ready, press go"
                            "to begin!")
SeventhLine.pack()

label = Label(root, font=("Helvetica", 60))
label.pack()

time_scoreLabel = Label(root, text="Time: " + str(time_score) +
                                "s", font=('Helvetica', 14))
time_scoreLabel.pack()

wordcounter = Label(root, text="Words: " + str(wordcount),
                            font =("Helvetica", 14))
wordcounter.pack()

skipcounter = Label(root, text="Skips: " + str(skips),
                            font =("Helvetica", 14))
skipcounter.pack()

wronglabel = Label(root, text="", font =("Helvetica, 14"))
wronglabel.pack()                                       

go = Button(root, text="GO!", command=shuffle)
go.pack()

hilab = Label(root, text="Well done, you got the high score!"
                      "Enter your name below"
                      "Press [TAB] to restart!")

enter = Button(root, text="Enter", command=update)
entry = Entry(root)

root.bind("<Return>", check)
root.bind("<Tab>", restart)

entry.pack()
entry.focus_set()

root.mainloop()

In other words, group code into readable chunks.

\$\endgroup\$
1
  • \$\begingroup\$ On the subject of code formatting, would it be more logical to use a class for my program? \$\endgroup\$
    – Inkblot
    Dec 15, 2015 at 16:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.