tkinter live data label changes (dependent on user input) - python

So I'm trying to code a sorta medieval RPG, and I'm using Tkinter to display the user's health, stamina, controls, etc. I'm trying to make it so the user has a base stamina of 50 and if they press the "Attack" button, the stamina will decrease by 5 and slowly regenerate over time, (if the current STM is lower than 50 it starts adding by 1 point every millisecond until it reaches 50 again). I got the subtraction working for each time "Attack" is pressed, but I can't seem to get my if (stamina < stmmax): statement working at all. Any tips?
import time
import sys
import random as rand
from tkinter import *
# -----------------------------------Custom Functions---------------------------------------
def dramaticeffect():
time.sleep(2)
print("")
def delay_print(s):
for c in s:
sys.stdout.write(c)
sys.stdout.flush()
time.sleep(0.1)
time.sleep(1)
print("")
def die():
delay_print("Your adventure has ended, " + name + ".")
sys.exit()
def endprogress():
print("[This is the end of the game's current progress]")
die()
def actionlog():
global log
log = log + 1
action = True
print("\t inputlog#" + str(log))
logcheck.configure(text="*")
def attack():
global stamina
stamina = int(stamina - 5)
print(stamina)
stmcount = ("Stamina: " + str(stamina) + "/" + str(stmmax))
stmmeter.configure(text=stmcount)
live = True
actionlog()
'''
def uistart():
window = Tk()
window.title("Fate of all")
uidefault()
def uidefault():
label = Label(window, text="Testing")
entry = Entry(window)
button1 = Button(window, text="Enter")
button2 = Button(window, text="SB_1")
button3 = Button(window, text="SB_2")
def uihalt():
label.pack()
entry.pack()
button1.pack()
button2.pack()
button3.pack()
window.mainloop()
'''
# ---------------------------------------Gameplay-------------------------------------------
window = Tk()
window.title("Fate of all")
log = int(0)
live = False
stmmod = int(0)
stamina = int(50 + stmmod)
stmmax = int(50 + stmmod)
if (stamina < stmmax):
time.sleep(0.1)
stamina = stamina + 1
print(stamina)
stmcount = ("Stamina: " + str(stamina) + "/" + str(stmmax))
#damage
stmmeter = Label(window, text=stmcount)
entry = Entry(window)
button1 = Button(window, text="Enter", command=actionlog)
button2 = Button(window, text="Attack", command=attack)
button3 = Button(window, text="Defend", command=actionlog)
logcheck = Label(window, text="")
stmmeter.pack()
entry.pack()
button1.pack()
button2.pack()
button3.pack()
logcheck.pack()
window.mainloop()
#name = input("This is the tale of... ")
#dramaticeffect()
#delay_print('''
#Greetings, Sir ''' + name + ''', I am a humble traveler like you. Allow me to tell you a
#story, a tale of a friend or two.
#''')
#delay_print('''
#\t It is a desolate time, there are wars between sword and stone all
#across the land...and you were but a simple knight trying to survive,
#but everything changed once you entered the outer lands of Newlochia.
#''')
#delay_print("Fate of all is in your hands.")
#dramaticeffect()

