Python Forum
I dont know where my local variable has gone
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
I dont know where my local variable has gone
#1
I am aiming to create a basic maths game, and I am creating a scoring system, after every question right the score should increment, it does so for a second before turning back to 0, thanks for any help. P.S. the code below uses the pygame module.
#relevent moduals are being imported into the python IDLE
import pygame
import system as sys
import math
import time
import random
from random import randrange
  
#pygame initialisation
pygame.init()
  
# colours being defined for future use
GREEN = (0, 255, 0)
DARK_GREEN = (0, 100, 0)
RED = (255, 0, 0)
GOLD = (255, 215, 0)
PINK = (255, 20, 147)
PURPLE = (128, 0, 128)
LIME = (0, 255, 0)
LIGHT_BLUE = (135, 206, 250)
YELLOW = (255, 255, 0)
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
BLUE = (0, 0, 168)
ORANGE = (255, 165, 0)

# A Array of global variables to be incremented through to create a optical effect
rainbow =[RED, DARK_GREEN, GOLD, PINK, PURPLE, LIME, LIGHT_BLUE, YELLOW, WHITE, BLUE, ORANGE]

standard_font = pygame.font.SysFont('arial', 70)
A = standard_font.render("A", 1, BLACK)
B = standard_font.render("B", 1, BLACK)
C = standard_font.render("C", 1, BLACK)

To_Win = 5


unit = 80

Box_width = (2*unit)
pygame_window_width = ((6*unit)+Box_width)
pygame_window_height = (7*unit)
pygame_window_size = (pygame_window_width, pygame_window_height)
pygame_screen = pygame.display.set_mode(pygame_window_size)

Easy_Bank = ['Q1','Q2','Q3','Q4','Q5']
Medium_Bank = ['Q6()','Q7()','Q8()','Q9()','Q10()']
Hard_Bank = ['Q11()','Q12()','Q13()','Q14()','Q15()']

def Q_display(Q_label, score, Answer, A1, A2, A3, X, E, D):
    cover(score)
    Question_label = standard_font.render(Q_label, 1, BLACK)
    Correct_label = standard_font.render("Correct", 1, DARK_GREEN)
    Incorrect_label = standard_font.render("Incorrect", 1, RED)
    A_label_1 = standard_font.render(str(A1), 1, BLACK)
    A_label_2 = standard_font.render(str(A2), 1, BLACK)
    A_label_3 = standard_font.render(str(A3), 1, BLACK)
    pygame_screen.blit(Question_label, (E,D))
    pygame_screen.blit(A, (X,250))
    pygame_screen.blit(B, ((X+140),250))
    pygame_screen.blit(C, ((X+265),250))
    pygame_screen.blit(A_label_1, (X, 320))
    pygame_screen.blit(A_label_2, (X+140, 320))
    pygame_screen.blit(A_label_3, (X+265, 320))
    update()
    select = False
    while select == False:
        for event in pygame.event.get():
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_a:
                    Response = A1
                    select = True
                if event.key == pygame.K_b:
                    Response = A2
                    select = True
                if event.key == pygame.K_c:
                    Response = A3
                    select = True
    if Response == Answer:
        cover(score)
        pygame_screen.blit(Correct_label, (100, 200))
        score = score + 1
        score_track(score)
    else:
        score = 0
        cover(score)
        pygame_screen.blit(Incorrect_label, (80,200))
    if score == To_Win:
        pass
    update()
    pygame.time.wait(1000)
    return score
    

    return score
def Q1(score):
    cover(score)
    Q_Label = ("6 + 8 =")
    Answer = 14
    A1 = 15
    A2 = Answer
    A3 = 13
    X = 70
    E = 150
    D = 100
    Q_display(Q_Label, score, Answer, A1, A2, A3, X, E, D)
    return score

def Q2(score):
    cover(score)
    Q_Label = ("4 x 7 =")
    Answer = 28
    A1 = 32
    A2 = 25
    A3 = Answer
    X = 70
    E = 150
    D = 100
    Q_display(Q_Label, score, Answer, A1, A2, A3, X, E, D)
    return score
    
def Q3(score):
    cover(score)
    Q_Label = ("100 ÷ 25 =")
    Answer = 4
    A1 = 5
    A2 = Answer
    A3 = 2.5
    X = 80
    E = 80
    D = 100
    Q_display(Q_Label, score, Answer, A1, A2, A3, X, E, D)
    return score

def Q4(score):
    cover(score)
    Q_Label = ("(10x33) - 60 =")
    Answer = 270
    A1 = Answer
    A2 = 250
    A3 = 280
    X = 70
    E = 35
    D = 100
    Q_display(Q_Label, score, Answer, A1, A2, A3, X, E, D)
    return score

def Q5(score):
    cover(score)
    Q_Label = ("39 ÷ 3 =")
    Answer = 13
    A1 = Answer
    A2 = 11
    A3 = 16
    X = 70 
    E = 150
    D = 100
    Q_display(Q_Label, score, Answer, A1, A2, A3, X, E, D)
    return score

def Box_Draw(score):
    pygame.draw.rect(pygame_screen, PURPLE, [490, 0, 150, pygame_window_height])
    update()
    return score

def score_track(score):
    score_font = pygame.font.SysFont('arial', 30)
    score_label = score_font.render(("Score: "+str(score)), 1, LIGHT_BLUE)
    pygame.draw.rect(pygame_screen, PURPLE, [510, 163, 120, 30])
    pygame_screen.blit(score_label, ((510),160))
    update()
    return score

