Keep track of score - python

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.

Related

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()

tkinter live data label changes (dependent on user input)

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()

How to get a value to change immediately after a button is pressed in tkinter?

When the rock button is pressed I want your score to go up by one immediately after you press the button. However the score updates on the button press after instead of immediately updating after one button press. To see what I mean press the rock button twice and you will get a score of 1. How would I fix this problem?
from tkinter import *
import random
root = Tk()
results = Label(root)
your_score = 0
def rock_input():
global results
global your_score
options = ['scissors']
cpu = random.choice(options)
win = Label(root, text='you win!!!')
human_score = Label(root, text='Your score: ' + str(your_score))
win.config(font=('Courier', 44))
human_score.config(font=('Courier', 15))
results.grid_forget()
if cpu == 'scissors':
your_score += 1
human_score.grid(row=2, column=1)
results = win
results.grid(row=4, column=0)
rock_button = Button(root, text='rock', bg='#a85032', padx=20, pady=15, command=rock_input)
rock_button.grid(row=1, column=0)
root.mainloop()
I have tried playing around with your code and im not sure what you're trying to achieve, so pardon me if im wrong. I think there is two ways to achieve what i think you want.
Way 1 (does not change your function code):
Simply changing your_score = 0 to your_score = 1 will fix the issue for now.
Way 2 (change inside your function, rearranging the code):
def rock_input():
global results
global your_score
options = ['scissors']
cpu = random.choice(options)
if cpu == 'scissors':
your_score += 1
win = Label(root, text='you win!!!')
human_score = Label(root, text='Your score: ' + str(your_score))
win.config(font=('Courier', 44))
human_score.config(font=('Courier', 15))
results.grid_forget()
human_score.grid(row=2, column=1)
results = win
results.grid(row=4, column=0)
Let me know if any errors or doubts :D

Is there a way to not use global variables in my code?

I am relatively new to Python so please bear with the inefficiency of my code. This is one of my first Tkinter applications and it is quite a simple one. It is a code guessing game where the user tries to guess a randomly generated 4 digit code. The code currently prints the randomly generated number so that it is easier to see if the code is working. But is there a way to not use global variables in this code. Also, it would be helpful if I was told how to make my code efficient. Thanks in advance. Code:
import random
import tkinter as tk
number_of_tries = 0
def tries():
global number_of_tries
number_of_tries += 1
comment.configure(state="normal")
comment.delete(0, "end")
comment.insert(0, "Not quite! Keep trying!")
comment.configure(state="disabled")
if str(guess) == str(random_number):
comment.configure(state="normal")
comment.delete(0, "end")
comment.insert(0, "You guessed it in " + str(number_of_tries) + " tries!")
comment.configure(state="disabled")
guess_entry.configure(state="disabled")
go.configure(state="disabled")
def character_check():
global guess
guess = guess_entry.get()
if len(guess) != 4:
comment.configure(state="normal")
comment.delete(0, "end")
comment.insert(0, "Guess must be 4 digits! ")
comment.configure(state="disabled")
else:
for char in guess:
if char.isalpha():
comment.configure(state="normal")
comment.delete(0, "end")
comment.insert(0, "Guess must only include integers! ")
comment.configure(state="disabled")
else:
digit_check()
def digit_check():
global guess
guess = guess_entry.get()
for i in range(0, 4):
if str(guess)[i] == str(random_number)[i]:
digits[i] = str(guess)[i]
digit_display.configure(state="normal")
digit_display.delete(0, "end")
digit_display.insert(0, digits)
digit_display.configure(state="disabled")
elif str(guess)[i] != str(random_number)[i]:
digits[i] = "?"
digit_display.configure(state="normal")
digit_display.delete(0, "end")
digit_display.insert(0, digits)
digit_display.configure(state="disabled")
def initialise():
global number_of_tries, digits
global random_number
digits = ["?"] * 4
random_number = random.randrange(1000, 9999)
number_of_tries = 0
digit_display.configure(state="normal")
comment.configure(state="normal")
digit_display.delete(0, "end")
digit_display.insert(0, digits)
comment.delete(0, "end")
comment.insert(0, "Good luck!")
digit_display.configure(state="disabled")
comment.configure(state="disabled")
guess_entry.configure(state="normal")
go.configure(state="normal")
print(random_number)
screen = tk.Tk()
screen.geometry("400x400")
screen.title("Code Crunchers")
heading = tk.Label(text="Welcome to Code Crunchers!", font="Montserrat 15")
heading.place(relx=0.5, rely=0.1, anchor="center")
instruction_1 = tk.Label(text="Enter your guess below: ", font="Montserrat 10")
instruction_1.place(relx=0.5, rely=0.2, anchor="center")
guess_entry = tk.Entry(screen, width=4)
guess_entry.place(relx=0.5, rely=0.25, anchor="center")
go = tk.Button(text="Go", font="Montserrat 10", command=lambda: [character_check(), tries()])
go.place(relx=0.6, rely=0.27, anchor="center")
instruction_2 = tk.Label(text="Digits correct: ", font="Montserrat 10")
instruction_2.place(relx=0.5, rely=0.35, anchor="center")
digit_display = tk.Entry(screen, width=10)
digit_display.place(relx=0.5, rely=0.4, anchor="center")
comment = tk.Entry(screen, width=40)
comment.place(relx=0.5, rely=0.45, anchor="center")
restart = tk.Button(text="Restart", font="Montserrat 10", command=lambda: initialise())
restart.place(relx=0.5, rely=0.55, anchor="center")
initialise()
screen.mainloop()
What I would do is simply display the number of tries to the user and then read from that object to see the amount of tries. If you do not want to display it to the user you can always hide it so it does not display. If you do not want to have it on your GUI at all you should then pass this variable around as arguments in your functions.