First of all when you have an if statement in a Tk instance obviously it is going to run just once and secondly, it is not a good idea to use time.sleep(some_num) with GUI applications so it's better to use root.after(millis, func) and use it in a function.
It also depends when and where do you want to run your function. If you want it to just run when the character is attacked then you can do something like this and bind it to the button or call it in the other function that is already bound to your button:
def regenerate():
global stamina
if stamina < stmmax:
stamina += 1
root.after(60, regenerate)
# root.after works with millis so it is better to use
# a bigger number like 60 rather than 1
UPDATE: I tried implementing your code and I believe that this is more likely what you would want:
from tkinter import *
root = Tk()
root.title("Game!")
root.geometry("400x300")
stamina, stmmax = 50, 50
regenerating = False
lbl = Label(root, text=f"Stamina: {stamina}")
lbl.pack(pady=15)
def regenerate():
global regenerating
if not regenerating:
regenerating = True
def add_stamina():
global stamina, regenerating
if stamina < stmmax:
stamina += 1
lbl.config(text=f"Stamina: {stamina}")
root.after(100, add_stamina)
else:
regenerating = False
add_stamina()
def attack():
global stamina
stamina -= 15
lbl.config(text=f"Stamina: {stamina}")
regenerate()
Button(root, text="Attack!", command=attack).pack()
root.mainloop()
I also tried writing the function with a while True: (smth) loop and making use of threading.Thread to constantly check if the current stamina is less then the max stamina but it seems like in every trial the code failed and the GUI froze. Though just using normal functions is the better way.
UPDATE: Sorry for the many updates. thinking about the code I was unsatisfied that it was not really clean so I made a better version for optimization sake. Also in this situation where you are configuring the label a lot I rather set a textvariable for the label.
Code without textvariable:
from tkinter import *
root = Tk()
root.title("Game!")
root.geometry("400x300")
stamina, stmmax = 50, 50
regenerating = False
lbl = Label(root, text=f"Stamina: {stamina}")
lbl.pack(pady=15)
def add_stamina():
global stamina, regenerating
if stamina < stmmax:
stamina += 1
lbl.config(text=f"Stamina: {stamina}")
root.after(100, add_stamina)
else:
regenerating = False
def attack():
global stamina, regenerating
stamina -= 15
lbl.config(text=f"Stamina: {stamina}")
if not regenerating:
regenerating = True
add_stamina()
Button(root, text="Attack!", command=attack).pack()
root.mainloop()
Same code with the textvariable:
from tkinter import *
root = Tk()
root.title("Game!")
root.geometry("400x300")
stamina, stmmax = 50, 50
regenerating = False
stm_var = StringVar()
stm_var.set(f"Stamina: {stamina}")
lbl = Label(root, textvariable=stm_var)
lbl.pack(pady=15)
def add_stamina():
global stamina, regenerating
if stamina < stmmax:
stamina += 1
stm_var.set(f"Stamina: {stamina}")
root.after(100, add_stamina)
else:
regenerating = False
def attack():
global stamina, regenerating
stamina -= 15
stm_var.set(f"Stamina: {stamina}")
if not regenerating:
regenerating = True
add_stamina()
Button(root, text="Attack!", command=attack).pack()
root.mainloop()

Related

How do I make a number in a StringVariable increase by 1 every 5 seconds in Tkinter

So i've been coding a Cookie Clicker prototype in Tkinter and I stumbled with this problem:
I first made an option that when pressed, makes every click worth 2 points(It has a price).
Then I wanted to make another option that when pressed, it would add up 1 point every 5 seconds
but I haven't found a way to make it work (I have not set the price because it doesn't work yet).
from tkinter import *
import time
#funciones y variables
clicks = 0
incrementer = 1
price1 = 1
loop1 = 0
def sumar():
global clicks
clicks += incrementer
you.set("Has dado " +str(clicks)+ " clicks")
def shop1():
global clicks
global incrementer
if clicks < price1:
return
elif clicks >= price1:
clicks -= price1
incrementer = 2
you.set("Has dado " +str(clicks)+ " clicks")
buy1.destroy()
buy2.place(x=52, y=155)
def shop2():
global loop1
loop1 = int(1)
buy2.destroy()
while loop1 == 1:
interface.update()
time.sleep(5)
clicks += 1
you.set("Has dado " + str(clicks) + " clicks")
#Ventana y su configuración
interface = Tk()
interface.title("Cokie Test")
interface.geometry("200x200")
interface.resizable(False, False)
interface.configure(bg="black")
#Botón y changeable value
buy2 = Button(interface, bg="black", fg="white", text="Comprar Auto 1", command=shop2)
buy1 = Button(interface, bg="black", fg="white", text="Comprar x2", command=shop1)
buy1.place(x=62, y=155)
clickerimg = PhotoImage(file="C:/Users/Eduardo/OneDrive/Escritorio/Programming/botoncito.png")
clicker = Button(interface, command=sumar)
clicker.config(image=clickerimg)
clicker.pack(pady=20)
you = StringVar()
you.set("Has dado 0 clicks")
clickss = Label(interface, bg="black",fg="white", textvariable=you)
clickss.place(x=49,y=123)
interface.mainloop()
So I tried this expecting that it would add up 1 point every 5 seconds
def shop2():
global loop1
loop1 = int(1)
buy2.destroy()
while loop1 == 1:
interface.update()
time.sleep(5)
clicks += 1
you.set("Has dado " + str(clicks) + " clicks")
but it didn't respond
Tkinter widgets have a method named after that can be used to schedule functions to run in the future. If that function itself calls after to reschedule itself, it will continue to run for the life of the application.
The first argument to after is a delay in milliseconds. The second argument is a reference to a funtion. Any additional arguments are passed to that function.
Here's a very simple example:
import tkinter as tk
def tick():
value = points.get()
points.set(value+1)
root.after(5000, tick)
root = tk.Tk()
points = tk.IntVar(root, value=0)
label = tk.Label(root, textvariable=points)
label.pack(padx=20, pady=20)
tick()
root.mainloop()