def cover(score):
    pygame.draw.rect(pygame_screen, LIGHT_BLUE, (0, 0, pygame_window_width, pygame_window_height))
    Box_Draw(score)
    score_track(score)
    return score
  
def update():
    # Updates screen
    pygame.display.update()

def start():
    score = 0
    game_over = False
    main_code(score, game_over)

def Questions(level, score):
    if level == 'Easy':
        Questions = Easy_Bank
    elif level == 'Medium':
        Questions = Medium_Bank
    elif level == 'Hard':
        Questions = Hard_Bank
    for i in range (1,5):
        Q = random.choice(Questions)
        Question_Load(Q, score)
        Questions.remove(Q)
    return True

def Question_Load(Q, score):
    if Q == 'Q1':
        Q1(score)
    if Q == 'Q2':
        Q2(score)
    if Q == 'Q3':
        Q3(score)
    if Q == 'Q4':
        Q4(score)
    if Q == 'Q5':
        Q5(score)
    return score
    
def main_code(score, game_over):
    level = 'Easy'
    while game_over == False:
        game_over = Questions(level, score)

# Calls the function which start the program
start()
Reply
#2
1. Your main loop is over refactor.
import pygame

def main():
    # Basic pygame setup
    pygame.display.caption("Example")
    surface = pygame.display.set_mode((400, 400))
    clock = pygame.time.Clock()
    rect = surface.get_rect()
    delta = 0
    fps = 60

    # Variables
    background = pygame.Color("black")

    # Main loop
    running = True
    while running:
        # Event loop
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False

        # Draw
        surface.fill(background)

        # Render main surface to screen
        pygame.display.update()

        # Idle/Sleep
        delta = clock.tick(fps)

main()
2. pygame has over 100 builtin colors name.
import pygame

rainbow = [
    pygame.Color('red'),
    pygame.Color('darkgreen'),
    pygame.Color('gold'),
    pygame.Color('pink'),
    pygame.Color('purple'),
    pygame.Color('limegreen'),
    pygame.Color('lightblue'),
    pygame.Color('yellow'),
    pygame.Color('white'),
    pygame.Color('blue'),
    pygame.Color('orange')
]

for color in rainbow:
    print(color)
3. Your code need more containers. list, tuples, dicts, or classes.

4. Try to create one function for creating question. You can use eval to get answer from text.

So try rewrite program.
99 percent of computer problems exists between chair and keyboard.
Reply
#3
Python does not pass variables by reference. When "Question_Load" passes "score" to Q1, Q1 is using a copy of "score". This local copy gets passed along to "Q_display" which get's its own local copy. When "Q_display" changes the value of score it only affects the local copy of score inside "Q_display".

It looks like you understand variable scope somewhat. By returning "score", "Q_display" is passing back the modified score, but "Q1" ignores the return value, and returns it's own local copy which is not modified. Back in "Question_Load" the return value is ignored again, and it's local copy of score is also unaltered.

The short answer to your question is that the score get's lost because you ignore changes to it. You could easily make your program work by paying attention to when the modified score is returned and passing the modified score back up the chain of function calls.

Hopefully you are beginning to see that writing a function for each question is a bad idea. Your program already has some abstraction in the Easy_Bank, Medium Bank, and Hard_Bank list of questions. But these should not be lists of functions. You should have one function that knows how to ask a question (just like you currently have one function that knows how to display the question and get the response). The questions should be data. Here is how I would write a console based version of your program. I have 1 function that knows how to ask a question, and the questions are represented as a named tuple. A regular tuple, list or even dictionary would work just as well. A round or quiz is a list of these structures:
from collections import namedtuple

Question = namedtuple('Question', 'prompt choices answer difficulty')

geography = [
    Question(prompt = 'What is the longest river in the northern hemisphere?',
             choices = ('A: Amazon', 'B: Misissippi', 'C: Yangtze', 'D: Volga'),
             answer = 'C', difficulty = 2),

    Question(prompt = 'What is the highest mountain in South America?',
             choices = ('A: Kangchenjunga', 'B: Aconcagua', 'C: Olympus Mons', 'D: K2'),
             answer = 'B', difficulty = 3)
]

def ask_question(question):
    score = 0
    print(question.prompt)
    for choice in question.choices:
        print('   ', choice)
    response = input('Your Response: ').upper()
    if response == question.answer:
        print('That is correct!')
        score = question.difficulty
    else:
        print('That is incorrect.  The correct answer is', question.answer)
    return score
 
def take_quiz(quiz):
    score = 0
    for question in quiz:
        score += ask_question(question)
        print('Score =', score, '\n\n')
    
take_quiz(geography)
Actually, this is not how I would write the program. To make the program more flexible and useful I would write the program to only know how to ask questions and keep score. The actual questions would be data imported into the program. It could be a database, or a spreadsheet, or just a file. Instead of defining the quiz inside the program I would write a function that knows how to import the data and turn it into a Question.
Reply
#4
Thank You, I will find some pygame material for importing questions from a spreadsheet, is there any online materials that would be good for this except the official pygame documents? thanks for the help.
Reply
#5
(Apr-03-2020, 02:00 PM)Help_me_Please Wrote: Thank You, I will find some pygame material for importing questions from a spreadsheet, is there any online materials that would be good for this except the official pygame documents? thanks for the help.

I'm sure there is lots. Just google or youtube "python import" and what ever the file format your are using is.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  local variable 'spider_1_health' referenced before assignment Tbot1000 1 1,721 Sep-01-2020, 09:07 PM
Last Post: metulburr

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020