Creating a Tkinter math Quiz

I am learning python and am having trouble getting this program to work correctly.
from Tkinter import*
import time
import tkMessageBox
import random
def Questions():
number1 = random.randrange(1,25,1)
number2 = random.randrange(1,50,2)
answer = number1 + number2
prompt = ("Add " + str(number1) + " and " + str(number2))
label1 = Label(root, text=prompt, width=len(prompt), bg='yellow')
label1.pack()
return answer
def start():
global count_flag
Questions()
count_flag = True
count = 0.0
while True:
if count_flag == False:
break
# put the count value into the label
label['text'] = str(count)
# wait for 0.1 seconds
time.sleep(0.1)
# needed with time.sleep()
root.update()
# increase count
count += 0.1
def Submit(answer, entryWidget):
""" Display the Entry text value. """
global count_flag
count_flag = False
print answer
if entryWidget.get().strip() == "":
tkMessageBox.showerror("Tkinter Entry Widget", "Please enter a number.")
if int(answer) != entryWidget.get().strip():
tkMessageBox.showinfo("Answer", "INCORRECT!")
else:
tkMessageBox.showinfo("Answer", "CORRECT!")
# create a Tkinter window
root = Tk()
root.title("Math Quiz")
root["padx"] = 40
root["pady"] = 20
# Create a text frame to hold the text Label and the Entry widget
textFrame = Frame(root)
#Create a Label in textFrame
entryLabel = Label(textFrame)
entryLabel["text"] = "Answer:"
entryLabel.pack(side=LEFT)
# Create an Entry Widget in textFrame
entryWidget = Entry(textFrame)
entryWidget["width"] = 50
entryWidget.pack(side=LEFT)
textFrame.pack()
#directions
directions = ('Click start to begin. You will be asked a series of questions like the one below.')
instructions = Label(root, text=directions, width=len(directions), bg='orange')
instructions.pack()
# this will be a global flag
count_flag = True
answer = Questions()
Sub = lambda: Submit(answer, entryWidget)
# create needed widgets
label = Label(root, text='0.0')
btn_submit = Button(root, text="Submit", command = Sub)
btn_start = Button(root, text="Start", command = start)
btn_submit.pack()
btn_start.pack()
label.pack()
# start the event loop
root.mainloop()
It just says "INCORRECT!" every time I push submit regardless of what I enter into the text box. Any suggestions would be appreciated. Thanks, Scott
Left side is an integer, right side is a string, so it's always False:
int(answer) != entryWidget.get().strip()
You can try:
int(answer) != int(entryWidget.get().strip())

Categories