Is there a way to make a function run after a specified amount of time in Python without the after method?

I am trying to create a simple program that tracks a user's clicks per second in Tkinter, but I have no idea how to make the program wait without freezing the program using the after method. The problem is that I need to log the high score after the time finishes, but using this method, the score logs before the click counter goes up. Here is my code:
from tkinter import *
import time
root = Tk()
root.geometry('600x410')
screen = Canvas(root)
h = 6 #button height
w = 12 #button width
c = 0 #counts amount of times clicked
start_btn = 0 #logs clicks of the start button
high_score = 0 #logs the highest score
time = 0
def count_hs():
high_score = c
def remove_time():
global time
time -= 1
def countdown(n):
for i in range(n):
time = n
root.after(1000, remove_time())
#alternatively i tried this:
#time.sleep(1)
#remove_time()
if time <= 0:
b["text"] = "Test done."
break
def start_test():
global start_btn
b["text"] = "Click to begin."
start_btn += 1
print("start button: " + str(start_btn))
def button_click():
global start_btn
global c
c+=1
print("click counter: " + str(c))
#resets the amount of clicks on the large button when the start button is pressed
if c >= 1 and start_btn >= 1:
print("test1")
c = 1
start_btn = 0
if b["text"] == "Click to begin.":
print("test2")
b["text"] = "Click!"
countdown(6)
count_hs()
print("hs: " +str(high_score))
#primary button
b = Button(root, text=" ", font=("Arial", 40), height = h, width = w, command = lambda: button_click())
b.grid(row=0, column=0)
#start button
start = Button(root, text="Start.", command = lambda: start_test())
start.grid(row=0, column=1)
root.mainloop()
Give it a try
from tkinter import *
root = Tk()
root.geometry('600x410')
screen = Canvas(root)
h = 6 # button height
w = 12 # button width
c = 0 # counts amount of times clicked
start_btn = 0 # logs clicks of the start button
high_score = 0 # logs the highest score
time = 0
def count_hs():
global high_score
if c > high_score:
high_score = c
return high_score
def remove_time():
global time
time -= 1
if time > 0:
root.after(1000, remove_time)
else:
show_score()
def start_test():
global start_btn
global c
global time
b["text"] = "Click to begin."
start_btn += 1
print("start button: " + str(start_btn))
# Reset your timer and counter
time = 6
c = 0
def button_click(*args):
global start_btn
global c
# resets the amount of clicks on the large button when the start button is pressed
if c == 0 and start_btn >= 1:
start_btn = 0
b["text"] = "Click!"
root.after(1000, remove_time)
print("hs: " + str(high_score))
else:
c += 1
print("click counter: " + str(c))
def show_score():
global c
score_label.configure(text=str(c))
high_score_label.configure(text=str(count_hs()))
c = 0
b['text'] = ""
# primary button
b = Button(root, text="", font=("Arial", 40), height=h, width=w, command=button_click)
b.grid(row=0, column=0, rowspan=5)
# start button
start = Button(root, text="Start.", command=lambda: start_test())
start.grid(row=0, column=1)
Label(root, text="Your score").grid(row=1, column=1)
score_label = Label(root, text="")
score_label.grid(row=2, column=1)
Label(root, text="High score").grid(row=3, column=1)
high_score_label = Label(root, text="")
high_score_label.grid(row=4, column=1)
root.mainloop()
Few changes:
In count_hs I assume you would update the highscore only if current score beats it.
You can use remove_time as a timer by making it calling itself until time <= 0, in which case you should end your game.
I've used the start button as a resetter, so that when it is clicked it will reset c and time.
On button_click you can now only bother with updating c (and change text at the beginning).
Finally I've added few labels to show the final results, both current and high scores.
Few suggestions to move on:
Instead of global variables you could create a class for the app, it should make it easier for you to exchange info and avoid subtle errors.
You could improve the layout, especially for the newly added labels.
You could make your original timer a parameter (currently, it is set within start_test).
Instead of importing from tkinter import *, I'd suggest you to do something like import tkinter as tk or from tkinter import ... since it increases readability and reduces the sources of errors.

Jumping between functions in tkinter

so I am working on this school project and I need to be able to run the random number generator then if it is 1 go to the headspinner module but if it is 2 go to the tailspinner module. After that the code should add up the score and print it to the user.
Any advice on how to jump from one function to another in my code would be much appreciated thank you.
from tkinter import * # access tkinter library
import random # get random number generator
money = 100
#create coin flip module
def coinFlip():
flip = random.randint(1, 2)
if flip == 1:
headspinner()
else:
tailspinner()
#create headspinner module
def headspinner():
global money
head = random.randint(1, 2)
if head == 1:
money = money + 30
else:
money = money - 25
#create tailspinner module
def tailspinner():
global money
tail = random.randint(1, 4)
if tail == 1:
money = money + 2
elif tail == 2:
money = money + 5
elif tail == 3:
money = money + 10
else:
money = money + 15
#gains or losses module
def upordown():
global money
if money > 100:
screen.itemconfig(message, text = f"Congratulations, you won ${(money - 100):.2f}", font = ("Calibri", "18"))
else:
screen.itemconfig(message, text = f"Congratulations, you won ${(100 - money):.2f}", font = ("Calibri", "18"))
#create pop up box
root = Tk()
#creating canvas
screen = Canvas (root, height = 600, width = 800, bg = "lightgreen")
screen.pack()
#flip button
go = Button(root, text = "Flip", cursor = "hand2", command = coinFlip)
goButton = screen.create_window(400, 530, window = go)
#cerate title
title = screen.create_text(400, 100, text = "Welcome to Flip and Spin", font = ("Calibri", "35"))
#text for instructions
text1 = Label(root, text = "Welcome to the Flip and Spin game! \nThis game includes a quick fate of what you could encounter. \nIt starts off with a fast flip of a coin followed by a dizzying spin of a spinner. \nCome and play to decide if you will lose money, \nmake your money back, or win some easy money!", font = ("Calibri", "20"), justify = CENTER, bg = "light green")
text1label = screen.create_window(400, 300, window = text1,)
#text for final results
message = screen.create_text(400, 400, text = "Results", font = ("Calibri", "18"))
#close canvas
mainloop()
You are already switching from function to function in def coinFlip.
You just need to put everything together.
Here's a simple example to get you started:
from tkinter import Tk, Button, Label, X, LEFT, RIGHT
import random
money = 100
#create coin flip module
def coin_flip():
flip = random.randint(1, 2)
if flip == 1:
headspinner()
else:
tailspinner()
#create headspinner module
def headspinner():
global money
head = random.randint(1, 2)
if head == 1:
money = money + 30
else:
money = money - 25
text.config(text=f"Headspinner: {money}", bg="#aaafff")
#create tailspinner module
def tailspinner():
global money
tail = random.randint(1, 4)
if tail == 1:
money = money + 2
elif tail == 2:
money = money + 5
elif tail == 3:
money = money + 10
else:
money = money + 15
text.config(text=f"Tailspinner: {money}", bg="#ffaaaa")
def show_result():
global money
text.config(text=f"Result: {money}.\nClick the Flip button to start over.", bg="#fffaaa")
money = 100 # reset
root = Tk()
root.title("Game")
# the text here changes when the buttons are pressed
text = Label(root, text="Welcome to the Flip and Spin game!", font = ("Calibri", "18"))
text.pack()
rules = Label(root, text="This game includes a quick fate of what you could encounter. \nIt starts off with a fast flip of a coin followed by a dizzying spin of a spinner. \nCome and play to decide if you will lose money, \nmake your money back, or win some easy money!", font = ("Calibri", "10"))
rules.pack()
# click the button to run the command and change the text in the Label
flip_button = Button(root, text="Flip", command=coin_flip, fg="blue")
flip_button.pack(fill=X, side=LEFT, expand=True)
# click the button to run the command and change the text in the Label
result_button = Button(root, text="Result", command=show_result, fg="blue")
result_button.pack(fill=X, side=RIGHT, expand=True)
root.mainloop()

Button isn't displaying the timer

I'm making a little game for my 4-year-old nephew. you plug two mice into the computer and try to press your button and I need the start button to turn into a timer. The problem is the button isn't displaying the time. It stops responding until the time is up and then displays "1". (keep in mind this is unfinished)
import tkinter
from tkinter import ttk
import time
score = 0
window = tkinter.Tk()
window.geometry("300x200")
def button1():
score = score - 1
def button2():
score = score + 1
def Start():
t = 30
while t > 0:
mins, secs = divmod(t, 60)
timer = '{:02d}:{:02d}'.format(mins, secs)
start.config(text=t)
print(timer, end="\r")
time.sleep(1)
t -= 1
start = ttk.Button( window, text = "Start", command = Start)
start.pack(padx= 2, pady = 1)
one = ttk.Button( window, text = "Player 1", command = button1)
one.pack(padx= 2, pady = 1)
two = ttk.Button( window, text = "Player 2", command = button2)
two.pack(padx= 2, pady = 1)
window.mainloop()
Here is an answer on the while loops indegestibility with the tkinter mainloop.
You could also solve this by running your start() function in its own thread:
import threading
def start():
t = 30
while t > 0:
mins, secs = divmod(t, 60)
timer = '{:02d}:{:02d}'.format(mins, secs)
start_button.config(text=t)
print(timer, end="\r")
time.sleep(1)
t -= 1
def start_in_thread():
thread = threading.Thread(target=start)
thread.daemon = True # forces thread to close when the tkinter mainloop is closed
thread.start()
start_button = ttk.Button(window, text="Start", command=start_in_thread)
Another issue is that you buttonX() functions change the global variable score without gloal keyword:
def button1():
global score
score = score - 1
You just need to remove the while and replace it with a call to after. I also cleaned up your script a little, and solved a future problem you were going to have. Using threading like the other answer states is overkill. You just need to stop blocking the mainloop with the while.
import tkinter as tk
window = tk.Tk()
window.geometry("300x200")
_PLAYTIME = 10
t, score = _PLAYTIME, 0
def tally(i):
global score
score += i
start = tk.Button(window, text="Start")
start.pack(padx= 2, pady = 1)
tk.Button(window, text="Player 1", command=lambda: tally(1)).pack(padx=2, pady=1)
tk.Button(window, text="Player 2", command=lambda: tally(-1)).pack(padx=2, pady=1)
def game():
global t, score
if t > 0:
timer = '{:02d}:{:02d}'.format(*divmod(t, 60))
start.config(text=f'Time: {timer} | Score: {score}')
t -= 1
start.after(1000, game)
else:
start.config(text=f'Score: {score} | Start')
t, score = _PLAYTIME, 0
start.configure(command=game)
window.mainloop()
Here's the exact same game, but made giant and colorful as I assume 4 year olds like things... ;). I also added a 3-2-1-Go! countdown after start is pressed so, the person pressing start doesn't lose an advantage. The red and green rects are your click area. Red subtracts and green adds.
I'm not sure if you are prepared for this but, plugging 2 mice into the same computer is not going to give you 2 pointers. Maybe that's part of your game ~ fighting a 4 year old for mouse control :D. If it isn't, you are going to need TeamPlayer or something similar. Or you could simply bind keyboard keys instead of the mouse.
import tkinter as tk
root = tk.Tk()
root.geometry("800x640")
root.title('CLICKFIGHT')
#seconds to play and player handicaps
_PLAYTIME = 10
_HANDICAP1 = 0
_HANDICAP2 = 0
#time, score, countdown
t, s, cd = _PLAYTIME, 0, 3
#gameboard
board = tk.Canvas(root, highlightthickness=0, width=800, height=640)
board.pack()
#score adjuster
def tally(i):
global s
s += i
#gameboard elements
player1 = board.create_rectangle(0, 0, 400, 600, fill="#ff0000")
player2 = board.create_rectangle(400, 0, 800, 600, fill="#00ff00")
timer = board.create_text(200, 50, font='Helvetica 40 bold', fill='#ffffff')
score = board.create_text(600, 50, font='Helvetica 40 bold', fill='#ffffff')
button = board.create_rectangle(0, 600, 800, 640, fill="#0000ff", tag="button")
start = board.create_text(400, 620, font='Helvetica 20 bold', fill='#ffffff', text="START", tag="button")
cdown = board.create_text(400, 300, font='Helvetica 80 bold', fill='#ffffff')
#game countdown
def countdown():
global cd, p
#so you can't click start again
board.tag_unbind("button", '<1>')
if cd > 0:
board.itemconfig(cdown, text=cd)
cd-=1
root.after(800, countdown)
else:
board.itemconfig(cdown, text='GO!')
root.after(200, game)
cd = 3
#actual game
def game():
global t, s
#game stats
board.itemconfig(timer, text='Time:\t{:02d}:{:02d}'.format(*divmod(t, 60)))
board.itemconfig(score, text=f'Score:\t{s}')
board.itemconfig(start, text='PLAYING...')
if t > 0:
#game looping
t -= 1
root.after(1000, game)
board.itemconfig(cdown, text='')
else:
#reset everything
t, s = _PLAYTIME, 0
board.itemconfig(start, text='START')
board.itemconfig(cdown, text='GAME OVER')
board.tag_bind("button", '<1>', lambda e: countdown())
#mouse events
board.tag_bind(player1 , '<1>', lambda e: tally(-(1+_HANDICAP1)))
board.tag_bind(player2 , '<1>', lambda e: tally(1+_HANDICAP2))
board.tag_bind("button", '<1>', lambda e: countdown())
root.mainloop()

Keep track of score

I am trying to make a quiz that shows the user the name of the state and they have to correctly state the capital. Everything works fine, except for keeping track of the user's score. I have tried to change around the score portion of the code, but nothing is working! I think the problem is somewhere in the nextCapital() function, but then again I could be wrong. I am new to python and all of this is a little overwhelming. I would really appreciate the help!
import tkinter
import random
capitals={"Washington":"Olympia","Oregon":"Salem",\
"California":"Sacramento","Ohio":"Columbus",\
"Nebraska":"Lincoln","Colorado":"Denver",\
"Michigan":"Lansing","Massachusetts":"Boston",\
"Florida":"Tallahassee","Texas":"Austin",\
"Oklahoma":"Oklahoma City","Hawaii":"Honolulu",\
"Alaska":"Juneau","Utah":"Salt Lake City",\
"New Mexico":"Santa Fe","North Dakota":"Bismarck",\
"South Dakota":"Pierre","West Virginia":"Charleston",\
"Virginia":"Richmond","New Jersey":"Trenton",\
"Minnesota":"Saint Paul","Illinois":"Springfield",\
"Indiana":"Indianapolis","Kentucky":"Frankfort",\
"Tennessee":"Nashville","Georgia":"Atlanta",\
"Alabama":"Montgomery","Mississippi":"Jackson",\
"North Carolina":"Raleigh","South Carolina":"Columbia",\
"Maine":"Augusta","Vermont":"Montpelier",\
"New Hampshire":"Concord","Connecticut":"Hartford",\
"Rhode Island":"Providence","Wyoming":"Cheyenne",\
"Montana":"Helena","Kansas":"Topeka",\
"Iowa":"Des Moines","Pennsylvania":"Harrisburg",\
"Maryland":"Annapolis","Missouri":"Jefferson City",\
"Arizona":"Phoenix","Nevada":"Carson City",\
"New York":"Albany","Wisconsin":"Madison",\
"Delaware":"Dover","Idaho":"Boise",\
"Arkansas":"Little Rock","Louisiana":"Baton Rouge"}
score=0
timeleft=30
print("This program will launch a capital quiz game.")
input1 = input("What difficulty would you like to play: easy, normal, or hard?\n")
if input1.lower() == "easy":
seconds = 90
timeleft = seconds
elif input1.lower() == "normal":
seconds = 60
timeleft = seconds
elif input1.lower() == "hard":
seconds = 30
timeleft = seconds
def startGame(event):
#if there's still time left...
if timeleft == seconds:
#start the countdown timer.
countdown()
#run the function to choose the next colour.
nextCapital()
if timeleft == 0:
endlabel = tkinter.Label(root, text="The time is up!\nYour score is: " + str(score) +" out of 50", font=('Helvetica', 12))
endlabel.pack()
e.pack_forget()
#function to choose and display the next colour.
def nextCapital():
#use the globally declared 'score' and 'play' variables above.
global score
global timeleft
#if a game is currently in play...
if timeleft > 0:
#...make the text entry box active.
e.focus_set()
randchoice = random.choice(list(capitals.keys()))
answer = capitals.get(randchoice)
if answer.lower() == randchoice.lower():
score = score+1
#### #this deletes the random choice from the dictionary
#### del capitals[randchoice]
#clear the text entry box.
e.delete(0, tkinter.END)
#this updates the random choice label
label.config(text=str(randchoice))
#update the score.
scoreLabel.config(text="Score: " + str(score))
#a countdown timer function.
def countdown():
#use the globally declared 'play' variable above.
global timeleft
#if a game is in play...
if timeleft > 0:
#decrement the timer.
timeleft -= 1
#update the time left label.
timeLabel.config(text="Time left: " + str(timeleft))
#run the function again after 1 second.
timeLabel.after(1000, countdown)
#create a GUI window.
root = tkinter.Tk()
#set the title.
root.title("Capital Quiz")
#set the size.
root.geometry("500x250")
#add an instructions label.
instructions = tkinter.Label(root, text="Brush up your geography skills!", font=('Helvetica', 12))
instructions.pack()
#add a score label.
scoreLabel = tkinter.Label(root, text="Press enter to start" + str(score), font=('Helvetica', 12))
scoreLabel.pack()
#add a time left label.
timeLabel = tkinter.Label(root, text="Time left: " + str(timeleft), font=('Helvetica', 12))
timeLabel.pack()
#prompt label
promptLabel = tkinter.Label(root, text= "Enter the capital of: ", font=('Helvetica', 12))
promptLabel.pack()
#add a label that will hold print the prompt
label = tkinter.Label(root, font=('Helvetica', 60))
label.pack()
#add a text entry box for typing in colours.
e = tkinter.Entry(root)
#run the 'startGame' function when the enter key is pressed.
root.bind('<Return>', startGame)
e.pack()
#set focus on the entry box.
e.focus_set()
#start the GUI
root.mainloop()
randchoice is one of the keys in the capitals dict, i.e. a State.
answer is one of the values in the capitals dict, i.e. a Capital
You then compare the lowercase versions of randchoice and answer and increment the score if they are equal. But clearly they will never be equal (one is a State, one is a Capital). So your score won't be updated properly.
Not an answer, but a bit of advice: eschew all global variables, wrap things into an object with clearly defined, short methods. You will have much easier time working with and reasoning about the code.
Consider this skeleton of a class:
class Quiz(object):
def __init__(self, difficulty, capitals_dict):
self.score = 0
self.capitals = capitals
self.difficulty = ...
self.right_answer = None
def getNextQuestion(self):
# Choose a capital and assign it as the current right answer
...
self.right_answer = ...
return self.right_answer # to show it to user
def checkAnswer(user_answer):
if user_answer == self.right_answer:
self.score = ...
return True
else:
...
def isGameOver(self):
return len(self.capitals) == 0
I guess it's clear enough how to use a class like this, and reasonably clear how to implement it.

Categories